<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Nextside Blog</title><link>https://blog.nextside.tech/en/</link><description>Posts by Nextside — technology, management, fast shipping. No hype.</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 26 Jun 2026 11:37:21 -0300</lastBuildDate><atom:link href="https://blog.nextside.tech/en/index.xml" rel="self" type="application/rss+xml"/><item><title>Pricing a client's tool: margin isn't the cheap dev</title><link>https://blog.nextside.tech/en/posts/2026/06/22/quanto-cobrar-por-uma-ferramenta/</link><pubDate>Mon, 22 Jun 2026 09:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/22/quanto-cobrar-por-uma-ferramenta/</guid><dc:creator>Pablo Winter</dc:creator><category>agencies</category><category>pricing</category><category>white-label</category><category>web-tools</category><category>margin</category><description>Your margin on reselling a tool doesn't come from the cheapest dev. It comes from a predictable delivery that doesn't come back broken on you.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every week I see the same scene. The agency closed the strategy, the client trusted them, and then comes the ask: a real tool on the site. A pricing calculator, a configurator, an assistant that answers on its own. The agency says yes, sends a price, and six weeks later is paying out of its own pocket to finish. The mistake wasn&rsquo;t charging too much. It was charging in the dark.</p>
<p>Let me be blunt: the margin on a tool you resell doesn&rsquo;t come from finding the cheapest dev. It comes from reselling a predictable delivery that doesn&rsquo;t come back. The cheap one charges the difference later, in rework and in your client&rsquo;s trust.</p>
<p>The numbers back it up. 78% of agencies rarely or never charge when scope grows mid-project (<a href="https://www.ignitionapp.com/blog/preventing-agency-scope-creep"target="_blank" rel="noopener">Ignition, 2025</a>). The money leaks out before the supplier even vanishes. And when he does vanish, you&rsquo;re the one left explaining it to the client.</p>
<h2>The discount you squeeze today comes back as rework tomorrow<span class="hx:absolute hx:-mt-20" id="the-discount-you-squeeze-today-comes-back-as-rework-tomorrow"></span>
    <a href="#the-discount-you-squeeze-today-comes-back-as-rework-tomorrow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The reflex is always the same: to protect margin, the agency hunts for the cheapest dev. It makes sense on the spreadsheet and breaks on delivery. Because the dev&rsquo;s price is only one part of the bill. The rest, the part that isn&rsquo;t in the proposal, is what decides whether any margin survived.</p>
<p>(If your team froze before you even got to the price, I wrote about <a href="/en/posts/2026/06/17/cliente-pediu-ferramenta-time-nao-da-conta/">that exact moment here</a>.)</p>
<p>Think about what cheap doesn&rsquo;t include. The rework when the first version comes back crooked. The extra three weeks that push your delivery and make the client call asking. The tool that goes down on a big-campaign Monday, and the brand taking the heat is YOURS, not the freelancer&rsquo;s. The freelancer charged half. You paid double, just in installments of pain.</p>
<p>Cheap isn&rsquo;t a price. It&rsquo;s an expiration date.</p>
<blockquote>
  <p>&ldquo;But if I pay more for the dev, my margin disappears.&rdquo;</p>

</blockquote>
<p>No. Your margin disappears when the work comes back. If you pay 30% more for someone who ships on time, with fixed scope, and who doesn&rsquo;t leave you stranded in front of the client, you didn&rsquo;t spend more. You bought predictability. And predictability is the only thing you can resell with peace of mind.</p>
<p>The real expense is never the dev&rsquo;s hourly rate. It&rsquo;s the opportunity cost of the delayed project, the cost of redoing what came out wrong, and the cost of a client who stopped trusting you. None of those three show up on any quote. But they all come out of your pocket.</p>
<h2>The bill nobody opens: what makes a tool&rsquo;s price<span class="hx:absolute hx:-mt-20" id="the-bill-nobody-opens-what-makes-a-tools-price"></span>
    <a href="#the-bill-nobody-opens-what-makes-a-tools-price" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the structural mistake I see all the time: the agency prices a tool with a website ruler. Per page, per design hour, per screen. But a tool isn&rsquo;t a website with a button. What costs money in a tool is what happens after the user clicks.</p>
<p>A website shows. A tool does. And &ldquo;doing&rdquo; is where the cost lives:</p>
<ul>
<li><strong>The business logic.</strong> The rule that calculates, decides, validates. It&rsquo;s invisible to the client and it&rsquo;s the bulk of the work.</li>
<li><strong>The integration.</strong> A tool that talks to the client&rsquo;s inventory, CRM or payments costs far more than one that lives alone.</li>
<li><strong>What holds it up afterward.</strong> Login, user data, security. The day the tool stores people&rsquo;s information, the game moves up a tier.</li>
<li><strong>The scale.</strong> Handling ten people is easy. Keeping the tool up when the campaign goes viral is another story.</li>
</ul>
<p>To give you orders of magnitude, without faking a precision that doesn&rsquo;t exist. These are market ranges and they vary a lot by scope:</p>
<table>
  <thead>
      <tr>
          <th>Type of tool</th>
          <th>What weighs most on price</th>
          <th>Order of magnitude (market)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Lead calculator or quiz</td>
          <td>simple logic, almost no integration</td>
          <td>the lowest: low thousands</td>
      </tr>
      <tr>
          <td>Product configurator</td>
          <td>business rules + catalog + visual</td>
          <td>mid</td>
      </tr>
      <tr>
          <td>On-site assistant or automation</td>
          <td>integration with the client&rsquo;s systems</td>
          <td>mid-high</td>
      </tr>
      <tr>
          <td>Tool with login and user data</td>
          <td>account, security, scale</td>
          <td>the highest</td>
      </tr>
  </tbody>
</table>
<p>The point isn&rsquo;t to memorize the table. It&rsquo;s to understand that two things both called &ldquo;a tool&rdquo; can differ tenfold in cost. Whoever prices them the same loses money on one and loses the client on the other.</p>
<h3>How do you price a tool without knowing what the dev will cost?<span class="hx:absolute hx:-mt-20" id="how-do-you-price-a-tool-without-knowing-what-the-dev-will-cost"></span>
    <a href="#how-do-you-price-a-tool-without-knowing-what-the-dev-will-cost" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>You don&rsquo;t guess. You ask for a fixed range before you close with the client. A good technical partner hands you the scope and a fixed price before starting, not an estimate that doubles halfway through. With the range in hand, you mark it up with your margin and close knowing exactly what&rsquo;s left.</p>
<p>It&rsquo;s the difference between an open budget and fixed scope. An open budget is an invitation to surprise: it starts at X, becomes 2X, and you&rsquo;re the one who absorbs it. Fixed scope is the opposite. You know the bill before you sign, your client knows <a href="/en/posts/2026/06/16/mvp-o-que-cortar-e-o-que-manter/">what&rsquo;s in and what&rsquo;s out</a> before paying. Both sides sleep well.</p>
<aside class="ns-cta ns-cta-mid" data-servico="discovery">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Want to hand your client a fixed range before you commit, with no budget blowing up mid-project? That&#39;s what we do in a Discovery.</h3>

  <p class="ns-cta-meta">Technical validation · 2-3 weeks · Outcome: roadmap &#43; prototype.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=discovery&amp;utm_content=quanto-cobrar-por-uma-ferramenta-mid#discovery" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>The real margin: you resell predictability, not dev hours<span class="hx:absolute hx:-mt-20" id="the-real-margin-you-resell-predictability-not-dev-hours"></span>
    <a href="#the-real-margin-you-resell-predictability-not-dev-hours" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the turn. You&rsquo;re not reselling development. You&rsquo;re reselling the outcome, with your brand up front, without your client ever knowing who wrote the code. This is the <dfn>white-label</dfn> model, where the supplier delivers under your brand and stays invisible. And their margin isn&rsquo;t born from the discount. It&rsquo;s born from predictability.</p>
<p>The resale markup in white-label usually lands between 40% and 70% over the cost of delivery (<a href="https://www.cloudcampaign.com/blog/how-to-price-white-label-software"target="_blank" rel="noopener">CloudCampaign</a>). Sounds like a lot until you notice the condition almost nobody says out loud: that markup only survives if the delivery doesn&rsquo;t come back. Every project that returns with a bug, every blown deadline, every supplier who vanishes eats that whole margin. The markup isn&rsquo;t guaranteed profit. It&rsquo;s profit conditioned on a delivery that works.</p>
<p>Run the numbers on a case I see repeat. The agency closes a configurator for the client at $20,000.</p>
<ul>
<li><strong>Path A.</strong> Finds a freelancer for $5,000 and celebrates the fat margin. The freelancer slips, the first version doesn&rsquo;t match the catalog, rework kicks in, and the launch that was meant for April moves to June. The $15,000 margin turned into a reputation loss.</li>
<li><strong>Path B.</strong> Closes with a predictable partner for $10,000, locked scope, on-time delivery. The margin on paper is smaller, $10,000, but it&rsquo;s the margin that actually LANDS. And the client, happy, comes back with the next project.</li>
</ul>
<p>A happy agency brings N projects. A burned client brings none.</p>
<p>A discount is margin you&rsquo;ll pay back later. Predictability is margin that stays.</p>
<h3>What margin can an agency charge reselling development?<span class="hx:absolute hx:-mt-20" id="what-margin-can-an-agency-charge-reselling-development"></span>
    <a href="#what-margin-can-an-agency-charge-reselling-development" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The range practiced in white-label runs from 40% to 70% markup over the cost of delivery. But the number that matters isn&rsquo;t the ceiling, it&rsquo;s what&rsquo;s left after rework. High markup on a delivery that comes back is zero. Honest markup on a predictable delivery is what builds the agency over time.</p>
<h2>Predictability is the product. The rest is luck.<span class="hx:absolute hx:-mt-20" id="predictability-is-the-product-the-rest-is-luck"></span>
    <a href="#predictability-is-the-product-the-rest-is-luck" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In the end, your client isn&rsquo;t buying a tool from you. They&rsquo;re buying the peace of mind that it&rsquo;ll work when they need it most. That&rsquo;s what you resell. The tool is the object. The predictability is the product.</p>
<p>When you hunt for the cheapest dev, you&rsquo;re not saving. You&rsquo;re betting that this time it&rsquo;ll work out. Sometimes it does. But you didn&rsquo;t build an agency to live on a bet.</p>
<p>Cheap always charges the difference. The only question is when, and in front of whom.</p>
]]></content:encoded></item><item><title>I inherited a vibe-coded MVP to scale: the honest diagnosis</title><link>https://blog.nextside.tech/en/posts/2026/06/19/recebi-mvp-vibe-coded-pra-escalar/</link><pubDate>Fri, 19 Jun 2026 10:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/19/recebi-mvp-vibe-coded-pra-escalar/</guid><dc:creator>Pablo Winter</dc:creator><category>vibe-coding</category><category>divida-tecnica</category><category>refatoracao</category><category>mvp</category><category>arquitetura</category><category>testes</category><description>Inherited a stuck vibe-coded MVP to scale? Rewriting from scratch is the costliest mistake. The honest diagnosis: what to save, what to rewrite, how to stabilize.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Over the past few months the profile of who reaches out to me has changed. It used to be &ldquo;I have an idea, build it for me.&rdquo; Now it&rsquo;s &ldquo;I already have the app, it sort of works, but it stalls the moment it has to grow, and I don&rsquo;t know whether to fix it or throw it out.&rdquo; The product was <dfn>vibe coding: generating software by asking an AI and accepting the result without reading or understanding the code that came out</dfn>. It works enough to have paying customers. And enough to be scary.</p>
<p>The first decision in front of one of these isn&rsquo;t technical. It&rsquo;s triage. And the most expensive temptation, the one almost everyone has on day one, is to order a full rewrite from scratch. It&rsquo;s almost always a mistake. In most cases it&rsquo;s not a transplant: it&rsquo;s a test suite first, then a scalpel on what actually rotted. You save far more than the panic suggests.</p>
<p>The numbers explain the scare and why it misleads. 45% of AI-generated code carries <a href="https://www.veracode.com/blog/genai-code-security-report/"target="_blank" rel="noopener">an OWASP Top 10 flaw</a> (Veracode), and only <a href="https://arxiv.org/html/2508.14727v1"target="_blank" rel="noopener">10.5% of vibe-coded code passes a decent security review</a> against 61% that simply &ldquo;works&rdquo; (Carnegie Mellon). It looks like a demolition order. It isn&rsquo;t. It&rsquo;s the measure of the distance between working and holding up, and distance you measure BEFORE you demolish, not after.</p>
<p>Working isn&rsquo;t the same as done. But it isn&rsquo;t the same as junk either.</p>
<h2>Rewriting from scratch is the most expensive mistake there is<span class="hx:absolute hx:-mt-20" id="rewriting-from-scratch-is-the-most-expensive-mistake-there-is"></span>
    <a href="#rewriting-from-scratch-is-the-most-expensive-mistake-there-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Everyone who calls me with a stuck app shows up with the same line on the tip of their tongue:</p>
<blockquote>
  <p>&ldquo;This code is a mess. It&rsquo;s faster to redo it from scratch than to understand this dumpster fire.&rdquo;</p>

</blockquote>
<p>Hold on. That line is the most expensive siren song in software engineering, and I&rsquo;m not the one who discovered it. Joel Spolsky called rewriting from scratch <a href="https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/"target="_blank" rel="noopener">&ldquo;the single worst strategic mistake that any software company can make&rdquo;</a>, and that was in 2000, long before AI made the rewrite even more tempting and even more expensive.</p>
<p>Why a mistake? Because you&rsquo;re about to throw out the one thing this MVP actually proved: that people want it. The code is ugly, but it carries months of learning baked in. Every weird hack is, half the time, a real edge case some customer hit, one that the &ldquo;clean&rdquo; rewrite will rediscover the hard way, in production, all over again.</p>
<p>Think about Twitter. It was born as a Rails monolith because that&rsquo;s what two guys could move fast enough to find product-market fit. The scaling problems came later. Because it worked. If they had started &ldquo;the right way,&rdquo; beefy and distributed, there probably wouldn&rsquo;t be a Twitter to have scaling problems. The speed of vibe coding is real and it&rsquo;s valuable for validating. The mistake isn&rsquo;t having validated that way. It&rsquo;s not shifting gears once the validation is over.</p>
<p>A rewrite from scratch is the vanity of whoever just showed up on the project.</p>
<h2>Before you touch a single line, the test suite<span class="hx:absolute hx:-mt-20" id="before-you-touch-a-single-line-the-test-suite"></span>
    <a href="#before-you-touch-a-single-line-the-test-suite" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the step almost everyone skips, and it&rsquo;s the one that separates a rescue from a second disaster: you don&rsquo;t fix what you can&rsquo;t test, nor safely refactor what you didn&rsquo;t cover first. Tests aren&rsquo;t the last step of the rescue. They&rsquo;re the first.</p>
<p>And it&rsquo;s exactly what vibe-coded code doesn&rsquo;t have. The AI generates with a brutal happy-path bias: it covers the flow you described and ignores the rest of the universe. Network error, invalid input, two clicks on the same button, the user who does it in the wrong order. None of that exists in the code, so none of it breaks visibly. Until it breaks in front of the customer.</p>
<blockquote>
  <p>&ldquo;Write tests before shipping a new feature? I&rsquo;ll spend two weeks with nothing to show the board.&rdquo;</p>

</blockquote>
<p>I get the anxiety, and it&rsquo;s backwards. The test suite isn&rsquo;t time lost before delivering value. It&rsquo;s what gives you permission to touch the code without praying. Without it, every refactor is a blind bet: you fix one bug and find out, three days later, that you broke two others nobody could see. With it, you refactor with your eyes open. It&rsquo;s the difference between operating with the lights on and operating in the dark.</p>
<p>In practice, I don&rsquo;t even ask for full coverage up front. I ask for tests on the flows that make money and the ones that lose money: the checkout, the login, anything that touches a balance. It&rsquo;s the minimum safety net so everything that comes next is surgery, not roulette. That same discipline of validating before trusting we already broke down in <a href="/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/">local validation with real quality</a>, only there applied to the flow of whoever is building, not rescuing.</p>
<h2>The diagnosis: reading the debt statement<span class="hx:absolute hx:-mt-20" id="the-diagnosis-reading-the-debt-statement"></span>
    <a href="#the-diagnosis-reading-the-debt-statement" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With a safety net in place, you can open the hood without fear. The diagnosis of a vibe-coded MVP almost always finds the same four holes. I call it reading the debt statement, because that&rsquo;s literally what it is: finding out how much you owe and to whom.</p>
<ul>
<li><strong>Coupled architecture.</strong> The business logic is glued to the infrastructure, the API was designed without thinking about load, the schema can&rsquo;t grow sideways. It works with fifty users because everything works with fifty users. The paper that formalized this calls it <a href="https://arxiv.org/abs/2512.11922"target="_blank" rel="noopener">flow-debt trade-off</a>: the fluidity of generating code masks the debt piling up in parallel.</li>
<li><strong>Missing observability.</strong> Logging, tracing, and metrics came in as an afterthought, or didn&rsquo;t come in at all. When it falls over at 3 a.m., you have nowhere to look. The OneUptime line stays on the wall: <a href="https://oneuptime.com/blog/post/2026-02-15-vibe-coding-and-the-observability-gap/view"target="_blank" rel="noopener">&ldquo;observability isn&rsquo;t a nice to have, it&rsquo;s your only safety net&rdquo;</a>. In vibe-coded code it&rsquo;s the stand-in for the human review that never happened.</li>
<li><strong>Decorative security.</strong> API key hardcoded in the repo, auth with the logic inverted, a database exposed with no access rule. It&rsquo;s not the exception: Apiiro measured AI-generated code adding up <a href="https://apiiro.com/blog/4x-velocity-10x-vulnerabilities-ai-coding-assistants-are-shipping-more-risks/"target="_blank" rel="noopener">10x more security findings in six months</a>, with privilege-escalation paths up 322%.</li>
<li><strong>Fragile deploy and CI.</strong> The classic case is preview, test, and production sharing the same database. That&rsquo;s how Replit&rsquo;s AI <a href="https://www.theregister.com/2025/07/21/replit_saastr_vibe_coding_incident/"target="_blank" rel="noopener">wiped the production database</a> during an explicit code freeze, in ALL CAPS in the prompt, and then lied saying the rollback was impossible. Separating environments is the cheapest and most ignored lesson on the list.</li>
</ul>
<p>The statement is scary on purpose. But a statement isn&rsquo;t an eviction notice. It tells you where the expensive debt is and where the debt you can roll over is, and that distinction is the whole rescue.</p>
<h3>How do I know whether the architecture can be saved or not?<span class="hx:absolute hx:-mt-20" id="how-do-i-know-whether-the-architecture-can-be-saved-or-not"></span>
    <a href="#how-do-i-know-whether-the-architecture-can-be-saved-or-not" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>There&rsquo;s just one practical criterion: how coupled the business logic is to the infrastructure, plus whether the data model can grow. If the logic that matters is buried in the middle of the controller, dependent on a database detail that won&rsquo;t scale sideways, that piece is a localized rewrite: there&rsquo;s no saving the foundation without redoing it. If the business logic is at least isolated, even if ugly, it&rsquo;s remediation: you improve it from the inside without demolishing. Most of an MVP falls in the second case. That&rsquo;s why a full rewrite is almost never the right answer: you condemn the whole building over two rooms.</p>
<h2>What to save and what to rewrite without mercy<span class="hx:absolute hx:-mt-20" id="what-to-save-and-what-to-rewrite-without-mercy"></span>
    <a href="#what-to-save-and-what-to-rewrite-without-mercy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Triage is deciding what goes into the operating room and what gets discharged. After doing this on plenty of apps, the pattern is pretty stable.</p>
<p><strong>Save almost always:</strong> the domain model that reflects the actual business (the names of things and how they connect), the flows the user already validated in practice, and a good chunk of the interface. That&rsquo;s the knowledge that cost months and that a rewrite throws in the trash for free. The version of this discipline at the code-structure level we opened up in <a href="/en/posts/2026/06/15/codebase-novo-prompt-mvp-que-escala/">your codebase is the new prompt</a>: what decides whether it scales isn&rsquo;t the stack, it&rsquo;s the repository staying navigable.</p>
<p><strong>Rewrite without mercy:</strong> the auth and permissions layer (it&rsquo;s where getting it wrong hurts most, because it touches every request), the business logic the AI duplicated across eight, ten, twelve places, the schema that can&rsquo;t take traction, and the integrations with no fallback at all. The duplication isn&rsquo;t a detail: in 2024, for the first time in history, <a href="https://www.gitclear.com/ai_assistant_code_quality_2025_research"target="_blank" rel="noopener">copy-pasted code overtook refactored code</a>, with duplicate blocks growing 8x (GitClear). Each copy is one more place for a bug to hide and never get fixed everywhere.</p>
<p>What guides the cut is understanding why the app stalls where it stalls. Addy Osmani dubbed it the <a href="https://addyo.substack.com/p/the-70-problem-hard-truths-about"target="_blank" rel="noopener">70% problem</a>: AI gets you fast to 70%, except it&rsquo;s 70% of the <em>volume</em> of code, not 70% of the <em>path</em> to a finished product. The missing 30% is exactly what you can&rsquo;t generate in a rush: edge cases, maintainability, performance, security. It&rsquo;s the expensive part. It&rsquo;s the part triage isolates.</p>
<h3>Is vibe coding fit for production?<span class="hx:absolute hx:-mt-20" id="is-vibe-coding-fit-for-production"></span>
    <a href="#is-vibe-coding-fit-for-production" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It&rsquo;s fit to get you to the door, not through it. Vibe coding is a spectacular validation accelerator: it proves the hypothesis, wins the first customers, shows there&rsquo;s a business. The mistake isn&rsquo;t using it. It&rsquo;s mistaking the prototype that validated for the product that scales, and going on stacking features on top of a foundation that was never built to carry weight. The very mechanics of this, of why &ldquo;prompt, accept, deploy&rdquo; stalls when it&rsquo;s time to grow, we discussed in <a href="/en/posts/2026/06/13/spec-driven-development-sair-do-vibe-coding/">getting out of vibe coding</a>. Vibe coding gets you to the MVP. Method gets the MVP to a product.</p>
<aside class="ns-cta ns-cta-mid" data-servico="auditoria">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Inherited a stuck vibe-coded MVP? An Audit gives you the diagnosis with no strings attached: what to save, what to rewrite, in what order, before you commit to a Sprint.</h3>

  <p class="ns-cta-meta">Independent audit · 1-2 weeks · No commercial strings attached.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=auditoria&amp;utm_content=recebi-mvp-vibe-coded-pra-escalar-mid#auditoria" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>Stabilizing without stopping the business: surgery with the patient awake<span class="hx:absolute hx:-mt-20" id="stabilizing-without-stopping-the-business-surgery-with-the-patient-awake"></span>
    <a href="#stabilizing-without-stopping-the-business-surgery-with-the-patient-awake" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The last piece, and the one that most sets a competent rescue apart, is the &ldquo;without stopping the business&rdquo; part. Because the app is live, it has customers using it, it has revenue coming in. You can&rsquo;t shut everything down for two months to tidy the house. You have to operate with the patient awake.</p>
<p>The way to do it has a name: <dfn>Strangler pattern: replacing the old system from the outside, module by module, while it keeps running, until the new one strangles the old</dfn>. Instead of the big bang (&ldquo;flip the switch to the new one on a Sunday and pray&rdquo;), you pick a piece (auth, say), build the new version alongside, send a fraction of the traffic to it with a feature flag, confirm it holds, and only then retire the old one. Got it wrong? Rollback in one click, nobody notices. Repeat for the next module. The risk gets sliced into pieces that fit in your pocket, instead of a single bet that can take the company down.</p>
<p>And the first slice, almost always, is the cheapest and the most forgotten: separating the environments. The production database is sacred, it has a tested automatic backup, and nobody, human or AI, touches it without a net. It&rsquo;s the fix that would have prevented the entire Replit disaster, and it costs a day.</p>
<p>There&rsquo;s a trade-off, and I don&rsquo;t sell miracles. On paper, the Strangler is slower than rewriting from scratch: you keep two systems alive at the same time for a while, you pay the cost of keeping the two talking. It&rsquo;s annoying. But it&rsquo;s the price of not stopping the revenue while you operate, and it&rsquo;s incomparably cheaper than the rewrite that freezes the product for a quarter and still ships late. It&rsquo;s the kind of independent diagnosis, with no strings attached, that we deliver in an Audit before a single line gets touched: the map of what to save, what to rewrite, and in what order to move. What to cut and what to keep when you decide the scope of that rebuild we opened up in <a href="/en/posts/2026/06/16/mvp-o-que-cortar-e-o-que-manter/">what to cut and what to keep in an MVP</a>.</p>
<h2>Working isn&rsquo;t done. But it isn&rsquo;t junk either.<span class="hx:absolute hx:-mt-20" id="working-isnt-done-but-it-isnt-junk-either"></span>
    <a href="#working-isnt-done-but-it-isnt-junk-either" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The instinct in front of a stuck vibe-coded MVP is binary: either it&rsquo;s wonderful because it&rsquo;s live, or it&rsquo;s junk because the code is ugly. Both are wrong. It&rsquo;s exactly what it looks like: a prototype that validated a business and now needs to become a product, with a debt you can read, line item by line item, and pay off in the right order.</p>
<p>The distance between the demo that wowed and the system that takes traction is measurable. It&rsquo;s not faith, it&rsquo;s diagnosis: tests to turn the lights on, the statement to know what you owe, triage to separate what you save from what you rewrite, and the Strangler to operate without switching the patient off. Almost always you can do it without demolishing the house.</p>
<p>Done is a state you prove, not one you feel.</p>
]]></content:encoded></item><item><title>A client wants a custom tool and your agency can't build it</title><link>https://blog.nextside.tech/en/posts/2026/06/17/cliente-pediu-ferramenta-time-nao-da-conta/</link><pubDate>Wed, 17 Jun 2026 09:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/17/cliente-pediu-ferramenta-time-nao-da-conta/</guid><dc:creator>Lucas Israel</dc:creator><category>agencies</category><category>web-tools</category><category>outsourcing</category><category>white-label</category><category>fixed-scope</category><description>The request landed, it's new revenue, and your team froze. Why a dev shop is expensive, an in-house hire is worse, and what the third way is.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A request for a real tool on your client&rsquo;s site is the best revenue an agency can land: high margin, recurring, harder to get swapped out of. But it runs into a real problem: you don&rsquo;t have a dev, a dev shop bills high and disappears, and building an in-house team is the most expensive, riskiest way to find out it wasn&rsquo;t going to work. The way out is to deliver with a technical partner under your own brand, without becoming a software company. <strong>The risk isn&rsquo;t in taking the project. It&rsquo;s in taking it the wrong way.</strong></p>
<h2>Why this is an opportunity, not a problem<span class="hx:absolute hx:-mt-20" id="why-this-is-an-opportunity-not-a-problem"></span>
    <a href="#why-this-is-an-opportunity-not-a-problem" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When a client asks for a tool (not a site, a tool that <em>does</em> something), they&rsquo;re telling you they trust you to solve a business problem, not just an image one. That&rsquo;s the kind of work that pays more, lasts longer, and pulls you out of the landing-page price war. It&rsquo;s exactly where an agency stops being a design vendor and becomes an operations partner.</p>
<p>The problem is the opportunity comes wrapped in a legitimate fear: &ldquo;what if I say yes and can&rsquo;t deliver?&rdquo;. That fear is healthy. It just can&rsquo;t become the reason you hand money back to the competition.</p>
<h2>The three obvious ways out (and where each one breaks)<span class="hx:absolute hx:-mt-20" id="the-three-obvious-ways-out-and-where-each-one-breaks"></span>
    <a href="#the-three-obvious-ways-out-and-where-each-one-breaks" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Turning it down, hiring a dev shop, or building an in-house team are the natural reactions. They all carry a hidden cost: the first makes you lose the account, the second makes you lose margin and control, the third makes you lose money for months before you even know if it was worth it. Worth breaking down.</p>
<h3>Turning the request down<span class="hx:absolute hx:-mt-20" id="turning-the-request-down"></span>
    <a href="#turning-the-request-down" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Looks prudent. In practice, you teach the client to go look for whoever &ldquo;does the tech part&rdquo;, and that person, sooner or later, also does the marketing part. You don&rsquo;t just lose the project: you open the door to losing the account.</p>
<h3>Calling a dev shop<span class="hx:absolute hx:-mt-20" id="calling-a-dev-shop"></span>
    <a href="#calling-a-dev-shop" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The quote comes back high, the timeline comes back long, and control leaves your hands. Worse: in front of the client, the brand answering for the tool is yours, but the one setting the pace is a vendor you don&rsquo;t control. When it stalls, you&rsquo;re stuck in the middle, no team to fix it and no vendor in sight.</p>
<h3>Hiring a dev (or a team)<span class="hx:absolute hx:-mt-20" id="hiring-a-dev-or-a-team"></span>
    <a href="#hiring-a-dev-or-a-team" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is the one that feels most &ldquo;definitive&rdquo; and it&rsquo;s the most expensive of all. A senior developer in the US runs <strong>$120k to $160k a year in base salary</strong> (<a href="https://www.glassdoor.com/Salaries/senior-software-engineer-salary-SRCH_KO0,24.htm"target="_blank" rel="noopener">Glassdoor</a>), and that&rsquo;s just salary, no benefits, no time-to-productivity, no risk of them quitting in six months. You&rsquo;re taking on a high, recurring fixed cost for a demand that&rsquo;s still one-off. And then comes the part nobody at the agency says out loud: <strong>you don&rsquo;t know how to hire a dev, you don&rsquo;t know how to tell if they&rsquo;re any good, and you don&rsquo;t know how to keep them afterward.</strong> Judging a professional from a field that isn&rsquo;t yours is a blind bet with your own money.</p>
<aside class="ns-cta ns-cta-mid" data-servico="discovery">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Want to know whether your next project fits a partner or calls for a team? Start with a Discovery: scope and cost on the table before you decide.</h3>

  <p class="ns-cta-meta">Technical validation · 2-3 weeks · Outcome: roadmap &#43; prototype.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=discovery&amp;utm_content=cliente-pediu-ferramenta-time-nao-da-conta-mid#discovery" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>The fourth way: deliver under your brand, without becoming a software company<span class="hx:absolute hx:-mt-20" id="the-fourth-way-deliver-under-your-brand-without-becoming-a-software-company"></span>
    <a href="#the-fourth-way-deliver-under-your-brand-without-becoming-a-software-company" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s a middle ground between turning it down and building a tech department: outsource the delivery to a technical partner who works under your brand, with fixed scope and timeline. You keep the client, the margin and the relationship; the partner ships the working tool, and vanishes from the client&rsquo;s radar. It&rsquo;s the model the market calls <dfn>white-label: the technical partner delivers under your brand and never shows up in front of your client</dfn>, and it exists precisely because an in-house senior dev is too expensive for most agencies (<a href="https://xovakstudio.com/pages/white-label-web-development-for-agencies"target="_blank" rel="noopener">Xovak</a>).</p>
<p>The difference between this and a traditional dev shop isn&rsquo;t just price. It&rsquo;s how the work gets done: scope defined up front, short timeline, delivery in phases with you approving each step. You&rsquo;re not buying &ldquo;development hours&rdquo; with no end. You&rsquo;re buying a result, with a date and a price agreed before anything starts.</p>
<h2>Where this breaks too (because everything has a trade-off)<span class="hx:absolute hx:-mt-20" id="where-this-breaks-too-because-everything-has-a-trade-off"></span>
    <a href="#where-this-breaks-too-because-everything-has-a-trade-off" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The wrong partner is as bad as no partner. The model only works if three things are clear: the scope is fixed (no &ldquo;we&rsquo;ll figure it out later&rdquo;), the code stays with the client (or with you, never hostage to the vendor), and the tool is built well, not a cheap hack that breaks in front of the end client and becomes your headache. A cheap, badly built tool costs more than a dev shop: you pay twice, and the second time in front of your client. If the partner won&rsquo;t lock scope and timeline before starting, that&rsquo;s the sign you&rsquo;re about to become the dev shop, just without the team.</p>
<h2>How to decide, in practice<span class="hx:absolute hx:-mt-20" id="how-to-decide-in-practice"></span>
    <a href="#how-to-decide-in-practice" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If the demand is one-off and you want to test the client&rsquo;s appetite without taking on fixed cost: partner, fixed scope. If the demand has become recurring and predictable enough to pay a salary every month with room to spare: then, maybe, it makes sense to think about a team, but only after you&rsquo;ve delivered a few times with a partner and understood what the work actually takes. Starting with the team is betting before you have the information.</p>
<p>The simple rule: don&rsquo;t build structure for a demand you haven&rsquo;t validated yet. Deliver first, learn the real cost, and only then decide whether it becomes an in-house operation.</p>
<h2>FAQ<span class="hx:absolute hx:-mt-20" id="faq"></span>
    <a href="#faq" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>How much does it cost to deliver a tool like this through a partner?<span class="hx:absolute hx:-mt-20" id="how-much-does-it-cost-to-deliver-a-tool-like-this-through-a-partner"></span>
    <a href="#how-much-does-it-cost-to-deliver-a-tool-like-this-through-a-partner" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It depends on scope, but the whole point of the model is having the price fixed before starting, not open-ended hours. A simple tool (calculator, smart form, configurator) usually comes out at a fraction of what a dev shop charges for a &ldquo;from scratch&rdquo; project, because the scope is lean and the method is standardized.</p>
<h3>Will the client know I outsourced it?<span class="hx:absolute hx:-mt-20" id="will-the-client-know-i-outsourced-it"></span>
    <a href="#will-the-client-know-i-outsourced-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the white-label model, no. The delivery goes out under your brand. The technical partner doesn&rsquo;t show up in front of your client.</p>
<h3>What if the tool breaks down the line?<span class="hx:absolute hx:-mt-20" id="what-if-the-tool-breaks-down-the-line"></span>
    <a href="#what-if-the-tool-breaks-down-the-line" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>That&rsquo;s why &ldquo;built well&rdquo; isn&rsquo;t a luxury, it&rsquo;s insurance. A tool with solid structure is stable and easy to adjust. The noise comes from cheap hacks that break in front of the end client: exactly what you want to avoid when it&rsquo;s your brand on the line.</p>
<h3>Wouldn&rsquo;t it be safer to just hire a dev?<span class="hx:absolute hx:-mt-20" id="wouldnt-it-be-safer-to-just-hire-a-dev"></span>
    <a href="#wouldnt-it-be-safer-to-just-hire-a-dev" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Only if the demand is already recurring enough to pay the salary with room to spare. For a one-off or still-uncertain demand, hiring means taking on the highest cost and the biggest risk (evaluating and keeping someone from a field that isn&rsquo;t yours) before you know it&rsquo;s worth it.</p>
<h3>How long does it take?<span class="hx:absolute hx:-mt-20" id="how-long-does-it-take"></span>
    <a href="#how-long-does-it-take" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Fixed-scope tools usually ship in weeks, not months, because the scope is defined up front and the work is done in phases, with you approving each step.</p>
<h2>Read also<span class="hx:absolute hx:-mt-20" id="read-also"></span>
    <a href="#read-also" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><a href="/en/posts/2026/06/15/codebase-novo-prompt-mvp-que-escala/">Your codebase is the new prompt: the MVP that scales (or turns to junk)</a></li>
<li><a href="/en/posts/2026/06/13/spec-driven-development-sair-do-vibe-coding/">Spec-driven development: getting out of stuck vibe coding</a></li>
</ul>
]]></content:encoded></item><item><title>Your MVP doesn't turn to junk for being fast, but for cutting the wrong thing.</title><link>https://blog.nextside.tech/en/posts/2026/06/16/mvp-o-que-cortar-e-o-que-manter/</link><pubDate>Tue, 16 Jun 2026 10:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/16/mvp-o-que-cortar-e-o-que-manter/</guid><dc:creator>Bruno Raphael</dc:creator><category>mvp-que-escala</category><category>mvp</category><category>escopo-de-produto</category><category>time-to-market</category><category>retrabalho</category><description>The MVP that turns to junk wasn't built too fast. It merged everything to save time and kept the feature nobody uses. What to cut and what to keep.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every technical founder who sits down with me shows up with the same fear: &ldquo;I launch in weeks, but I don&rsquo;t want to rewrite everything three months from now.&rdquo; The fear is legitimate. It just makes you cut the wrong thing.</p>
<p>The MVP that turns to junk almost never turned to junk for being fast. It turned because it cut the separation (which is cheap to keep and expensive to redo) to keep a feature (which is expensive to build and that almost nobody will use). The MVP that scales does the opposite: it cuts features without mercy and keeps the separation always. It isn&rsquo;t born a disposable prototype. It&rsquo;s born as phase 1 of a product, and phase 2 grows on top of it when you cut and kept right.</p>
<p>The numbers anchor the inversion. 42% of startups that die <a href="https://www.cbinsights.com/research/report/startup-failure-reasons-top/"target="_blank" rel="noopener">die building something the market didn&rsquo;t want</a>. In an average product, <a href="https://www.pendo.io/resources/the-2019-feature-adoption-report/"target="_blank" rel="noopener">64% to 80% of features are rarely or never used</a>. And redoing what came out wrong is the quietest cost: teams <a href="https://codeclimate.com/blog/rework-costs-millions"target="_blank" rel="noopener">rework about 26% of their code before they even ship</a>, and most of that comes from misunderstanding what to build, not from coding fast.</p>
<p>Speed isn&rsquo;t the enemy of the MVP that scales. Blind scope is.</p>
<h2>The MVP doesn&rsquo;t turn to junk for being fast. It turns for merging everything and keeping the feature.<span class="hx:absolute hx:-mt-20" id="the-mvp-doesnt-turn-to-junk-for-being-fast-it-turns-for-merging-everything-and-keeping-the-feature"></span>
    <a href="#the-mvp-doesnt-turn-to-junk-for-being-fast-it-turns-for-merging-everything-and-keeping-the-feature" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The image of an MVP the founder carries around is almost always the wrong one: a small version of the whole product. A bit of each thing. Every screen, every feature, just half-baked.</p>
<blockquote>
  <p>&ldquo;An MVP is for validating fast. Do the minimum of everything, polish it later.&rdquo;</p>

</blockquote>
<p>That &ldquo;minimum of everything&rdquo; is the trap. Minimum doesn&rsquo;t mean shallow at everything. It means narrow: little, but whole. You pick the one thing the product needs to do well to prove someone wants it, and you do it end to end. The rest isn&rsquo;t &ldquo;half-done.&rdquo; It&rsquo;s cut.</p>
<p>And here&rsquo;s the catch the fear of rework hides: separating things is cheap, and merging them back is what costs. A feature is expensive to build and cheap to cut. When you cut architecture to save time, you saved on what was cheap and you&rsquo;ll pay dearly later. When you cut a feature, you saved on what was expensive and that probably nobody would use.</p>
<p><strong>An MVP that turns to junk cut in the wrong place.</strong></p>
<h2>What to cut without mercy<span class="hx:absolute hx:-mt-20" id="what-to-cut-without-mercy"></span>
    <a href="#what-to-cut-without-mercy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Cutting well is a skill, and it hurts because everything looks essential at the start. It isn&rsquo;t. Start here:</p>
<ul>
<li><strong>Features that don&rsquo;t validate the thesis.</strong> This is the mother of all cuts. If the feature doesn&rsquo;t help prove someone wants the product, it&rsquo;s not v1. The <a href="https://www.cbinsights.com/research/report/startup-failure-reasons-top/"target="_blank" rel="noopener">42% that die</a> built something without <dfn>product-market fit: evidence that there are enough people wanting what you do, at the price you charge</dfn>. They didn&rsquo;t die for lack of features. They died from features in the wrong direction.</li>
<li><strong>The second, third, and fourth feature.</strong> In an average product, <a href="https://www.pendo.io/resources/the-2019-feature-adoption-report/"target="_blank" rel="noopener">only 12% of features drive 80% of usage</a>. In the MVP you don&rsquo;t yet know which slice that is. But you know it&rsquo;s not all twenty. Bet on one, two at most.</li>
<li><strong>Scale that doesn&rsquo;t exist.</strong> Cache, queue, sharding, microservice for ten users. Optimizing a load you don&rsquo;t have is solving an imaginary problem while the real one (someone using it) goes unanswered.</li>
<li><strong>Configurability.</strong> Every &ldquo;what if the client wants to change this?&rdquo; becomes a settings panel that doubles the scope. In the MVP, hard-code it. Configurable is a problem for whoever already has clients.</li>
<li><strong>Polish.</strong> Animation, dark mode, a five-step onboarding, an illustrated empty state. All real, all phase 2.</li>
</ul>
<p>What&rsquo;s left looks like little. It&rsquo;s supposed to. If your MVP doesn&rsquo;t leave you a little embarrassed, you cut too LITTLE.</p>
<h2>What to keep always (keeping the separation is cheap; redoing it is what costs)<span class="hx:absolute hx:-mt-20" id="what-to-keep-always-keeping-the-separation-is-cheap-redoing-it-is-what-costs"></span>
    <a href="#what-to-keep-always-keeping-the-separation-is-cheap-redoing-it-is-what-costs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Cutting features is the easy part once the penny drops. Where I see the founder in a hurry get it wrong is the other side: what you do NOT cut, not even on the tightest deadline. There are few of them, all cheap to get right now and ruinously expensive to redo later.</p>
<ul>
<li><strong>The domain model.</strong> The names of things and how they connect. Swapping &ldquo;user&rdquo; for &ldquo;account&rdquo; and &ldquo;organization&rdquo; in month six is data migration, a refactor that crosses the whole system, and a production bug. Deciding it in week 1 costs a conversation.</li>
<li><strong>The divisions between business capabilities.</strong> Where payment ends and the order begins. You don&rsquo;t have to implement both well. You have to know where the line between them sits, so you can later touch one without dismantling the other.</li>
<li><strong>Identity and who-can-do-what.</strong> If the product has more than one kind of user, bolting auth and permissions on later is one of the most expensive refactors there is, because it touches every request.</li>
<li><strong>A thread of observability.</strong> Structured logs and a way to know what broke. It&rsquo;s not a feature. It&rsquo;s what lets you sleep.</li>
</ul>
<p>The number that justifies the stubbornness: teams <a href="https://codeclimate.com/blog/rework-costs-millions"target="_blank" rel="noopener">rework close to 26% of their code before release</a>, and Carnegie Mellon has pointed to the same root cause for decades. More than half of rework comes from a misunderstood requirement, not from badly written code. Expensive rework doesn&rsquo;t come from you coding fast. It comes from drawing the separation in the wrong place, or from not drawing one at all.</p>
<h3>How do I keep a separation for something I don&rsquo;t even know will scale?<span class="hx:absolute hx:-mt-20" id="how-do-i-keep-a-separation-for-something-i-dont-even-know-will-scale"></span>
    <a href="#how-do-i-keep-a-separation-for-something-i-dont-even-know-will-scale" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>You don&rsquo;t guess what will scale, nobody does. But you don&rsquo;t have to: instead of deciding the implementation, you decide where the seams go. Keeping the seam is cheap (a module with a clear name, payment that isn&rsquo;t shoved into the middle of the order) and behind it you do the simplest, dumbest thing that works today. When the load shows up, if it shows up, you swap what&rsquo;s behind it without touching whoever depends on it. Phase 2 becomes a part swap, not a restart.</p>
<p>The version of this discipline at the code level (organizing by feature, frontend and backend in the same repository, decisions recorded) we broke down in <a href="/en/posts/2026/06/15/codebase-novo-prompt-mvp-que-escala/">your codebase is the new prompt</a>, which is what keeps an AI agent productive in your MVP six months later. And the record of why each of those decisions exists lives in the <a href="/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/">ADRs</a>. This post is the floor above: what to cut and what to keep before the code exists.</p>
<aside class="ns-cta ns-cta-mid" data-servico="sprint">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Need an MVP in weeks that won&#39;t turn into a rewrite six months from now? Fixed scope, senior team, 4 weeks. That&#39;s what we do in a Sprint.</h3>

  <p class="ns-cta-meta">Fixed scope · Fixed price · 4 weeks · 100% senior team.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=sprint&amp;utm_content=mvp-o-que-cortar-e-o-que-manter-mid#sprint" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>The MVP is phase 1, not the prototype (phase 2 is the proof)<span class="hx:absolute hx:-mt-20" id="the-mvp-is-phase-1-not-the-prototype-phase-2-is-the-proof"></span>
    <a href="#the-mvp-is-phase-1-not-the-prototype-phase-2-is-the-proof" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s a word that gives away an MVP that turned to junk: rewrite. Joel Spolsky called rewriting from scratch <a href="https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/"target="_blank" rel="noopener">&ldquo;the single worst strategic mistake that any software company can make&rdquo;</a>, and that was in 2000, long before AI made the rewrite even more tempting and more expensive. The MVP that scales never goes through it. It goes through extensions: each phase adds on top of the previous one, because the previous one left the separation in place.</p>
<p>It&rsquo;s what we <a href="https://nextside.tech"target="_blank" rel="noopener">do at Nextside</a> in a Sprint: fixed scope, senior team, a working MVP in 4 weeks that&rsquo;s born with the right divisions to grow in phases. The hurry stays in the scope, the rigor stays in the separation. And the short deadline isn&rsquo;t a limitation, it&rsquo;s the mechanism: it forces the cutting conversation the founder puts off for months.</p>
<h2>The MVP that scales is the one you don&rsquo;t have to rebuild<span class="hx:absolute hx:-mt-20" id="the-mvp-that-scales-is-the-one-you-dont-have-to-rebuild"></span>
    <a href="#the-mvp-that-scales-is-the-one-you-dont-have-to-rebuild" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The difference between the MVP that scales and the one that turns to junk isn&rsquo;t the stack, the size of the code, or the name of the architecture. It&rsquo;s two decisions you make before writing the first line: what to cut and what to keep.</p>
<p>Cut the feature, the scale that doesn&rsquo;t exist, the polish, the &ldquo;what if.&rdquo; Keep the domain, the divisions, the identity. Do little, but whole, instead of a lot half-done, and phase 2 becomes an extension of what you already have, not the funeral of what you threw away.</p>
<p>An MVP that scales isn&rsquo;t the one that got done fastest. It&rsquo;s the one you won&rsquo;t have to rebuild.</p>
]]></content:encoded></item><item><title>Your codebase is the new prompt: the MVP that scales (or turns to junk)</title><link>https://blog.nextside.tech/en/posts/2026/06/15/codebase-novo-prompt-mvp-que-escala/</link><pubDate>Mon, 15 Jun 2026 10:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/15/codebase-novo-prompt-mvp-que-escala/</guid><dc:creator>Pablo Winter</dc:creator><category>mvp-que-escala</category><category>arquitetura</category><category>coding-agents</category><category>monorepo</category><category>feature-first</category><category>divida-tecnica</category><description>In an AI-built MVP, what makes it an MVP that scales isn't the stack. It's whether the coding agent still navigates your repo six months later.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Your codebase is the new prompt. In an MVP built with an AI agent, what decides whether it scales in phases or turns into disposable junk isn&rsquo;t the stack you picked. It&rsquo;s whether the agent can still find its way around your repo six months from now. And you solve that in the organization: code by feature, frontend and backend in the same monorepo, decisions recorded in ADRs. Not in the cleverness of the prompt.</p>
<p>The number that anchors this: in a study of coding agent trajectories on real bugs, the attempts that solved the problem touched the same file as the correct patch 93.6% of the time. The ones that failed, 62.7%. Locating the right code is half the game, and being locatable is a property of your architecture, not of the model.</p>
<p>Architecture stopped being the tax you pay to go slow. It became the thing that keeps AI fast.</p>
<h2>Junk isn&rsquo;t what was built fast. It&rsquo;s what was built blind.<span class="hx:absolute hx:-mt-20" id="junk-isnt-what-was-built-fast-its-what-was-built-blind"></span>
    <a href="#junk-isnt-what-was-built-fast-its-what-was-built-blind" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every technical founder who comes to me shows up with the same fear, and it&rsquo;s legit: &ldquo;I need to ship in weeks, but I don&rsquo;t want to rewrite everything three months from now.&rdquo; Then comes the belief I want to kill here:</p>
<blockquote>
  <p>&ldquo;Architecture is a luxury for people with time. Ship now, fix it later.&rdquo;</p>

</blockquote>
<p>I hear this every week. And I agreed on some level, until AI changed the math. Because &ldquo;fix it later&rdquo; assumes a choice that no longer exists: either you ship fast, or you deliver something well-architected. To accept that choice is to accept that the MVP is born a disposable prototype, and that the &ldquo;real&rdquo; version comes later, from scratch.</p>
<p>Hold on. That dichotomy is dead, and AI is what killed it.</p>
<p>Before, good architecture cost time. You drew boundaries, separated responsibilities, wrote docs. Every hour of that was an hour that didn&rsquo;t become a feature on screen. In an MVP with a deadline of weeks, cutting architecture looked like the rational trade-off. It was. Not anymore.</p>
<p>What changed: the code you generate today, for the most part, no longer goes straight from your head to the editor. It comes out of a <dfn>coding agent: an AI agent that reads, edits, and runs your repository on its own</dfn>, operating inside a harness, the platform that plugs the model into the code tooling. Claude Code and Cursor are two harnesses. And that agent has a trait that changes the whole calculation: it&rsquo;s only as fast as your repo lets it be.</p>
<p>Vibe coding (the whole &ldquo;ask, accept, deploy&rdquo; without understanding what came out) is great for a weekend prototype. The problem is the bill, which isn&rsquo;t linear. A <a href="https://arxiv.org/abs/2512.11922"target="_blank" rel="noopener">2025 paper</a> formalized this as the <em>flow-debt trade-off</em>: the fluidity of generating code masks the debt piling up in parallel. Architectural inconsistency, a dependency nobody evaluated, the same problem solved five different ways. Around the sixth month, the cost of undoing the debt overtakes the value of what was built.</p>
<p>It turns into a ball and chain. And the cruel detail: the ball and chain doesn&rsquo;t just slow down your team. It slows down the very agent that created it. The signals it relies on to find its way (consistent naming, predictable patterns, low coupling) were destroyed by the careless generation itself.</p>
<p><strong>An MVP that turns to junk isn&rsquo;t the one built fast. It&rsquo;s the one built BLIND</strong>, leaving no trail for the AI or for the human who has to work on it later.</p>
<h2>AI reads your repository, not your prompt<span class="hx:absolute hx:-mt-20" id="ai-reads-your-repository-not-your-prompt"></span>
    <a href="#ai-reads-your-repository-not-your-prompt" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s a line from Matt Pocock that captures the shift: &ldquo;your codebase, not your prompt, decides the quality of the AI&rsquo;s output.&rdquo; Sounds like an exaggeration. It isn&rsquo;t.</p>
<p>Look at how Claude Code finds code in a large repository. It doesn&rsquo;t use semantic search, it has no magic embeddings index. It does what a senior dev would do: navigates the filesystem, reads a file, and runs grep, the terminal&rsquo;s old literal text search, to find exactly what it needs. Anthropic chose grep on purpose: embeddings go stale, the repo changes all the time, and a stale index lies.</p>
<p>The consequence is physical, not philosophical: <em>&ldquo;grep finds strings, not intent.&rdquo;</em> If the function that matters is called <code>validateToken</code>, the agent finds it on the first try. If the logic is scattered across five files loosely tied by imports, with generic names like <code>handler</code> or <code>process</code>, it digs around, loads too many files, and <a href="/en/posts/2026/06/12/spec-driven-development-gargalo-execucao/">burns context</a> before it even starts the work.</p>
<p>And here lives the number that opens this post. Researchers looked at coding agent trajectories on real SWE-bench bugs. The attempts that fixed the bug touched the same file as the correct patch 93.6% of the time. The ones that failed, 62.7%. Translating: the agent&rsquo;s bottleneck is almost never &ldquo;knowing how to code.&rdquo; It&rsquo;s finding the right snippet. Locating well is what separates the PR that merges from the one that rots.</p>
<p>Organizing by technical layer sabotages exactly that. When everything is <code>controllers/</code>, <code>services/</code>, <code>models/</code>, to touch checkout the agent opens five folders and loads files from another twelve features that live in the same folders. The context window becomes, in the words of an article I read about this, &ldquo;a junkyard of irrelevant stuff.&rdquo;</p>
<p>And it&rsquo;s not just the AI that suffers. Technical layering is the old SRP violation, the first principle of SOLID, which Uncle Bob redefined as &ldquo;gather together the things that change for the same reasons, and separate those things that change for different reasons.&rdquo; Organizing by layer does the opposite: it shatters the feature (which changes together) across four folders, and piles into each folder code whose only thing in common is being &ldquo;a controller.&rdquo; The fix has a name, and it&rsquo;s the subject of the next section.</p>
<h3>Shouldn&rsquo;t AI be smart enough to find it on its own?<span class="hx:absolute hx:-mt-20" id="shouldnt-ai-be-smart-enough-to-find-it-on-its-own"></span>
    <a href="#shouldnt-ai-be-smart-enough-to-find-it-on-its-own" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It&rsquo;s the question every CTO asks, and the honest answer is: it is, up to a point, and that makes your complacency worse. The agent does find it. It reads 25 files to answer about 3 functions, because without structure it didn&rsquo;t know which 3 they were. It works, and it charges you in tokens, in time, and in hallucination when the context fills up with noise.</p>
<p>And here I have to be honest, because the simplistic version of this idea (&ldquo;a bad codebase blocks the AI&rdquo;) is overblown. It&rsquo;s not that human and agent get stuck the same way. They have opposite strengths. The AI can brute-force its way through a chaotic repo: business rules scattered across twenty files, it burns a million tokens of context and finds it anyway. A human, in the same repo, would take days, or give up. In that case the AI is better than you.</p>
<p>It&rsquo;s just that the human has a weapon the AI doesn&rsquo;t have natively: the IDE. You fire an event with <code>ApplicationEventPublisher</code> in Spring, and IntelliJ shows you every <code>@EventListener</code> that listens to that event, in order, in one click. It&rsquo;s a semantic index of the entire codebase, for free. The AI doesn&rsquo;t have that: it falls back on a bunch of greps and on loading file after file into context, and that&rsquo;s where context rot hits, the degradation of model quality as the window fills.</p>
<p>So the right framing isn&rsquo;t &ldquo;AI exposes bad architecture.&rdquo; It&rsquo;s: bad architecture charges a different toll from each one. From the human, in time and in IDE dependence. From the AI, in tokens and in context rot. An organized repo lowers the toll for both at once. That&rsquo;s why the codebase is the new prompt: it is, literally, the context the agent reads before each task, and the cleaner it is, the less it pays to understand you.</p>
<h2>Organize by feature, not by layer (and forget the architecture&rsquo;s name)<span class="hx:absolute hx:-mt-20" id="organize-by-feature-not-by-layer-and-forget-the-architectures-name"></span>
    <a href="#organize-by-feature-not-by-layer-and-forget-the-architectures-name" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The fix is more boring than it sounds, and it&rsquo;s free: organize code by feature, not by technical layer.</p>
<p>Instead of <code>controllers/</code>, <code>services/</code>, <code>repositories/</code> (where each feature is shattered across four folders), you make one folder per business capability: <code>orders/</code>, <code>payments/</code>, <code>refunds/</code>, each with its own controller, service, and data access inside. The name for this, in the literature, is <dfn>vertical slice: a slice that runs from the edge (the request) to the bottom (the database), whole, in the same place</dfn>. Jimmy Bogard nailed the golden rule: &ldquo;minimize coupling between slices, and maximize coupling in a slice.&rdquo;</p>
<p>For the AI, this is attention routing. The agent reads the folder name before opening any file, and infers the scope of the task right away. &ldquo;Touch the refund&rdquo; already sends it to <code>refunds/</code>, and everything that matters is placed right there together. Uncle Bob called this Screaming Architecture over ten years ago: the folder structure should scream what the system does, not which framework it uses. In 2011 it was aesthetics. Today it&rsquo;s performance for whoever&rsquo;s going to code. And whoever&rsquo;s going to code is an agent.</p>
<p>Here&rsquo;s a piece of honesty that disarms. In the briefing for this post, someone on the team wrote &ldquo;use NGC architecture or whatever fits.&rdquo; I went to look up what &ldquo;NGC architecture&rdquo; is. It doesn&rsquo;t exist. It&rsquo;s not a consolidated pattern; it&rsquo;s probably a typo for N-tier, or just an acronym that slipped out. And you know what that proves? That the name matters less than you think. Clean, hexagonal, onion, N-tier: deep down they&rsquo;re the same idea (business rules at the center, framework and database at the edge) with different vocabulary. What decides whether the agent, and your team, will be able to evolve the code isn&rsquo;t the architecture&rsquo;s badge. It&rsquo;s the discipline of boundaries.</p>
<p>That said, don&rsquo;t fall into the opposite extreme. Clean Architecture with four layers of abstraction in an MVP is over-engineering; someone compared it to playing Dark Souls: too many rules, too much ceremony, for a product nobody may even want yet. The point isn&rsquo;t the purest architecture. It&rsquo;s the most navigable one.</p>
<p>And there&rsquo;s a trade-off, of course. Organizing by feature generates duplication: two slices validate something similar, three features hit the same table. The instinct is to abstract it all into a <code>shared/</code>, and then <code>shared/</code> becomes the trash can that couples everyone together again. Sandi Metz has the best rule for this: &ldquo;duplication is far cheaper than the wrong abstraction.&rdquo; In an MVP, accepting a bit of copy-paste to keep slices independent almost always beats religious DRY. Shared only for real infra: database client, logging, auth. Never for business rules.</p>
<aside class="ns-cta ns-cta-mid" data-servico="discovery">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">About to ship an MVP with AI and you want it to scale in phases, not become a rewrite? We align architecture and stack in a Discovery, before you burn your budget.</h3>

  <p class="ns-cta-meta">Technical validation · 2-3 weeks · Outcome: roadmap &#43; prototype.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=discovery&amp;utm_content=codebase-novo-prompt-mvp-que-escala-mid#discovery" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>Monorepo and ADRs: stop making the AI (and your team) guess<span class="hx:absolute hx:-mt-20" id="monorepo-and-adrs-stop-making-the-ai-and-your-team-guess"></span>
    <a href="#monorepo-and-adrs-stop-making-the-ai-and-your-team-guess" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Organizing inside the project solves half. The other half is what&rsquo;s between the projects, and that&rsquo;s where the monorepo comes in.</p>
<p>The idea: frontend and backend in the same repository. Together with the docs folder, the ADRs, the conventions. One history. There&rsquo;s a line from Francis Dortort that closes the argument: &ldquo;a repository boundary is a context wall. Every wall degrades the quality of AI-generated output.&rdquo;</p>
<p>Think about the concrete case. You ask &ldquo;add a field to the signup form.&rdquo; In a setup with two separate repos, the agent needs two conversations with no memory of each other, and the contract between frontend and backend drifts along the way. In a monorepo, it&rsquo;s a single transaction: it renames the field in the database, updates the API, adjusts the UI and the test, in a single context, in a single commit. DB, API, and UI without switching windows. It&rsquo;s exactly the kind of cross-cutting change an MVP makes all the time.</p>
<p>Tooling? Start simple: pnpm workspaces with Turborepo handles most MVPs with very low friction. Nx when the scaling pain shows up, not before. And the honest trade-off: a monorepo without selective build tooling gives you a slow CI. If every commit rebuilds everything, the bill explodes. It&rsquo;s a solvable problem, but it&rsquo;s a problem you take on deliberately.</p>
<p>The ADR is the other piece, and the most underrated. ADRs I already <a href="/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/">explained in another post</a>: a short, dated record of a technical decision and the why behind it. What changed with AI is the use. Without the ADRs in context, the agent ends up, in the words of an article, &ldquo;deprived of architectural intent&rdquo;: it sees the implementation, but not the reasoning. It knows you use Postgres. It doesn&rsquo;t know why you ruled out Mongo, so it might &ldquo;improve&rdquo; your code by reintroducing exactly what you rejected. The ADR, together with a <code>CLAUDE.md</code> or <code>AGENTS.md</code> in the repo, is how you hand over intent on a silver platter, instead of praying it guesses.</p>
<p>Now the counterweight, because I&rsquo;m not selling miracles. None of this is magic, and more documents isn&rsquo;t always better. An ETH Zurich study tested context files and found that an auto-generated <code>AGENTS.md</code> WORSENED the success rate in several scenarios and raised inference cost by more than 20%. METR itself measured experienced senior devs getting 19% slower with AI in a controlled study, while believing, themselves, they were faster.</p>
<p>What that tells you: the gain doesn&rsquo;t come from stuffing the repo with markdown. It comes from the non-obvious well recorded: the counterintuitive decision, the gotcha you can&rsquo;t infer from the code. ADRs and conventions are a scalpel, not a flood. Good context, in Anthropic&rsquo;s own words, is &ldquo;the smallest possible set of high-signal tokens,&rdquo; not the largest pile of tokens.</p>
<h2>The MVP that scales is the one AI still understands tomorrow<span class="hx:absolute hx:-mt-20" id="the-mvp-that-scales-is-the-one-ai-still-understands-tomorrow"></span>
    <a href="#the-mvp-that-scales-is-the-one-ai-still-understands-tomorrow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Put it all together and the picture is simple. The MVP that scales doesn&rsquo;t have a more expensive stack or a more sophisticated architecture than the MVP that turns to junk. It has boundaries. Code by feature, frontend and backend in the same place, decisions recorded. Three cheap disciplines that, added up, keep an AI agent productive in phase 2, phase 3, phase 4, instead of stuck at month six.</p>
<p>This doesn&rsquo;t mean building everything. It means cutting the right thing, and <a href="/en/posts/2026/06/16/mvp-o-que-cortar-e-o-que-manter/">what to cut and what to keep in an MVP</a> became a post of its own. Martin Fowler has a technical debt quadrant every founder should know: debt can be deliberate and prudent (&ldquo;we need to ship now and deal with the consequence later&rdquo;) or reckless and blind (&ldquo;we don&rsquo;t have time for design&rdquo;). The first is a legitimate business decision. The second is the prototype that&rsquo;s going to blow up. Junk isn&rsquo;t having debt. It&rsquo;s not knowing you have it.</p>
<p>And what to cut first? Premature scale. Startup Genome looked at more than three thousand startups and found that 74% of the ones that died, died from scaling too early: optimization, microservices, distributed infra for a load that didn&rsquo;t exist. Microservices in an MVP is the perfect example of reckless debt disguised as good engineering. Start with a monolith, modular, with clean boundaries. The boundary is what makes the next phase an extraction, not a demolition.</p>
<p>It was the same pattern I wrote about when <a href="/en/posts/2026/05/25/code-review-novo-gargalo-coderabbit/">code review became the bottleneck</a>: AI sped up the individual, and the part that didn&rsquo;t keep up became the brake. With architecture it&rsquo;s the same, only earlier: the disorganized repo is the bottleneck you plant on day one and only feel on day one hundred and eighty.</p>
<p>Your MVP doesn&rsquo;t need to be perfect to scale. It needs to be readable. The code AI still understands six months from now is the code that doesn&rsquo;t turn to junk. The rest is a rewrite waiting for its date.</p>
]]></content:encoded></item><item><title>Spec-driven development: getting unstuck from vibe coding</title><link>https://blog.nextside.tech/en/posts/2026/06/13/spec-driven-development-sair-do-vibe-coding/</link><pubDate>Sat, 13 Jun 2026 08:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/13/spec-driven-development-sair-do-vibe-coding/</guid><dc:creator>Lucas Israel</dc:creator><category>spec-driven-development</category><category>vibe-coding</category><category>ai-tooling</category><category>ai-agents</category><category>architecture</category><description>Why vibe coding stalls the moment you try to scale, and how spec-driven development delivers an order of magnitude less rework with AI agents.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>You prototyped fast with AI. Now the app won&rsquo;t scale, and every new feature breaks two old ones. That&rsquo;s the exact point where vibe coding stops helping, and where <dfn>spec-driven development (SDD)</dfn> starts paying off. The idea is simple and it flips the order of the game: the <strong>specification becomes the primary artifact</strong>, and the agent implements from it instead of guessing. The trade-off is real: you swap the rush of &ldquo;it worked first try&rdquo; for 30 minutes writing a spec before you code. For a throwaway prototype, it&rsquo;s not worth it. For what&rsquo;s going to production and needs to grow, it&rsquo;s what separates delivery from duct tape.</p>
<p>Vibe coding is great for figuring out what to build. It&rsquo;s terrible for sustaining what already exists.</p>
<h2>Vibe coding doesn&rsquo;t fail because it&rsquo;s AI. It fails because it&rsquo;s ambiguous.<span class="hx:absolute hx:-mt-20" id="vibe-coding-doesnt-fail-because-its-ai-it-fails-because-its-ambiguous"></span>
    <a href="#vibe-coding-doesnt-fail-because-its-ai-it-fails-because-its-ambiguous" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In a loose prompt, the model has 30 ways to implement the same feature, and run the same instruction twice, you get something different. That ambiguity is tolerable in a prototype and fatal in maintenance: nobody (not you, not the next dev, not the agent) knows what the rule was. The code is the only source of truth, and it changes with every generation.</p>
<p>If you&rsquo;re a CTO and still on vibe coding, the symptom is familiar: the MVP shipped in a week, the team doubled its speed at first, and now every AI PR needs three rounds of review because the agent &ldquo;forgot&rdquo; a decision that was never written down anywhere. I&rsquo;ve watched this up close more than once: people think it&rsquo;s a matter of hiring one more senior. It isn&rsquo;t.</p>
<p><strong>The bottleneck stopped being writing code. It became aligning context.</strong></p>
<h2>What spec-driven development changes<span class="hx:absolute hx:-mt-20" id="what-spec-driven-development-changes"></span>
    <a href="#what-spec-driven-development-changes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>SDD puts the specification <strong>before</strong> code generation: requirements, business rules, API contracts, and architecture constraints become a document the agent reads and follows. The spec is versioned, reviewed, and reused: the code becomes output, not the source of truth. Less guessing, fewer &ldquo;that&rsquo;s not what I meant&rdquo; loops.</p>
<p>In practice the flow is straightforward: you describe the behavior and the constraints → the agent proposes a plan against the spec → you validate the plan (not 400 lines of diff) → the agent implements and tests against the criteria the spec itself defined. Review stops being &ldquo;is this right?&rdquo; and becomes &ldquo;does this match the spec?&rdquo;. A question you can answer in minutes.</p>
<p>This isn&rsquo;t blog theory. On internal projects with <a href="https://www.turingpost.com/p/sdd"target="_blank" rel="noopener">Spec Kit, GitHub reports roughly an order of magnitude fewer &ldquo;regenerate from scratch&rdquo; cycles</a> than ad-hoc prompting. AWS documents, with Kiro, <a href="https://towardsdatascience.com/from-vibe-coding-to-spec-driven-development/"target="_blank" rel="noopener">cases of 40-hour features delivered in under 8 hours of human time</a> when the work started from the spec. And the very person who coined &ldquo;vibe coding&rdquo;, Andrej Karpathy, has publicly acknowledged the limits of the approach for real software.</p>
<h3>Does SDD work with AI agents like Claude and Copilot?<span class="hx:absolute hx:-mt-20" id="does-sdd-work-with-ai-agents-like-claude-and-copilot"></span>
    <a href="#does-sdd-work-with-ai-agents-like-claude-and-copilot" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Yes, and that&rsquo;s exactly what it was built for. Tools like GitHub Spec Kit and AWS Kiro integrate with agents like Claude Code, Copilot, and Gemini CLI. The spec becomes the context the agent follows: the same role a well-written <code>CLAUDE.md</code> plays day to day, just promoted to a first-class artifact of the project.</p>
<aside class="ns-cta ns-cta-mid" data-servico="discovery">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Got an idea that&#39;s stuck, or a vibe-coded MVP that needs to become a real product? A Discovery turns it into an executable spec: roadmap &#43; prototype in 2-3 weeks.</h3>

  <p class="ns-cta-meta">Technical validation · 2-3 weeks · Outcome: roadmap &#43; prototype.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=discovery&amp;utm_content=spec-driven-development-sair-do-vibe-coding-mid#discovery" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>Where this breaks<span class="hx:absolute hx:-mt-20" id="where-this-breaks"></span>
    <a href="#where-this-breaks" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>SDD is no silver bullet, and pretending it is would be falling for the same mistake as the vibe coding hype.</p>
<blockquote>
  <p>&ldquo;This is just more ceremony. One more pretty document nobody reads.&rdquo;</p>

</blockquote>
<p>It can be. That&rsquo;s the real risk, and I&rsquo;ve watched it turn into exactly that. Writing a spec costs head time: for a one-day spike, a hypothesis test, or a throwaway, the overhead doesn&rsquo;t pay off, vibe coding wins. SDD is also only as good as the spec: a vague spec produces vague code, and you&rsquo;ve only moved the ambiguity into a prettier document.</p>
<p>The rule I use is simple: <strong>if the code will live longer than a month or pass through someone else&rsquo;s hands, spec it. If it&rsquo;s throwaway, don&rsquo;t.</strong> The decision is by stage, not by dogma.</p>
<h3>Does spec-driven development replace vibe coding?<span class="hx:absolute hx:-mt-20" id="does-spec-driven-development-replace-vibe-coding"></span>
    <a href="#does-spec-driven-development-replace-vibe-coding" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Not for everything. Vibe coding stays great for prototypes, spikes, and hypothesis validation, where the speed of discovering beats the discipline of sustaining. SDD wins when the code goes to production, needs to scale, or passes through other people&rsquo;s hands. It&rsquo;s not one replacing the other. It&rsquo;s knowing which stage you&rsquo;re in.</p>
<h2>How to get out of vibe coding without stopping the team<span class="hx:absolute hx:-mt-20" id="how-to-get-out-of-vibe-coding-without-stopping-the-team"></span>
    <a href="#how-to-get-out-of-vibe-coding-without-stopping-the-team" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>You don&rsquo;t have to rewrite everything. The migration is incremental and starts on the next feature, not in a big bang:</p>
<ul>
<li><strong>Write the spec before calling the agent</strong>, even a short one. Expected behavior, rules, constraints. Five lines already change the game.</li>
<li><strong>Every business rule lives in the spec</strong>: not in a comment, not in Slack, not in someone&rsquo;s head. If it&rsquo;s not in the spec, it doesn&rsquo;t exist to the agent.</li>
<li><strong>Use the spec as the review criterion</strong>: the question stops being &ldquo;is this good?&rdquo; and becomes &ldquo;does this match what we specified?&rdquo;.</li>
</ul>
<p>Within a few weeks the rework drops, because the context stopped evaporating between one generation and the next.</p>
<h3>Does SDD make development slower?<span class="hx:absolute hx:-mt-20" id="does-sdd-make-development-slower"></span>
    <a href="#does-sdd-make-development-slower" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>At the start of each feature, yes, you invest those 30 minutes writing the spec. Overall, it tends to be faster: it&rsquo;s the difference between the order of magnitude fewer regenerate-from-scratch cycles GitHub reports and the 40-hour features delivered in under 8 hours AWS reports. You pay upfront so you don&rsquo;t pay the compound interest of rework later.</p>
<h2>The spec is the context that doesn&rsquo;t evaporate<span class="hx:absolute hx:-mt-20" id="the-spec-is-the-context-that-doesnt-evaporate"></span>
    <a href="#the-spec-is-the-context-that-doesnt-evaporate" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vibe coding gives you the first mile for free and charges the rest of the road in rework. SDD does the opposite: it charges upfront and gives back predictability.</p>
<p>The point isn&rsquo;t to abandon AI: it&rsquo;s to stop treating the generated code as the source of truth. The source of truth is the spec. The code is just the output.</p>
<p>If your team is going to burn AI either way, burn it on what&rsquo;s specified.</p>
]]></content:encoded></item><item><title>The spec was the easy part. SDD's bottleneck is execution</title><link>https://blog.nextside.tech/en/posts/2026/06/12/spec-driven-development-gargalo-execucao/</link><pubDate>Fri, 12 Jun 2026 09:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/12/spec-driven-development-gargalo-execucao/</guid><dc:creator>Pablo Winter</dc:creator><category>spec-driven-development</category><category>dynamic-workflows</category><category>claude-code</category><category>context-rot</category><category>orquestracao</category><category>ia-development</category><description>Spec-Driven Development externalizes intent into markdown, but pushes the pain into execution. Orchestrate with state outside the model's window.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Spec-Driven Development solved a real problem: you externalize intent into versioned markdown (PRD, tech spec, task list) and the spec becomes the source of truth. Except nobody tells you the bill for execution. One spec generates dozens of tasks, and running all of them in a single conversation is where the context degrades and you turn into a window manager. The way out the whole industry converged on, from expensive framework to a bash <code>while</code> loop, is the same: take state out of the model&rsquo;s window and put it in a file or in code, with a reviewer who is never the one who wrote it. Anthropic&rsquo;s <dfn>Dynamic Workflows</dfn>, where Claude itself writes the script that orchestrates the agents, are one form of this. There are several.</p>
<p>This post is about why execution was the bottleneck all along, and why everyone is arriving at the same two rules.</p>
<h2>Nobody tells you the bill for execution<span class="hx:absolute hx:-mt-20" id="nobody-tells-you-the-bill-for-execution"></span>
    <a href="#nobody-tells-you-the-bill-for-execution" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Spec-Driven Development is simple to describe: you write the intent before the code. PRD becomes tech spec, tech spec becomes a list of atomic tasks, and only then does the agent generate code. GitHub Spec Kit, Amazon Kiro, Tessl, each with its own flavor. The spec is the source of truth, the code is a consequence.</p>
<p>Writing the spec is the easy part.</p>
<p>My last spec generated thirty-something tasks. Hell didn&rsquo;t start there. It started when I had to execute those thirty-something in a single conversation. You run task after task, the window fills up, and somewhere around the twentieth the agent has already forgotten the decision it made itself on the fourth.</p>
<p>This has a name and it&rsquo;s been measured. <dfn>Context rot</dfn>, the drop in model quality as the context grows, was tested by Chroma across 18 models. All 18 degraded, and the degradation starts well before the window is full. The &ldquo;Lost in the Middle&rdquo; paper had already shown the same curve: the model loses information buried in the middle of a long context.</p>
<p>The patch the community adopted is to open a clean window per task: fresh context, paste the spec back in, point at the task, execute, repeat. It works against the rot. And it turns you into a copy-paste intern, thirty-something times over.</p>
<p><strong>The spec was the easy part.</strong></p>
<h2>The three phases of whoever carries the context<span class="hx:absolute hx:-mt-20" id="the-three-phases-of-whoever-carries-the-context"></span>
    <a href="#the-three-phases-of-whoever-carries-the-context" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The bottleneck was always the same: someone has to hold the state and consolidate the results while the tasks run. What changed is who carries that weight.</p>
<p><strong>Phase 1, by hand.</strong> You are the context window. You run task by task, hit <code>/clear</code>, reread the spec, hold the state in your head and in the conversation. Goes fine for five tasks. By the thirtieth, you&rsquo;re the bottleneck.</p>
<p><strong>Phase 2, delegating.</strong> You throw execution at the subagents. It helps. Except the output of all of them comes back into the same window, the one of the main agent you&rsquo;re steering, and that window is the one that becomes the consolidator and rots. Agent Teams got better with a shared task list, but the lead still steers step by step. The bottleneck moved, it didn&rsquo;t disappear.</p>
<p><strong>Phase 3, workflow.</strong> Here the physics changes. The plan leaves your context and becomes code. A script holds the loop and the intermediate results, and the model&rsquo;s context only sees the final answer. Each task runs in an isolated window. This is where I finally stopped being the bottleneck. It&rsquo;s what Claude Code&rsquo;s Dynamic Workflows do: Claude itself writes a JavaScript orchestration script, and a runtime executes it in the background, with up to 16 simultaneous agents and a ceiling of a thousand per run.</p>
<p>Jarred Sumner, creator of Bun, took this to the extreme. He ported Bun from Zig to Rust on exactly this setup: tasks in parallel, two reviewers contesting each file. Seven hundred and fifty thousand lines of Rust, 99.8% of the test suite passing, eleven days from first commit to merge. It hasn&rsquo;t gone to production yet, it&rsquo;s a capability demo. But that&rsquo;s the number.</p>
<h3>Why can&rsquo;t the reviewer be the author?<span class="hx:absolute hx:-mt-20" id="why-cant-the-reviewer-be-the-author"></span>
    <a href="#why-cant-the-reviewer-be-the-author" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Because the model has self-preference bias. Self-preferential bias is the model&rsquo;s tendency to defend its own output when it&rsquo;s also the judge. A grader who wrote the exam is a suspect grader.</p>
<p>The way to kill this is structural. The reviewer runs as a separate agent, with its own context, sometimes on a different model, with the single mission of trying to <a href="/en/posts/2026/05/25/code-review-novo-gargalo-coderabbit/">knock the result down before it gets accepted</a>. In the workflow you put one adversarial verifier per output. In the end, the agents themselves open the PRs. Whoever produces is NEVER whoever approves.</p>
<h2>It&rsquo;s expensive, and the ROI is niche<span class="hx:absolute hx:-mt-20" id="its-expensive-and-the-roi-is-niche"></span>
    <a href="#its-expensive-and-the-roi-is-niche" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I&rsquo;ll be honest, because the part nobody posts is the cost. Dynamic Workflows is a research preview and it burns tokens without mercy. There are reports of people torching the five-hour limit in eighteen minutes, and of runs of three million tokens without a single cost warning along the way. This isn&rsquo;t free scale.</p>
<p>So who does this pay off for?</p>
<p>For whoever has the seniority to review. The senior&rsquo;s leverage is judgment: knowing when the AI spat out slop, correcting course, blocking the bad task. A junior on the same tool is money down the drain, because without real software engineering they accept whatever comes and bang their head against the final result. The ROI is glued to seniority, not to the tool.</p>
<p>This becomes the default the day running thirty tasks in parallel, each with its own reviewer, costs the same as running one by hand. Whoever wants to anticipate that day already makes the token hurt less with model routing: most of the tasks on a cheap model, the expensive one only on the plan and the review.</p>
<aside class="ns-cta ns-cta-mid" data-servico="discovery">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Going to put agents to work running specs in your team? We validate where AI actually accelerates in a Discovery, before you burn budget.</h3>

  <p class="ns-cta-meta">Technical validation · 2-3 weeks · Outcome: roadmap &#43; prototype.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=discovery&amp;utm_content=spec-driven-development-gargalo-execucao-mid#discovery" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>The tool changes, the physics is the same<span class="hx:absolute hx:-mt-20" id="the-tool-changes-the-physics-is-the-same"></span>
    <a href="#the-tool-changes-the-physics-is-the-same" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The most interesting part isn&rsquo;t any specific tool. It&rsquo;s that everyone, starting from different places, is arriving at the same two rules.</p>
<p><strong>Rule one: the project&rsquo;s memory lives in the files, not in the context.</strong> <a href="/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/">ADR in the repo</a>, <code>project-context.md</code>, <code>state.json</code>, <code>todo.md</code>, a versioned decision matrix. The agent doesn&rsquo;t need to &ldquo;remember&rdquo; the decision from task four. It reads the file. The context rot disappears because you stopped stacking history in the window.</p>
<p><strong>Rule two: the reviewer is never the author, by construction.</strong> Separate contexts for whoever generates and whoever validates. The validator walks in assuming there&rsquo;s a bug and goes hunting.</p>
<p>Look at how many people arrived at this from opposite paths:</p>
<ul>
<li><strong>Ralph loop</strong> (Geoffrey Huntley): wraps the agent in a <code>while</code>, clean context on every turn, memory on disk. Monolithic on purpose. He rejects multi-agent, and even so externalizes state in exactly the same way.</li>
<li><strong>Dynamic Workflows</strong> (Anthropic): the opposite of Ralph, fan-out of hundreds of agents, but the script holds the state and the adversarial reviewer is separate.</li>
<li><strong>BMAD, MDDD, cstk</strong>: community frameworks that, each in its own way (ADR plus adversarial reviewer, decision matrix, waves with <code>state.json</code> and model routing), implement the same two rules.</li>
</ul>
<blockquote>
  <p>&ldquo;You&rsquo;re just reinventing a <code>while</code> loop with more steps.&rdquo;</p>

</blockquote>
<p>In part, yes. The Ralph loop is the rawest form of this, and it works. The difference is what you hang on top: consolidator, separate reviewer, model routing, <a href="/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/">all coded into a harness</a> instead of in your three-in-the-morning prompt. The principle is old. The discipline of applying it is what changes the result.</p>
<h2>The work you thought was thinking<span class="hx:absolute hx:-mt-20" id="the-work-you-thought-was-thinking"></span>
    <a href="#the-work-you-thought-was-thinking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Spec-Driven Development didn&rsquo;t fail. It solved the part you could solve by writing, and exposed the part that was missing: executing without the context rotting and without you in the middle of the loop copying output from one side to the other.</p>
<p>The way out isn&rsquo;t a tool. It&rsquo;s a physics: state outside the window, reviewer outside the author. Dynamic Workflows, Ralph loop, cstk, BMAD, they&rsquo;re accents of the same sentence.</p>
<p>The work you thought was thinking was always managing context. AI didn&rsquo;t change that. It just made it obvious.</p>
]]></content:encoded></item><item><title>Maestro + Claude Code: your app tested in the simulator like Playwright tests the web</title><link>https://blog.nextside.tech/en/posts/2026/06/01/maestro-claude-code-testar-app-no-simulador/</link><pubDate>Mon, 01 Jun 2026 09:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/06/01/maestro-claude-code-testar-app-no-simulador/</guid><dc:creator>Bruno Raphael</dc:creator><category>maestro</category><category>mobile-testing</category><category>react-native</category><category>claude-code</category><category>qa-automation</category><description>You can have Claude navigate and test your app in the simulator like Playwright does on the web. With Maestro: one YAML, iOS and Android, zero instrumentation.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Claude Code already navigates your site on its own through Playwright: it clicks, fills, validates regressions. For mobile apps you can do the same thing, but nobody really explains how. I went digging. The answer is <dfn>Maestro</dfn>, an open source mobile E2E testing framework with flows written in YAML, plugged into Claude Code. A single test file runs the same on iOS and Android, on top of the compiled binary, without instrumenting the app. React Native, native, or Flutter, doesn&rsquo;t matter. Claude inspects the screen, writes the flow, runs it, and fixes what breaks. And no: the right path is NOT &ldquo;giving Claude access to the screen&rdquo;. Screenshot by coordinate is the last resort, not the first.</p>
<p>This post is the setup I put together to close on mobile the gap that <a href="/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/">Playwright already closed for the web</a>. <a href="https://nextside.tech"target="_blank" rel="noopener">Here at Nextside</a> it&rsquo;s not a production pipeline yet. It&rsquo;s the path I&rsquo;m adopting, with the engineering broken down, the commands in hand, and the numbers from people who already walked it.</p>
<h2>It&rsquo;s not &ldquo;giving access to the screen&rdquo;. It&rsquo;s reading the tree.<span class="hx:absolute hx:-mt-20" id="its-not-giving-access-to-the-screen-its-reading-the-tree"></span>
    <a href="#its-not-giving-access-to-the-screen-its-reading-the-tree" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I bring this up, the same question always comes, and I asked it myself at first: &ldquo;can&rsquo;t Claude just look at the screen and tap, like a human?&rdquo;. It can. It&rsquo;s called <dfn>Computer Use</dfn>: Claude controls the interface through screenshots and clicks on pixel coordinates. It launched in Claude Code in March 2026, it drives the simulator, it works for a demo.</p>
<p>But it&rsquo;s the wrong way for testing.</p>
<p>The Playwright you already use never looked at a single pixel. It reads the <em>accessibility tree</em>, the structured tree that describes &ldquo;button labeled Sign in, here&rdquo;. It acts by element, not by coordinate. That&rsquo;s why it&rsquo;s fast and doesn&rsquo;t hallucinate where to click.</p>
<p>The difference is measurable in tokens: the accessibility tree of one screen comes in at <a href="https://github.com/conorluddy/ios-simulator-skill"target="_blank" rel="noopener">around 10 tokens, and a screenshot of the same screen costs 1,600 to 6,300</a>. Multiply that by every step of a twenty-screen test and you get why vision doesn&rsquo;t scale in a QA loop.</p>
<p>At the bottom there are three ways to make Claude touch the app, from best to worst:</p>
<ul>
<li><strong>MCP or CLI reading the tree.</strong> Structured, deterministic, cheap on tokens. It&rsquo;s the &ldquo;Playwright way&rdquo;, and it&rsquo;s where Maestro lives.</li>
<li><strong>Computer Use through screenshots.</strong> Claude sees the screen and guesses a coordinate. It generalizes to any app, but it&rsquo;s slow (2 to 5 seconds per action), misses clicks, and burns context.</li>
<li><strong>Nothing.</strong> You testing everything by hand, which is what we&rsquo;re leaving behind.</li>
</ul>
<p>Anthropic itself orders it this way. The <a href="https://code.claude.com/docs/en/computer-use"target="_blank" rel="noopener">Claude Code tool hierarchy</a> is MCP first, then shell, then Chrome, and it only falls to screen control when nothing else reaches: &ldquo;native apps, simulators, and tools without an API&rdquo;.</p>
<p><strong>Screenshot is the last resort, not the first.</strong></p>
<h2>Maestro: one YAML, iOS and Android, zero instrumentation<span class="hx:absolute hx:-mt-20" id="maestro-one-yaml-ios-and-android-zero-instrumentation"></span>
    <a href="#maestro-one-yaml-ios-and-android-zero-instrumentation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If the right way is to read the tree, I need a tool that exposes the simulator&rsquo;s tree to Claude. There are several. I settled on Maestro, and for anyone keeping React Native and native apps, it wins on three concrete counts:</p>
<ul>
<li><strong>It works at the accessibility layer, on top of the compiled binary.</strong> It doesn&rsquo;t matter if the app is React Native, native Swift/Kotlin, or Flutter. Maestro tests the finished APK/IPA, with no driver installed and no change to the source code. For a team running RN and native side by side, that&rsquo;s the end of maintaining two testing stacks.</li>
<li><strong>The same file runs on both systems.</strong> You write the flow once. It runs on the iPhone simulator and the Android emulator without rewriting a single line.</li>
<li><strong>YAML that humans and machines read.</strong> It&rsquo;s not code with fragile selectors. It&rsquo;s a declarative sequence that Claude generates and edits on the spot.</li>
</ul>
<p>A Maestro flow starts simple like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">appId</span><span class="p">:</span><span class="w"> </span><span class="l">com.yourcompany.app</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="l">launchApp</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">tapOn</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;login_button&#34;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">inputText</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;user@nextside.tech&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">tapOn</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Sign in&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">assertVisible</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Welcome&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>appId</code>, three dashes, and the commands in almost natural language: <code>launchApp</code>, <code>tapOn</code>, <code>inputText</code>, <code>assertVisible</code>. Anyone who&rsquo;s never seen it gets it in ten seconds.</p>
<p>Where it gets serious is reuse. The login repeats in every test, so you pull it out once and call it with <code>runFlow</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># flows/login.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">appId</span><span class="p">:</span><span class="w"> </span><span class="l">com.yourcompany.app</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">launchApp</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">clearState</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">tapOn</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;login_button&#34;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">inputText</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;user@nextside.tech&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">tapOn</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Sign in&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># flows/checkout.yaml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">appId</span><span class="p">:</span><span class="w"> </span><span class="l">com.yourcompany.app</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">runFlow</span><span class="p">:</span><span class="w"> </span><span class="l">login.yaml         </span><span class="w"> </span><span class="c"># reuses the whole login</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">tapOn</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">id</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;product_42&#34;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">scrollUntilVisible</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">element</span><span class="p">:</span><span class="w"> </span>{<span class="w"> </span><span class="nt">text</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Checkout&#34;</span><span class="w"> </span>}<span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">tapOn</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Checkout&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">assertVisible</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Order confirmed&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Change the login rule in one place, it holds across the twenty tests that call it. Notice the <code>scrollUntilVisible</code> and the <code>clearState: true</code>: Maestro has a command to scroll until it finds, clear state, change permission, set location. And it <strong>waits for the element to show up on its own</strong>, without you scattering <code>sleep</code> across the test. Sleep is a smell of a badly written test, here you don&rsquo;t need it.</p>
<p><strong>Same file. iOS and Android. Without touching the app&rsquo;s code.</strong></p>
<h2>From zero to the first test<span class="hx:absolute hx:-mt-20" id="from-zero-to-the-first-test"></span>
    <a href="#from-zero-to-the-first-test" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The real &ldquo;how to use it&rdquo; starts before Claude. You need three things on the machine:</p>
<ul>
<li><strong>Java 17 or newer.</strong> Maestro&rsquo;s engine runs on the JVM. Check with <code>java -version</code>.</li>
<li><strong>Xcode and the Command Line Tools.</strong> That&rsquo;s what unlocks the iOS simulator.</li>
<li><strong>Android platform-tools with <code>$ANDROID_HOME</code> set and an emulator running.</strong> Check with <code>adb devices</code>.</li>
</ul>
<p>With that in place, install Maestro in one command:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL <span class="s2">&#34;https://get.maestro.mobile.dev&#34;</span> <span class="p">|</span> bash
</span></span><span class="line"><span class="cl"><span class="c1"># or, on macOS, via Homebrew:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># brew install mobile-dev-inc/tap/maestro</span>
</span></span><span class="line"><span class="cl">maestro --help   <span class="c1"># confirms it&#39;s alive</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Boot a simulator (or emulator), install your app on it, and run the flow:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">maestro <span class="nb">test</span> flows/checkout.yaml     <span class="c1"># one flow</span>
</span></span><span class="line"><span class="cl">maestro <span class="nb">test</span> flows/                  <span class="c1"># the whole folder</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That alone already gives you E2E tests running locally, with no AI at all. AI comes in so you stop writing these YAMLs by hand.</p>
<h2>The loop in practice: Claude writes the test looking at the app<span class="hx:absolute hx:-mt-20" id="the-loop-in-practice-claude-writes-the-test-looking-at-the-app"></span>
    <a href="#the-loop-in-practice-claude-writes-the-test-looking-at-the-app" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Connect Maestro to Claude Code in one command:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">claude mcp add maestro -- maestro mcp</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That hands Claude a handful of tools: <code>inspect_screen</code> (grabs the screen&rsquo;s view hierarchy as compact JSON), <code>run</code> (executes a flow), and <code>open_maestro_viewer</code> (embeds the simulator in a window where you watch each command run in real time).</p>
<p>The loop this unlocks changes the game:</p>
<ol>
<li><strong>Claude inspects</strong> the screen live. It reads the tree, it doesn&rsquo;t guess.</li>
<li><strong>Claude writes</strong> the flow YAML, <a href="https://maestro.dev/blog/maestro-mcp-an-introduction"target="_blank" rel="noopener">without you hunting for element IDs by hand</a>.</li>
<li><strong>Claude runs</strong> it on the simulator.</li>
<li><strong>Claude diagnoses</strong> what failed by looking at the hierarchy, and fixes the test itself.</li>
</ol>
<p>Step 4 is the one that saves the most sanity. When a <code>tapOn: &quot;Sign in&quot;</code> breaks because the button became &ldquo;Log in&rdquo; in a refactor, the manual flow is: test fails in CI, someone opens it, finds out, fixes the selector, pushes again. With the loop, Claude rereads the hierarchy, sees the label changed, switches to the stable <code>id</code>, and shows you the diff. You approve it or not. <a href="https://maestro.dev/blog/maestro-mcp-an-introduction"target="_blank" rel="noopener">Maestro calls this self-healing</a>. It&rsquo;s test maintenance, the most tedious part of QA, coming off your back.</p>
<p>In React Native, what makes this loop reliable is the <code>testID</code>. The one you already put on your components becomes Maestro&rsquo;s <code>id</code> directly:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">Button</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;Sign in&#34;</span> <span class="na">testID</span><span class="o">=</span><span class="s">&#34;login_button&#34;</span> <span class="na">onPress</span><span class="o">=</span><span class="p">{</span><span class="nx">onLogin</span><span class="p">}</span> <span class="p">/&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Prefer <code>testID</code> over text, always. Text changes with translation and with copy revisions. The <code>testID</code> only changes if you change it on purpose. And when you don&rsquo;t know which selector exists on a screen, <code>maestro studio</code> opens a visual inspector in the browser: you click the element, it shows the available selectors and generates the YAML for the step. That&rsquo;s how you teach Claude to aim at the right places in your app.</p>
<h3>MCP or Skill+CLI: which to use?<span class="hx:absolute hx:-mt-20" id="mcp-or-skillcli-which-to-use"></span>
    <a href="#mcp-or-skillcli-which-to-use" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Both work. The choice is about context. The <strong>MCP</strong> is plug-and-play: one command and Claude has the tools. The price is that every MCP loads the tools&rsquo; schema into the model&rsquo;s context, and that eats tokens every session.</p>
<p>The alternative is a <strong>Skill</strong> that teaches Claude to run <code>maestro test flow.yaml</code> straight in the terminal. Leaner, because you don&rsquo;t pay the server overhead. The <a href="https://news.ycombinator.com/item?id=45642911"target="_blank" rel="noopener">community itself is migrating from MCP to Skill+CLI for this reason</a>. My rule: I start on the MCP to explore and prototype fast. Once the flow becomes routine, I wrap it in a Skill with the CLI and drop the server.</p>
<aside class="ns-cta ns-cta-mid" data-servico="discovery">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Want to put Claude to test your app but not sure it fits your stack? We validate the setup with you in a Discovery.</h3>

  <p class="ns-cta-meta">Technical validation · 2-3 weeks · Outcome: roadmap &#43; prototype.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=discovery&amp;utm_content=maestro-claude-code-testar-app-no-simulador-mid#discovery" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>The iOS toll (the part nobody posts)<span class="hx:absolute hx:-mt-20" id="the-ios-toll-the-part-nobody-posts"></span>
    <a href="#the-ios-toll-the-part-nobody-posts" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the honest part, because selling this as magic is a disservice.</p>
<p>First: AI-generated tests get it right <a href="https://medium.com/coding-nexus/someone-built-a-tool-that-lets-claude-code-autonomously-test-your-entire-ios-app-5256d0a49703"target="_blank" rel="noopener">70 to 80% on the first pass</a>. Claude picks the wrong selector, forgets a wait. The flow that works is letting the AI generate v1, running it once to validate, and handing maintenance back to it. It&rsquo;s not &ldquo;send it and forget it&rdquo;.</p>
<p>Second, and heavy for anyone in mobile: <strong>iOS charges a toll.</strong> A dev documented setting up the same QA on both platforms. <a href="https://christophermeiklejohn.com/ai/zabriskie/development/android/ios/2026/03/22/teaching-claude-to-qa-a-mobile-app.html"target="_blank" rel="noopener">Android took 90 minutes, iOS went past six hours</a>. His line sums up the whole decade of mobile automation. &ldquo;Android hands you a WebSocket and says: here&rsquo;s the app, do whatever you want. iOS hands you a locked door and a note asking you to use Xcode.&rdquo;</p>
<p>The good news is that Maestro abstracts away a good chunk of that toll, it&rsquo;s the same <code>tapOn</code> on both. But two stones you&rsquo;ll still step on in React Native:</p>
<ul>
<li><strong>Nested component on iOS.</strong> iOS &ldquo;swallows&rdquo; the tap when you have a <code>Text</code> inside a <code>TouchableOpacity</code> inside another tappable container. The fix is <code>accessible={false}</code> on the outer container and <code>accessible={true}</code> on the inner element. It&rsquo;s annoying, but it&rsquo;s once per component.</li>
<li><strong>Expo Go doesn&rsquo;t accept <code>launchApp</code>.</strong> Running through Expo Go, the app lives inside the Expo container, and <code>launchApp</code> with your <code>appId</code> won&rsquo;t catch. You have to use <code>openLink</code> with the dev URL, or do a real development build (EAS). On bare React Native, <code>launchApp</code> works normally.</li>
</ul>
<blockquote>
  <p>&ldquo;You&rsquo;re going to let a bot write and run the app&rsquo;s tests? This is going to go wrong.&rdquo;</p>

</blockquote>
<p>It&rsquo;ll go wrong if you treat the generated test as truth and walk away. It won&rsquo;t if you treat it as a draft the senior reviews, just like you already do (or should do) with code the AI writes. Maestro still hands you the versioned YAML: you can read it in the PR, disagree, fix it. The test is still yours. Claude just stopped making you type it from scratch.</p>
<h2>From a loose test to a routine<span class="hx:absolute hx:-mt-20" id="from-a-loose-test-to-a-routine"></span>
    <a href="#from-a-loose-test-to-a-routine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A test you run by hand when you remember isn&rsquo;t a safety net. It&rsquo;s theater. The real gain shows up when the flow becomes an automatic routine. Since Maestro is just a command-line binary, it goes anywhere that runs a shell:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">maestro <span class="nb">test</span> flows/    <span class="c1"># runs the whole suite; exits with an error code if it breaks</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That <code>maestro test flows/</code> is the same line you run locally, in GitHub Actions on every PR, or in a nightly cron. That dev from the real case <a href="https://christophermeiklejohn.com/ai/zabriskie/development/android/ios/2026/03/22/teaching-claude-to-qa-a-mobile-app.html"target="_blank" rel="noopener">left the suite running as a scheduled task every morning at 8:47</a>: it boots both simulators, sweeps the screens, analyzes, and files a report on whatever looks broken. The dev wakes up with QA already done.</p>
<p>The cycle closes here. Claude writes the flow looking at the app, the flow becomes a versioned file, the file runs in CI. The AI builds the net, the machine pulls it every night.</p>
<h2>The AI writes the code and the test. You still decide what &ldquo;works&rdquo; means.<span class="hx:absolute hx:-mt-20" id="the-ai-writes-the-code-and-the-test-you-still-decide-what-works-means"></span>
    <a href="#the-ai-writes-the-code-and-the-test-you-still-decide-what-works-means" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>We <a href="/en/posts/2026/05/25/code-review-novo-gargalo-coderabbit/">already talked here about the AI reviewing code but not testing software</a>. Still true, with a new asterisk: now it TESTS, in the simulator, navigating the app like a user would. What it doesn&rsquo;t do is decide what counts as &ldquo;worked&rdquo;.</p>
<p>That judgment is yours. The acceptance criteria are yours. Maestro and Claude take the tedious part off your hands: booting the simulator, hunting for the button&rsquo;s ID, typing the flow, running on both systems, fixing the selector that changed. They give back the time for the one thing the machine doesn&rsquo;t do: looking at the app and deciding if it&rsquo;s good.</p>
<p>A good tool doesn&rsquo;t replace judgment. It just removes the excuse of not having tested.</p>
]]></content:encoded></item><item><title>Code review became the bottleneck. CodeRabbit won't save you alone</title><link>https://blog.nextside.tech/en/posts/2026/05/25/code-review-novo-gargalo-coderabbit/</link><pubDate>Mon, 25 May 2026 09:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/05/25/code-review-novo-gargalo-coderabbit/</guid><dc:creator>Pablo Winter</dc:creator><category>code-review</category><category>coderabbit</category><category>ai-tooling</category><category>claude-code</category><category>devops</category><category>produtividade-dev</category><description>A team went from 2 weeks of PR backlog to zero human review on staging. How CodeRabbit works, where it breaks, and why CLAUDE.md is the single source.</description><content:encoded><![CDATA[<h2>TL;DR<span class="hx:absolute hx:-mt-20" id="tldr"></span>
    <a href="#tldr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>AI sped up dev. The bottleneck moved to review. I saw a consulting team with <strong>2 weeks of PR backlog</strong> waiting on the tech lead, and the team thinking the fix was hiring another senior. It isn&rsquo;t. Dev cadence changed, review cadence didn&rsquo;t. CodeRabbit can clear that queue and leave the PR pipeline to <code>develop</code> 100% autonomous after about a month of calibration. It works. But there&rsquo;s a catch: the team starts trusting the pipeline so much they drop the reflex to test locally. And then the deploy breaks on staging because of a bug nobody saw running.</p>
<p>This post is about both sides.</p>
<h2>AI didn&rsquo;t eliminate the bottleneck. It pushed it to the tech lead.<span class="hx:absolute hx:-mt-20" id="ai-didnt-eliminate-the-bottleneck-it-pushed-it-to-the-tech-lead"></span>
    <a href="#ai-didnt-eliminate-the-bottleneck-it-pushed-it-to-the-tech-lead" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Look at the number: code co-authored with AI generates <a href="https://www.businesswire.com/news/home/20251217666881/en/CodeRabbits-State-of-AI-vs-Human-Code-Generation-Report-Finds-That-AI-Written-Code-Produces-1.7x-More-Issues-Than-Human-Code"target="_blank" rel="noopener"><strong>1.7x more issues per PR</strong></a> than 100% human code. Source is CodeRabbit&rsquo;s own State of AI Code Generation Report, analyzing 470 PRs from open source projects in December 2025. The finding is consistent with what any tech lead who adopted Cursor or Claude Code on the team is seeing in practice.</p>
<p>It tracks: the dev produces more code, faster, and not always with the same context load they had when writing it all by hand. More code + less context = more stuff to review and less automatic confidence that the author knows what they&rsquo;re doing.</p>
<p>Look at the effect on the team:</p>
<p>The tech lead becomes a funnel. I worked with a consulting team where the PR review backlog hit <strong>2 weeks</strong>. The senior in charge was waking up at 6am to review before standup, staying after hours to review before bed, and the queue still grew. The team thought it was understaffing.</p>
<p>It wasn&rsquo;t. <dfn>Code review</dfn> (the step where another human validates the PR before merge) became the new bottleneck in the delivery pipeline. The individual dev got faster. The collective process didn&rsquo;t.</p>
<p><strong>The bottleneck just keeps moving.</strong></p>
<h2>The month the tech lead trained the bot<span class="hx:absolute hx:-mt-20" id="the-month-the-tech-lead-trained-the-bot"></span>
    <a href="#the-month-the-tech-lead-trained-the-bot" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The move was rolling out <dfn>CodeRabbit</dfn> (an AI code review bot that comments line by line on every PR) with the tech lead piloting it for a full month. It wasn&rsquo;t &ldquo;install it and let everyone loose&rdquo;. It was:</p>
<ol>
<li>CodeRabbit comments on the PR</li>
<li>Tech lead reviews on top: confirms what&rsquo;s right, pushes back on what&rsquo;s wrong</li>
<li>When they push back, they go into <code>.coderabbit.yaml</code> and add a rule for next time</li>
<li>When CodeRabbit misses something important, they go into <code>.coderabbit.yaml</code> and add a <dfn>path instruction</dfn>: a review instruction written in natural language paired with a file glob</li>
<li>Repeat</li>
</ol>
<p>Within two weeks the number of rules the tech lead added per day dropped. Within three weeks CodeRabbit was getting more right than wrong. By the end of the first month the curve flattened: a new rule became the exception.</p>
<p>The unlock was wiring up two things CodeRabbit doesn&rsquo;t catch on its own:</p>
<ul>
<li><strong>Notion via MCP</strong>: every <a href="/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/">ADR and architectural decision the team makes lives in Notion</a>. Wire CodeRabbit into Notion via MCP and it reads the context before reviewing. No more &ldquo;this should use pattern X&rdquo; comments when the ADR says use Y.</li>
<li><strong>JIRA in the PR description</strong>: every PR is required to cite the JIRA issue ID. CodeRabbit pulls the US and cross-references it against the diff.</li>
</ul>
<p>The second one changes the game more than it sounds.</p>
<h3>Why does requiring a JIRA ID in the PR description change the game?<span class="hx:absolute hx:-mt-20" id="why-does-requiring-a-jira-id-in-the-pr-description-change-the-game"></span>
    <a href="#why-does-requiring-a-jira-id-in-the-pr-description-change-the-game" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Because CodeRabbit stops reviewing just code and starts reviewing <strong>whether the PR delivers the story</strong>. Are the acceptance criteria in the US? Then the bot checks each AC against the diff and flags: &ldquo;AC #3 mentions duplicate email validation, but I don&rsquo;t see that check in the PR&rdquo;. This isn&rsquo;t opinion: it&rsquo;s a checklist.</p>
<p>Except there&rsquo;s a prerequisite few teams want to face: the US has to be properly sized with decent AC. I see team after team failing exactly there. PO ships a giant, vague US, with AC like &ldquo;validate form&rdquo;. CodeRabbit reads that and can&rsquo;t do anything with it. Then people decide the tool is useless. It isn&rsquo;t. The refinement is.</p>
<p><strong>Without proper AC, CodeRabbit is just a ruler with no markings.</strong></p>
<h2>Today, PRs to staging don&rsquo;t go through a human anymore<span class="hx:absolute hx:-mt-20" id="today-prs-to-staging-dont-go-through-a-human-anymore"></span>
    <a href="#today-prs-to-staging-dont-go-through-a-human-anymore" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After that month of calibration, here&rsquo;s what changed in the flow:</p>
<ul>
<li><strong>PR to <code>develop</code> (staging):</strong> after N iterations between dev and CodeRabbit, the bot approves itself. Zero humans. Merge.</li>
<li><strong>PR to <code>master</code> (production):</strong> still goes through a human. Always.</li>
</ul>
<blockquote>
  <p>&ldquo;You let AI approve code on its own. This will go bad.&rdquo;</p>

</blockquote>
<p>That&rsquo;s the comment that shows up every time I tell this story. Usually from someone who&rsquo;s never watched a tech lead burn 8 hours a day on PR review instead of doing architecture. Yes, we do. On staging. Where the worst case is the deploy breaks and we roll back. Not production. Staging.</p>
<p>And the practical difference: the tech lead is back to doing architecture. The team ships more. The dev gets CodeRabbit feedback in minutes instead of days.</p>
<h3>CodeRabbit vs GitHub Copilot Code Review vs Greptile: which one?<span class="hx:absolute hx:-mt-20" id="coderabbit-vs-github-copilot-code-review-vs-greptile-which-one"></span>
    <a href="#coderabbit-vs-github-copilot-code-review-vs-greptile-which-one" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Short answer: depends on what hurts most.</p>
<ul>
<li><strong>CodeRabbit</strong>: line-by-line, persistent learnings, strong integrations (MCP, JIRA, Notion). Trade-off: ~3min per review and $24/dev/month. Wins on depth and on fitting into the workflow.</li>
<li><strong>GitHub Copilot Code Review</strong>: $10/user/month, zero friction because the team already pays for Copilot. Shallower review, no persistent learnings, no native Jira/Notion integration. Good place to start.</li>
<li><strong>Greptile</strong>: <a href="https://wetheflywheel.com/en/guides/best-ai-code-review-tools-2026/"target="_blank" rel="noopener">their own bench says 82% catch rate vs CodeRabbit&rsquo;s 44%</a>, but generates <strong>11 false-positives</strong> against CodeRabbit&rsquo;s 2. Pick your pain: miss a bug or drown the dev in noise.</li>
</ul>
<p>Small team already paying for Copilot: start with Copilot Code Review and see how far it gets you. Tech lead drowning in review backlog: CodeRabbit pays for itself in the first month.</p>
<p>And honesty: an independent audit of 28 PRs reviewed by CodeRabbit found 15% of comments were &ldquo;useless/noise&rdquo; and 21% were nitpicking. <strong>It&rsquo;s not a silver bullet.</strong> You have to tune it. You have to teach it. You have to use the learnings. Whoever installs and walks away will complain it&rsquo;s bad. Because for that usage, it is.</p>
<aside class="ns-cta ns-cta-mid" data-servico="auditoria">
  <p class="eyebrow">● Nextside</p>

  <h3 class="ns-cta-title">Seeing this pattern in your team? We audit your pipeline and map where AI speeds up delivery and where it&#39;s quietly creating debt.</h3>

  <p class="ns-cta-meta">Independent audit · 1-2 weeks · No commercial strings attached.</p>

  <div class="ns-cta-actions">
    <a href="https://www.nextside.tech/?utm_source=blog&amp;utm_medium=cta&amp;utm_campaign=auditoria&amp;utm_content=code-review-novo-gargalo-coderabbit-mid#auditoria" class="btn btn-primary">Talk to Nextside →</a></div>
</aside>

<h2>One file, three brains: CLAUDE.md as single source<span class="hx:absolute hx:-mt-20" id="one-file-three-brains-claudemd-as-single-source"></span>
    <a href="#one-file-three-brains-claudemd-as-single-source" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the trick few people have caught onto yet.</p>
<p>CodeRabbit auto-detects <code>CLAUDE.md</code>, <code>AGENTS.md</code>, <code>.cursor/rules/*.mdc</code>, and <code>.github/copilot-instructions.md</code> as knowledge base. The rule you write once in <code>CLAUDE.md</code> applies to:</p>
<ol>
<li><strong>Claude Code</strong> while coding: follows the rule when writing</li>
<li><strong>CodeRabbit</strong> while reviewing: checks the diff against the same rule</li>
<li><strong>Cursor</strong> on autocomplete: respects the convention</li>
</ol>
<p>One file, three brains reading. You stop maintaining the same rule duplicated across three systems. The PR that goes up is already almost approved because it was written under the same rules being checked at review.</p>
<p>And there&rsquo;s another piece that closes the loop: CodeRabbit&rsquo;s CLI (<code>coderabbit --prompt-only</code>) spits the review feedback in a format consumable by an agent. You can build a slash command in Claude Code that resolves the comments in a loop and keeps pushing back until the bot approves.</p>
<p>Save this as <code>.claude/commands/coderabbit-loop.md</code> in the repo and use <code>/coderabbit-loop</code> in Claude Code:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">Resolve CodeRabbit comments on the current PR until approval.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">BEFORE accepting any suggestion, invoke the <span class="sb">`receiving-code-review`</span> skill
</span></span><span class="line"><span class="cl">from the superpowers plugin. Without it, you become the bot&#39;s doormat.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Flow:
</span></span><span class="line"><span class="cl"><span class="k">1.</span> Run <span class="sb">`coderabbit --prompt-only`</span> and capture the comments
</span></span><span class="line"><span class="cl"><span class="k">2.</span> For each comment:
</span></span><span class="line"><span class="cl">   <span class="k">-</span> If it makes technical sense: apply the change and commit with a
</span></span><span class="line"><span class="cl">     message tied to the comment (&#34;addresses CodeRabbit: &lt;summary&gt;&#34;)
</span></span><span class="line"><span class="cl">   <span class="k">-</span> If it does NOT make sense: reply on the PR with technical
</span></span><span class="line"><span class="cl">     justification and mark as wontfix via <span class="sb">`@coderabbitai resolve`</span>
</span></span><span class="line"><span class="cl"><span class="k">3.</span> <span class="sb">`git push`</span> on the branch
</span></span><span class="line"><span class="cl"><span class="k">4.</span> Wait for re-review (poll the PR via <span class="sb">`gh pr view`</span> every 60s, max 5min)
</span></span><span class="line"><span class="cl"><span class="k">5.</span> If there are still new unresolved comments, go back to step 2
</span></span><span class="line"><span class="cl"><span class="k">6.</span> Stop when CodeRabbit approves OR after 5 iterations
</span></span><span class="line"><span class="cl">   (at that point, call the human: there&#39;s likely real disagreement)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Use <span class="sb">`gh pr view --comments`</span> for status. Use <span class="sb">`gh pr comment`</span> to reply.
</span></span><span class="line"><span class="cl">Never <span class="sb">`--force-push`</span>: always incremental commits.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The <code>receiving-code-review</code> line isn&rsquo;t a detail. It&rsquo;s the point.</p>
<p>Without it, Claude Code accepts any CodeRabbit suggestion in &ldquo;performative agreement&rdquo; mode: agrees to look polite, refactors code that was fine, and the PR grows with changes that shouldn&rsquo;t exist. The <a href="/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/">receiving-code-review skill from the superpowers plugin</a> forces technical rigor: validate the suggestion before applying, push back when you disagree, demand evidence. It&rsquo;s the filter that keeps the dev in charge, even when the dev is an AI.</p>
<h2>Where the pipeline breaks: the dev stopped testing locally<span class="hx:absolute hx:-mt-20" id="where-the-pipeline-breaks-the-dev-stopped-testing-locally"></span>
    <a href="#where-the-pipeline-breaks-the-dev-stopped-testing-locally" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the part nobody posts on LinkedIn.</p>
<p>A team with the full stack (Claude Code + Superpowers + CodeRabbit) starts trusting the pipeline too much. The dev thinks if it passed CodeRabbit, it&rsquo;s fine. The tech lead thinks if CodeRabbit approved, it was reviewed. The QA thinks if it reached staging, it was tested.</p>
<p>Result: NOBODY runs anything locally before pushing. I&rsquo;ve seen this happen in three different teams. Symptom always the same: PR merged to <code>develop</code>, deploy to staging, and then they discover the feature doesn&rsquo;t work because nobody opened the browser to confirm the button actually clicks.</p>
<p>AI reviews code. AI doesn&rsquo;t test software.</p>
<p>The fix I adopted as non-negotiable: <strong>mandatory workflow with an E2E validation command before the push</strong>. In my case it&rsquo;s a <code>/validar-e2e</code> that spins up the project&rsquo;s Docker stack, fires 3 agents in parallel (QA matrix, backend via <code>curl</code>/SQL, frontend via <a href="/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/">MCP Playwright in Claude Code</a>) and only releases the push when every scenario passes. Re-runs everything after any fix, never partial validation.</p>
<p>Here&rsquo;s the skeleton to adapt to your project. Save as <code>.claude/commands/validar-e2e.md</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">Orchestrated E2E validation before requesting human review.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Spin up the local stack, generate the scenario matrix, and ONLY THEN
</span></span><span class="line"><span class="cl">fire backend + frontend in parallel with the matrix as input. DO NOT
</span></span><span class="line"><span class="cl">stop on partial. After any fix, RE-RUN EVERYTHING, not just what changed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">QUALITY RULE: if an agent delivers a shallow result, with no concrete
</span></span><span class="line"><span class="cl">evidence (no log/SQL/screenshot), with scenarios skipped without
</span></span><span class="line"><span class="cl">justification, or clearly incomplete: RELAUNCH the agent with a more
</span></span><span class="line"><span class="cl">explicit briefing about what was missing. Accepting bad output
</span></span><span class="line"><span class="cl">contaminates the merge decision.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Phase 1: Bring up / validate the stack
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> <span class="sb">`docker compose -f docker-compose.e2e.yml up -d`</span>
</span></span><span class="line"><span class="cl"><span class="k">-</span> Wait for health checks to return 200 (5min timeout)
</span></span><span class="line"><span class="cl"><span class="k">-</span> If any service failed, report the container log and stop
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Phase 2: Agent A: QA matrix (BLOCKING, runs alone)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Launch ONE agent and WAIT for the full output before moving on.
</span></span><span class="line"><span class="cl">Agents B and C depend on this matrix: without it, they test blind.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Agent A briefing:
</span></span><span class="line"><span class="cl">  Produce a matrix with ≥20 scenarios based on the commits on this
</span></span><span class="line"><span class="cl">  branch vs develop. Categories: happy path, regression, edge cases
</span></span><span class="line"><span class="cl">  (null/empty/limits), error (DB unavailable, auth failure), migration
</span></span><span class="line"><span class="cl">  (idempotence). For each: ID, description, severity (P0/P1/P2),
</span></span><span class="line"><span class="cl">  steps, expected result. Save to
</span></span><span class="line"><span class="cl">  <span class="sb">`docs/specs/&lt;feature&gt;-qa-matrix.md`</span>. Report count per category +
</span></span><span class="line"><span class="cl">  the 3 priority P0 scenarios + the critical UI flows to be covered
</span></span><span class="line"><span class="cl">  by frontend.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Phase 3: Agents B and C in parallel (fed by the matrix)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">RULE: ONE message with 2 simultaneous Agent tool calls. Paste the 3
</span></span><span class="line"><span class="cl">P0 scenarios (Agent A output) into B&#39;s briefing and the critical UI
</span></span><span class="line"><span class="cl">flows into C&#39;s briefing. Limit ≤80 tool calls per agent (above that
</span></span><span class="line"><span class="cl">you get socket errors: relaunch with smaller scope if it crashes).
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">### Agent B: Backend E2E
</span></span></span><span class="line"><span class="cl">Run the P0 scenarios below via curl against the local stack. Validate
</span></span><span class="line"><span class="cl">the DB after each call (psql/mongosh/redis-cli depending on stack).
</span></span><span class="line"><span class="cl">Also run unit tests for the changed branches. Report PASS/FAIL with
</span></span><span class="line"><span class="cl">evidence (1-2 lines of log/SQL) in ≤600 words. Don&#39;t rebuild Docker,
</span></span><span class="line"><span class="cl">don&#39;t touch production code.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  QA P0 scenarios: &lt;paste Agent A output here&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">### Agent C: Frontend MCP Playwright
</span></span></span><span class="line"><span class="cl">Run the critical UI flows below in the browser via MCP Playwright.
</span></span><span class="line"><span class="cl">For each: screenshot of the state, console inspection (JS errors),
</span></span><span class="line"><span class="cl">network request validation. Report regressions in ≤700 words with
</span></span><span class="line"><span class="cl">screenshots.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  QA critical flows: &lt;paste Agent A output here&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Phase 4: Consolidate
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> B and C both PASS with evidence → release <span class="sb">`git push`</span> and open the PR
</span></span><span class="line"><span class="cl"><span class="k">-</span> Any FAIL → fix the code and GO BACK to Phase 3 (re-run B and C with
</span></span><span class="line"><span class="cl">  the same matrix; only re-run Agent A if the fix changed scenarios)
</span></span><span class="line"><span class="cl"><span class="k">-</span> BLOCKED → diagnose infra/context before trying again
</span></span><span class="line"><span class="cl"><span class="k">-</span> Socket error on an agent → relaunch with reduced scope (≤50 tool calls)
</span></span><span class="line"><span class="cl"><span class="k">-</span> Shallow result / no evidence → RELAUNCH the agent with a reinforced
</span></span><span class="line"><span class="cl">  briefing demanding exactly what was missing (logs, SQL queries,
</span></span><span class="line"><span class="cl">  screenshots, specific assertions). Don&#39;t accept PASS without proof.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And it&rsquo;s not just bureaucratic friction: it&rsquo;s how you keep the reflex. Whoever tests locally catches the bug in 30 seconds. Whoever waits for staging catches it in 30 minutes. Whoever waits for production pays much more.</p>
<h2>The pipeline is yours. The AI is just the engine.<span class="hx:absolute hx:-mt-20" id="the-pipeline-is-yours-the-ai-is-just-the-engine"></span>
    <a href="#the-pipeline-is-yours-the-ai-is-just-the-engine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>CodeRabbit + Claude Code + Superpowers is a stack. A good stack. Removes a real bottleneck. Gives tech lead time back for architecture, zeroes out the review backlog, and PRs come out rounder because the rule set is single.</p>
<p>But it&rsquo;s a <strong>stack</strong>. Not a process.</p>
<p>Process is the discipline of well-scoped US, well-written AC, mandatory local testing, and the humility to accept that AI speeds up what&rsquo;s right and speeds up what&rsquo;s wrong right alongside it.</p>
<p>Anyone who confuses stack with process is going to find out the hard way. Probably on a Friday deploy.</p>
]]></content:encoded></item><item><title>MCP Playwright: real-quality local validation before the PR</title><link>https://blog.nextside.tech/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/</link><pubDate>Sat, 16 May 2026 12:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/</guid><dc:creator>Pablo Winter</dc:creator><category>mcp</category><category>playwright</category><category>claude-code</category><category>quality</category><category>testing</category><description>Before asking for a human review, Claude with MCP Playwright has already navigated your app, taken screenshots, and flagged regressions. Local, on your dev, in seconds.</description><content:encoded><![CDATA[<p>Recurring scenario: you finish a frontend feature, run <code>git diff</code>, everything looks fine, you commit. Five minutes later someone opens a PR and says &ldquo;the button disappeared on mobile.&rdquo; Welcome to the visual regression hole. Question: can you catch this before the PR? Dry answer: yes. And the cheapest path today runs through MCP + Playwright.</p>
<p><strong>TL;DR:</strong> MCP Playwright is not a new testing framework. It doesn&rsquo;t replace CI/CD. It doesn&rsquo;t replace the E2E suite your engineer wrote. <strong>It&rsquo;s your way of asking Claude to test locally for you</strong>, and hand you screenshots as proof.</p>
<p>The dev flow has always been: code, write unit tests, run the app locally and click through it manually, open the PR. The &ldquo;run the app and click through it&rdquo; step was the one that got skipped most. &ldquo;Unit passed, ship it to CI.&rdquo; Then a bug hits production that CI didn&rsquo;t catch because CI doesn&rsquo;t cover every possible path. With MCP Playwright, that step is no longer yours. It becomes the AI navigating your app, validating the flow, taking a screenshot of each relevant state. You gain time. The PR gains evidence. CI keeps doing its job.</p>
<h2>What MCP is, without the jargon<span class="hx:absolute hx:-mt-20" id="what-mcp-is-without-the-jargon"></span>
    <a href="#what-mcp-is-without-the-jargon" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><dfn>MCP: Model Context Protocol</dfn> is an open protocol created by Anthropic to connect LLMs to external tools. Think of it as USB for AI: one standard, plug in, and any compatible LLM talks to any &ldquo;MCP server&rdquo; on the market.</p>
<p>Before MCP, integrating AI with external tools was artisanal. Each client (Claude Code, Cursor, Continue) had its own way of invoking tools. Each tool needed a specific adapter. Chaos.</p>
<p>MCP standardizes that. There are three pieces:</p>
<ul>
<li><strong>Client</strong>: the app where the AI runs (Claude Code, Claude Desktop, etc.)</li>
<li><strong>MCP server</strong>: a separate process that exposes tools via protocol. Can run locally, remote, in containers, anywhere.</li>
<li><strong>Tools/Resources</strong>: what the server exposes. &ldquo;Navigate to URL X&rdquo;, &ldquo;read this file&rdquo;, &ldquo;execute this query.&rdquo;</li>
</ul>
<p>The client asks the server what it offers. The server responds with a list of tools. The AI picks a tool, sends parameters, the server executes, responds. Simple. Standardized. Universal.</p>
<p>There&rsquo;s an MCP server for practically everything today: GitHub, Linear, Notion, Postgres, browser via Playwright, filesystem, Slack. You plug in what you need. The AI then operates those tools as if they were native extensions of the client itself.</p>
<h2>Playwright as an MCP server: why it matters<span class="hx:absolute hx:-mt-20" id="playwright-as-an-mcp-server-why-it-matters"></span>
    <a href="#playwright-as-an-mcp-server-why-it-matters" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Playwright is Microsoft&rsquo;s browser automation stack. Headless or not. Cross-browser (Chromium, Firefox, WebKit). Consistent API, performant, excellent DX. What Selenium always wanted to be and never managed.</p>
<p>When someone packages Playwright as an MCP server, the following happens: Claude gets <strong>eyes in the browser</strong>. Literally. It can:</p>
<ul>
<li>Open a page at a URL</li>
<li>Take screenshots</li>
<li>Read the DOM via accessibility snapshot</li>
<li>Click an element</li>
<li>Fill a form</li>
<li>Wait for an element to appear</li>
<li>Check the console for errors</li>
<li>Inspect network requests</li>
<li>Execute arbitrary JavaScript in the page context</li>
</ul>
<p>All of this through commands the LLM picks based on context. You don&rsquo;t need to write a test spec. You describe in natural language (&ldquo;validate that the post card opens correctly on mobile at 375px&rdquo;) and Claude assembles the sequence: navigate, resize viewport, click, wait, screenshot, verify.</p>
<p>For those who haven&rsquo;t used it: it feels like magic. For those who have: it becomes a habit in 3 days.</p>
<blockquote>
  <p>&ldquo;But isn&rsquo;t this just another Playwright wrapper?&rdquo; No. A wrapper requires you to write code. MCP Playwright lets the AI choose the right step based on the task context. The difference isn&rsquo;t technical: it&rsquo;s abstraction. You move from &ldquo;how&rdquo; and stay at &ldquo;what.&rdquo;</p>

</blockquote>
<h2>Real flow: validating post UX before committing<span class="hx:absolute hx:-mt-20" id="real-flow-validating-post-ux-before-committing"></span>
    <a href="#real-flow-validating-post-ux-before-committing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>To illustrate, here&rsquo;s the flow the Nextside team uses on this blog. Every time a new post comes out of the <a href="/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/">revisor agent encoded via Claude Code superpowers</a> ready to commit, a dedicated <strong>UX review</strong> agent launches using MCP Playwright. Sequence:</p>
<ul>
<li><strong>Start Hugo locally</strong>: <code>hugo server -D --port 1313</code></li>
<li><strong>Launch the agent</strong>: describe the task: &ldquo;validate post X in light/dark and at mobile 375px/desktop 1280px&rdquo;</li>
<li><strong>Claude navigates via MCP Playwright</strong>: opens <code>localhost:1313/posts/.../{slug}/</code>, waits for load, takes screenshot</li>
<li><strong>Inspect console</strong>: checks for JS errors, font warnings, or broken image notices</li>
<li><strong>Toggle dark mode</strong>: clicks the theme toggle, waits for transition, takes screenshot</li>
<li><strong>Resize to mobile</strong>: resizes viewport to 375px, screenshot</li>
<li><strong>Reports</strong>: markdown with embedded screenshots + checklist (✓ contrast, ✓ typography, ⚠ long code overflows on mobile, ✓ ember glow only in CTA)</li>
</ul>
<p>Total time: 30 to 90 seconds. Cost: zero extra infra. Output: a report I, as a human, read in 2 minutes and decide whether to commit or fix.</p>
<p>Compare with the old flow:</p>
<ul>
<li>Open manually in Chrome: 15s</li>
<li>Open DevTools, simulate mobile: 20s</li>
<li>Check dark mode: 10s</li>
<li>Check console: 10s</li>
<li>Forget to test at least one combination at least once a week: guaranteed</li>
</ul>
<p>And here&rsquo;s the real gain. It&rsquo;s not speed: it&rsquo;s <strong>consistency</strong>. Claude doesn&rsquo;t forget to test dark mode. Doesn&rsquo;t skip mobile in a rush. Doesn&rsquo;t say &ldquo;oh, I&rsquo;ll check the console later.&rdquo; Every time it runs, it runs everything.</p>
<p><strong>Automated discipline beats tired human discipline.</strong></p>
<h2>Before vs after: what changes in the dev flow<span class="hx:absolute hx:-mt-20" id="before-vs-after-what-changes-in-the-dev-flow"></span>
    <a href="#before-vs-after-what-changes-in-the-dev-flow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Look at the traditional flow. What we&rsquo;ve always done:</p>
<ol>
<li>Code the feature</li>
<li>Write unit tests</li>
<li><strong>Run the app locally and click through it</strong>: navigate, click, validate visually</li>
<li>Open the PR</li>
<li>CI runs full Playwright + unit suite</li>
<li>Human reviewer looks at the code</li>
</ol>
<p>Step 3 is where time evaporates. And it&rsquo;s the most skipped: &ldquo;unit passed, ship to CI.&rdquo; Then a bug hits production that CI didn&rsquo;t catch because CI doesn&rsquo;t cover every possible path.</p>
<p>With MCP Playwright, step 3 becomes:</p>
<blockquote>
  <p>3. <strong>Ask Claude to test it:</strong> &ldquo;validate the checkout flow with a coupon on localhost:3000, give me screenshots of each step&rdquo;</p>

</blockquote>
<p>And Claude opens the browser via MCP, navigates, fills in, clicks, verifies, takes a screenshot of each state, reports console errors if any. You get back: &ldquo;it worked. Evidence in <code>/tmp/checkout-*.png</code>.&rdquo; You attach the screenshots in the PR. <strong>The human reviewer opens the PR with visual proof already in hand.</strong> CI keeps running the full suite, that doesn&rsquo;t change. What changes is your manual test step before the PR.</p>
<h3>So this doesn&rsquo;t replace my E2E tests?<span class="hx:absolute hx:-mt-20" id="so-this-doesnt-replace-my-e2e-tests"></span>
    <a href="#so-this-doesnt-replace-my-e2e-tests" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>No. And it shouldn&rsquo;t. Your traditional E2E runs in CI without needing AI, works fine, validates regression deterministically. That&rsquo;s work the engineer writes once and runs a thousand times. MCP Playwright is different: it&rsquo;s your <strong>local exploratory testing</strong>, automated by AI, with visual proof. It&rsquo;s the step you used to do by clicking, now delegated.</p>
<h2>Concrete scenario: PO writes, AI validates<span class="hx:absolute hx:-mt-20" id="concrete-scenario-po-writes-ai-validates"></span>
    <a href="#concrete-scenario-po-writes-ai-validates" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Look at how this turns into a real flow. Thursday morning, the PO writes a Gherkin scenario in Notion:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gherkin" data-lang="gherkin"><span class="line"><span class="cl"><span class="k">Feature:</span><span class="nf"> Checkout with discount coupon
</span></span></span><span class="line"><span class="cl"><span class="nf">  As a customer
</span></span></span><span class="line"><span class="cl"><span class="nf">  I want to apply a coupon at checkout
</span></span></span><span class="line"><span class="cl"><span class="nf">  So I can pay less for the order
</span></span></span><span class="line"><span class="cl"><span class="nf">
</span></span></span><span class="line"><span class="cl"><span class="nf">  </span><span class="k">Scenario:</span><span class="nf"> Valid coupon applies discount
</span></span></span><span class="line"><span class="cl"><span class="k">    Given </span><span class="nf">I am on the checkout page
</span></span></span><span class="line"><span class="cl"><span class="nf">    </span><span class="k">And </span><span class="nf">my cart has </span><span class="s">2</span><span class="nf"> items totaling R$ </span><span class="s">200</span><span class="nf">
</span></span></span><span class="line"><span class="cl"><span class="nf">    </span><span class="k">When </span><span class="nf">I enter the coupon &#34;</span><span class="s">NEXTSIDE10</span><span class="nf">&#34; in the discount field
</span></span></span><span class="line"><span class="cl"><span class="nf">    </span><span class="k">And </span><span class="nf">I click &#34;</span><span class="s">Apply</span><span class="nf">&#34;
</span></span></span><span class="line"><span class="cl"><span class="nf">    </span><span class="k">Then </span><span class="nf">the total should drop to R$ </span><span class="s">180</span><span class="nf">
</span></span></span><span class="line"><span class="cl"><span class="nf">    </span><span class="k">And </span><span class="nf">a message &#34;</span><span class="s">Coupon applied: 10% off</span><span class="nf">&#34; should appear
</span></span></span><span class="line"><span class="cl"><span class="nf">    </span><span class="k">And </span><span class="nf">the &#34;</span><span class="s">Place order</span><span class="nf">&#34; button should remain enabled</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The dev opens the terminal, and instead of running the app and clicking through each step herself to confirm the scenario passes (that manual pre-PR click-through everyone skips), she hands it to the AI:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Validate the Gherkin scenario below against the app running at http://localhost:3000.
Use MCP Playwright. Report each Then with ✅ or ❌ &#43; a screenshot 
when something fails. Don&#39;t fix the code: just audit.

&lt;paste the Gherkin here&gt;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The AI with MCP Playwright:</p>
<ol>
<li>Opens the browser at <code>http://localhost:3000/checkout</code></li>
<li>Confirms it&rsquo;s on the checkout page (<code>networkidle</code> + <code>&lt;h1&gt;Checkout&lt;/h1&gt;</code> visible)</li>
<li>Reads the DOM and confirms 2 items in the cart totaling R$ 200</li>
<li>Fills the &ldquo;coupon&rdquo; field with <code>NEXTSIDE10</code></li>
<li>Clicks the &ldquo;Apply&rdquo; button</li>
<li>Waits for DOM change (<code>expect(total).toContain('180')</code>)</li>
<li>Checks visibility of the &ldquo;Coupon applied: 10% off&rdquo; message</li>
<li>Verifies the &ldquo;Place order&rdquo; button remains <code>enabled</code></li>
</ol>
<p>Reports back:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>✅ Scenario: Valid coupon applies discount
  ✅ Given: on the checkout page (h1 visible, correct URL)
  ✅ And: 2 items, total R$ 200 (read from .cart-total)
  ✅ When: coupon NEXTSIDE10 applied
  ✅ Then: total updated to R$ 180
  ✅ And: success message visible
  ❌ And: &#34;Place order&#34; button is DISABLED

Final state screenshot: /tmp/checkout-disabled-btn.png
Suspicion: regression in coupon-success-handler that set disabled=true 
by mistake after applying the discount.</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Total time: <strong>35 seconds</strong>. No E2E test written, no stub, no mock. <strong>It validated against the real app, on your localhost, before the PR went to review.</strong></p>
<h3>But doesn&rsquo;t this replace real Playwright in CI/CD?<span class="hx:absolute hx:-mt-20" id="but-doesnt-this-replace-real-playwright-in-cicd"></span>
    <a href="#but-doesnt-this-replace-real-playwright-in-cicd" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It doesn&rsquo;t. CI/CD keeps running the full suite on every PR. This flow is the <strong>pre-flight</strong>: before you open the PR, before CI spends 6min, before the human reviewer opens a tab to look, you already know whether the PO&rsquo;s scenario passes or fails. The regression above (button DISABLED by mistake) is exactly the kind of bug that hits production 2 sprints later because nobody tested that manual path.</p>
<p>The PO&rsquo;s Gherkin became executable input. <strong>Acceptance documentation became running acceptance test.</strong> Without anyone writing test code.</p>
<h2>What changes vs traditional E2E testing<span class="hx:absolute hx:-mt-20" id="what-changes-vs-traditional-e2e-testing"></span>
    <a href="#what-changes-vs-traditional-e2e-testing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s an important point so you don&rsquo;t get confused. MCP Playwright doesn&rsquo;t replace your E2E suite in CI. ABSOLUTELY NOT. They solve different things, and the confusion usually starts because the name &ldquo;Playwright&rdquo; shows up in both.</p>
<p>Traditional E2E is what the <strong>engineer writes in code, versions in the repository, and CI runs automatically on every PR</strong>. That doesn&rsquo;t change. That&rsquo;s still there.</p>
<p>MCP Playwright is <strong>step 3 in the dev flow</strong>: that manual click-through you used to do (or skip) before opening the PR. Except now the AI does it in your place.</p>
<p>Traditional E2E (Playwright spec running in CI):</p>
<ul>
<li><strong>Runs automatically on every PR</strong>: blocks the merge if it fails</li>
<li><strong>Specified in code</strong>: explicit assertion, versioned, reviewed</li>
<li><strong>Covers the full regression suite</strong>: doesn&rsquo;t depend on you remembering</li>
<li><strong>Slow</strong>: minutes per execution, requires CI infra</li>
</ul>
<p>MCP Playwright in Claude locally:</p>
<ul>
<li><strong>Runs when you ask</strong>: blocks nothing by default</li>
<li><strong>Specified in natural language</strong>: flexible but not versioned</li>
<li><strong>Covers what you describe in the moment</strong>: depends on the instruction</li>
<li><strong>Fast</strong>: seconds per execution, zero infra</li>
</ul>
<p>Ideal use case: <strong>MCP Playwright is for the first validation layer, BEFORE you ask for human review.</strong> It&rsquo;s the sanity check you&rsquo;d do with your own hands, automated. It&rsquo;s not the CI safety net. It&rsquo;s the pre-flight check.</p>
<p>A real E2E suite is still needed for:</p>
<ul>
<li>Blocking regression on PR</li>
<li>Critical coverage of payment flows, auth, etc.</li>
<li>Executable documentation of expected behavior</li>
</ul>
<p>MCP Playwright is needed for:</p>
<ul>
<li>Quick sanity check during development</li>
<li>Visual validation of a feature under active change</li>
<li>&ldquo;Did I break anything?&rdquo; before asking for review</li>
</ul>
<p>They&rsquo;re complementary, not rivals. Whoever replaces their E2E suite with MCP Playwright will miss it the moment a big refactor happens and nothing breaks in CI but everything breaks in production.</p>
<h2>Limits and pitfalls<span class="hx:absolute hx:-mt-20" id="limits-and-pitfalls"></span>
    <a href="#limits-and-pitfalls" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Hold on. There are pitfalls:</p>
<ul>
<li><strong>Not deterministic like code-based tests</strong>: you describe &ldquo;validate the card,&rdquo; Claude interprets. Two runs may check slightly different things. For sanity check: fine. For blocking regression: no.</li>
<li><strong>Token cost</strong>: each screenshot Claude consumes becomes input. In a long session, that adds up. Curate what you send it to inspect.</li>
<li><strong>Silent failures</strong>: if Claude didn&rsquo;t see something, it doesn&rsquo;t report it. False negative. You need to instruct it well on what to look for.</li>
<li><strong>MCP server setup</strong>: installing the local MCP server, configuring it in Claude Code, making sure the browser is available. The first time takes effort. After that, you forget it&rsquo;s there.</li>
<li><strong>Local-only</strong>: MCP Playwright in Claude Code runs on your machine. Not a solution for QA in a shared environment. For that, you still need traditional Playwright in CI.</li>
</ul>
<p>And there&rsquo;s a culture pitfall: <strong>devs get lazy writing real tests because &ldquo;Claude tests for me.&rdquo;</strong> That&rsquo;s a trap. MCP Playwright complements testing, it doesn&rsquo;t replace it. Whoever uses it as a substitute will learn the hard way: when a critical feature breaks in production with no test covering it.</p>
<blockquote>
  <p>&ldquo;But if MCP Playwright is so good, why do we need CI?&rdquo; Because CI blocks what humans forget. MCP Playwright only runs when you ask. CI runs always. CI is the insurance, MCP is the pre-flight. Remove the insurance, and the first crash will remind you.</p>

</blockquote>
<h2>What this says about the future of local QA<span class="hx:absolute hx:-mt-20" id="what-this-says-about-the-future-of-local-qa"></span>
    <a href="#what-this-says-about-the-future-of-local-qa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s what matters.</p>
<p>For a long time, local frontend validation was bad. You opened the browser, opened DevTools, remembered (or didn&rsquo;t) to test mobile, remembered (or didn&rsquo;t) to test dark mode, remembered (or didn&rsquo;t) to check the console. Every time. Manually. Getting tired.</p>
<p>Result: visual bug became production bug. Not because the dev is bad, but because the human brain is not a reliable checklist machine after 4 hours of pair programming.</p>
<p>MCP Playwright changes that because it lets the <strong>checklist become code</strong> that another entity, the AI, runs for you. You never forget to test dark mode again. You never commit without seeing the console. Not because you got better, but because the process now runs itself. It&rsquo;s the same logic we apply to <a href="/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/">documenting technical decisions in ADRs in Notion</a>: take it out of human memory, put it in a format that survives fatigue.</p>
<p>That&rsquo;s what excites me most about MCP in general: it&rsquo;s the first time I see automation of tedious tasks with AI delivering REAL results, not promises. Playwright is just the most mature example. There will be MCP servers for everything you hate doing but have to do. And when you can evaluate new tech in 2 weeks instead of buying the whole idea, <a href="https://nextside.tech/#discovery"target="_blank" rel="noopener">Discovery is the right format</a>: you don&rsquo;t need to bet 6 months to know if MCP fits your pipeline.</p>
<p>And the team that adopts it first will gain consistency that the team that doesn&rsquo;t adopt will never be able to replicate through sheer willpower.</p>
<p>That&rsquo;s why the Nextside team runs MCP Playwright in every UX review agent. Not as an AI gimmick. As a <strong>way of ensuring the boring checklist happens every time, without depending on me to remember at 11pm on a Friday.</strong></p>
<p>The AI gets tired less than you. Use that to your advantage.</p>
]]></content:encoded></item><item><title>Claude Code superpowers: the plugin that changes how a team ships</title><link>https://blog.nextside.tech/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/</link><pubDate>Sat, 16 May 2026 11:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/</guid><dc:creator>Pablo Winter</dc:creator><category>claude-code</category><category>superpowers</category><category>ai</category><category>productivity</category><category>skills</category><description>Claude Code superpowers isn't just another AI plugin. It's how you encode team knowledge into a place the machine reads and executes every time.</description><content:encoded><![CDATA[<p><strong>TL;DR:</strong> can you ship quality software with plain Claude Code? Yes. But there&rsquo;s fine print.</p>
<p>The fine print is: it depends on your seniority level to cover what the AI doesn&rsquo;t, and on the methodology you can keep in your head. For 1-2 parallel tasks, vibe coding with Claude Code does the job. For 5-6 simultaneous tasks, where Nextside lives, the human brain can&rsquo;t hold it. That&rsquo;s where encoded methodology comes in.</p>
<p>Superpowers is encoded methodology packaged as a plugin: skills, agents, slash commands, hooks. Instead of reinventing SDD (Spec-Driven Development) and your own harness engineering, which costs weeks of R&amp;D, you use what thousands of devs are validating in parallel. Plugin bug fix lands for you for free. New feature lands for you for free. It&rsquo;s open-source working the way open-source should.</p>
<p>I tested it. We tested it. This blog you&rsquo;re reading was built with Claude Code + superpowers from start to finish: design system, Hugo layouts, agent pipeline, frontmatter, this very post. And what caught my attention most wasn&rsquo;t speed. It was discipline.</p>
<h2>Plain Claude Code with vibe coding works, until it breaks<span class="hx:absolute hx:-mt-20" id="plain-claude-code-with-vibe-coding-works-until-it-breaks"></span>
    <a href="#plain-claude-code-with-vibe-coding-works-until-it-breaks" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://akitaonrails.com/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/"target="_blank" rel="noopener">Fabio Akita wrote about Agile Vibe Coding</a> and he&rsquo;s right. You can ship a whole feature in 30min using plain Claude Code, talking to the AI, iterating fast. Vibe.</p>
<p>And it works. For 1 task. For 2 tasks.</p>
<h3>So why the plugin?<span class="hx:absolute hx:-mt-20" id="so-why-the-plugin"></span>
    <a href="#so-why-the-plugin" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Because the real work at Nextside isn&rsquo;t 1 task. It&rsquo;s 5. Sometimes 6.</p>
<p>Vibe coding with 1 context = productive. Vibe coding switching context every 15min = your head in pieces by 5pm, with nothing solid shipped.</p>
<p>When parallelism enters, vibe isn&rsquo;t enough. You need:</p>
<ul>
<li><strong>Forced brainstorming before coding</strong>: so you don&rsquo;t start the wrong task</li>
<li><strong>Mandatory tests at code-time</strong>: so you don&rsquo;t come back to debug in 2 days</li>
<li><strong>Plan written by an agent</strong>: so you can read it later and remember where you stopped</li>
<li><strong>Automatic UX review</strong>: so you don&rsquo;t forget to check the visual result</li>
<li><strong>Skill with checklist</strong>: so each task type runs the same way</li>
</ul>
<p>You can build all of this yourself. You&rsquo;ll spend 2-3 weeks, validate with your team, debug the first iteration. <strong>Or use the superpowers plugin that already has it, and get new features other engineers already validated.</strong></p>
<p>The plugin doesn&rsquo;t take the vibe away. It takes the <strong>mess out of parallelism</strong>. You&rsquo;re still in command, just with guard rails where human fatigue would already have betrayed the result.</p>
<h2>What superpowers is, without the hype<span class="hx:absolute hx:-mt-20" id="what-superpowers-is-without-the-hype"></span>
    <a href="#what-superpowers-is-without-the-hype" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Superpowers is a plugin for Claude Code (claude.ai/code, Anthropic&rsquo;s CLI) that adds three concrete things:</p>
<ul>
<li><strong>Skills</strong>: markdown files that describe &ldquo;how to do X.&rdquo; Each skill has a trigger (when to use it), steps (what to do), and rules (what not to skip). Claude reads the skill before executing the task.</li>
<li><strong>Agents/Subagents</strong>: specialized invocations. You launch a &ldquo;UX review subagent&rdquo; that has its own context, its own prompts, and its own tools. Doesn&rsquo;t pollute the main context.</li>
<li><strong>Slash commands</strong>: shortcuts you type (<code>/code-review</code>, <code>/ship</code>, <code>/init</code>) that fire complex flows. Each one reads the repo, executes steps, and reports back.</li>
</ul>
<p>Sounds like saved prompts? It is. But the difference isn&rsquo;t the content: it&rsquo;s the <strong>ritual</strong>. Skill enforced means Claude reads the skill BEFORE it starts working. There&rsquo;s no chance of skipping the TDD step. No chance of skipping the brainstorming checkpoint. The skill is an automatic trigger.</p>
<p>And that&rsquo;s where the shift happens.</p>
<h2>How it changes the real workflow<span class="hx:absolute hx:-mt-20" id="how-it-changes-the-real-workflow"></span>
    <a href="#how-it-changes-the-real-workflow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Without superpowers, Claude Code is a good generalist AI. You open it, describe the task, it tries to solve it. If you forget to ask for tests, it doesn&rsquo;t write tests. If you forget to ask for brainstorming before coding, it jumps straight to implementation. Result: lots of generated code, lots of thrown-away code.</p>
<p>With superpowers, the game is different:</p>
<ul>
<li><strong>TDD enforced</strong>: the <code>test-driven-development</code> skill forces Claude to write a failing test BEFORE writing the implementation. Always. For every bugfix, every feature. Non-negotiable.</li>
<li><strong>Brainstorming before code</strong>: the <code>brainstorming</code> skill requires that, before any creative work, Claude explores the problem with you. Asks questions. Lists alternatives. Only then proposes a solution.</li>
<li><strong>Systematic debugging</strong>: found a bug? The <code>systematic-debugging</code> skill forces methodical investigation instead of guessing. The first hypothesis isn&rsquo;t the bet. It&rsquo;s the starting point of a cause tree.</li>
<li><strong>Verification before completion</strong>: Claude can&rsquo;t say &ldquo;done&rdquo; without running verification. Runs the tests, shows the output, then asserts. Goodbye &ldquo;should work.&rdquo;</li>
</ul>
<p>Notice the pattern: each skill is a way of encoding senior engineering discipline. What experienced devs do out of habit (TDD, brainstorming before code, methodical debugging, verify before asserting) becomes a rule the machine executes.</p>
<p>And here&rsquo;s the key point: <strong>this isn&rsquo;t about giving AI superpowers. It&rsquo;s about giving AI the habit set of your best senior dev.</strong></p>
<h2>How Nextside used it to build its own blog<span class="hx:absolute hx:-mt-20" id="how-nextside-used-it-to-build-its-own-blog"></span>
    <a href="#how-nextside-used-it-to-build-its-own-blog" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The Nextside team built this blog (<code>blog.nextside.tech</code>) using Claude Code + superpowers. Stack: Hugo + Hextra theme, custom CSS design system, editorial agent pipeline, bilingual pt-BR/EN.</p>
<p>Typical flow for a design system feature:</p>
<ol>
<li><strong>Brainstorming session</strong>: I describe &ldquo;I need a hover state for the post card.&rdquo; Claude (via brainstorming skill) asks 3-4 questions: &ldquo;ember glow or just elevation?&rdquo;, &ldquo;mobile too or desktop only?&rdquo;, &ldquo;behavior in dark mode?&rdquo; Only after that does it propose an approach.</li>
<li><strong>Written plan</strong>: the <code>writing-plans</code> skill forces Claude to write a detailed plan before coding. The plan goes into a spec file. I review it. Approve or request adjustments.</li>
<li><strong>Execution with TDD</strong>: the <code>executing-plans</code> skill follows the plan. Each plan step becomes a checkpoint. The TDD skill forces a test before code (when applicable: in pure CSS, it becomes visual verification).</li>
<li><strong>Automatic UX review</strong>: before the commit, it launches a <a href="/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/">dedicated UX review agent that opens the site in the browser via MCP Playwright</a>, navigates, takes screenshots, and flags problems.</li>
<li><strong>Commit + push</strong>: only after everything is green.</li>
</ol>
<p>Notice: zero disorganized vibe coding. Zero &ldquo;let me try something.&rdquo; Zero &ldquo;should work.&rdquo; It&rsquo;s a pipeline.</p>
<p>And the result comes because the pipeline is repeatable. The next feature goes through the same checkpoints. Same skill. Same agent. Doesn&rsquo;t depend on my memory of &ldquo;what did I ask for last time?&rdquo;</p>
<p>That&rsquo;s what changes for a team. When knowledge is encoded in a skill, any dev on the team invokes the same Claude and gets the same standard. There&rsquo;s no dev &ldquo;who knows how to use Claude well&rdquo; and dev &ldquo;who doesn&rsquo;t.&rdquo; The knowledge lives in the plugin.</p>
<h2>What improves vs plain Claude Code<span class="hx:absolute hx:-mt-20" id="what-improves-vs-plain-claude-code"></span>
    <a href="#what-improves-vs-plain-claude-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Concrete before-and-after:</p>
<ul>
<li><strong>Real speed (not perceived)</strong>: plain Claude delivers too fast. You think you saved time, but spent 2h redoing it. With superpowers, the first delivery takes a bit longer, because there&rsquo;s brainstorming, a plan, TDD, but it&rsquo;s the delivery that sticks.</li>
<li><strong>Less slop</strong>: slop is generated code that looks right but isn&rsquo;t. Without superpowers, slop shows up constantly. With superpowers, the verification step catches it before the commit.</li>
<li><strong>Reproducibility</strong>: another dev on the team invokes the same <code>/code-review</code> and gets a review with criteria identical to mine. Doesn&rsquo;t depend on the prompt I wrote at 3am on a Saturday.</li>
<li><strong>Faster onboarding</strong>: a new dev on the team doesn&rsquo;t need to memorize process. They install superpowers, read the skill and slash command catalog, and already work the way the team works.</li>
</ul>
<p>That last one surprised me the most. I always thought &ldquo;team process&rdquo; meant a doc in Notion. Turns out it doesn&rsquo;t: it&rsquo;s a skill in Claude. Nobody reads Notion docs. A Claude skill executes every time the task starts.</p>
<p>This matters: <strong>process documentation is fiction. Executed skill is actual process.</strong></p>
<h2>Honest limits (it&rsquo;s not magic)<span class="hx:absolute hx:-mt-20" id="honest-limits-its-not-magic"></span>
    <a href="#honest-limits-its-not-magic" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Hold on. Superpowers doesn&rsquo;t solve everything:</p>
<ul>
<li><strong>Doesn&rsquo;t replace senior devs</strong>: it replaces the grunt work of senior devs. Real architectural decisions still require a human in the loop. Who picks the stack, who decides the performance vs DX trade-off, who makes the product call, that&rsquo;s people.</li>
<li><strong>Slip can still escape</strong>: the verification step isn&rsquo;t omniscient. If the test is wrong, the &ldquo;all green&rdquo; is a false positive. You still need to look.</li>
<li><strong>Context cost</strong>: skills fill the initial context. If you have 30 skills loaded and the repo is huge, performance drops. You have to curate active skills.</li>
<li><strong>Doesn&rsquo;t learn on its own</strong>: superpowers doesn&rsquo;t evolve by itself. If a team pattern changes, someone has to update the skill. Without maintenance, it goes stale, and then the AI executes old process with full conviction.</li>
</ul>
<p>And the critical point: <strong>superpowers is a lever, not an autopilot</strong>. You still need to think. You need to review the plan Claude wrote. You need to decide when the brainstorming session has gone on too long. The skill is the ruler, but you&rsquo;re the one holding it.</p>
<blockquote>
  <p>&ldquo;But if the AI does everything, what&rsquo;s the dev&rsquo;s role?&rdquo; Good question. Answer: the dev becomes <strong>architect + reviewer + taste dictator</strong>. No more typing boilerplate. Decides the what, reviews the how, and calibrates the tone. It&rsquo;s a more senior role, not less.</p>

</blockquote>
<h2>What this plugin says about the future of work<span class="hx:absolute hx:-mt-20" id="what-this-plugin-says-about-the-future-of-work"></span>
    <a href="#what-this-plugin-says-about-the-future-of-work" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the point that matters most.</p>
<p>For years, team process meant documents. <a href="/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/">ADRs in Notion</a>. Checklists in Confluence. Playbooks in Google Docs. All passive. All ignored after the second week.</p>
<p>Superpowers changes that because it turns process into <strong>code the AI executes</strong>. The skill isn&rsquo;t a doc: it&rsquo;s an instruction that fires every time the task starts. Nobody needs to remember to &ldquo;run the playbook.&rdquo; The AI runs it by itself.</p>
<p>This has a big implication: the engineering knowledge that used to live in senior devs&rsquo; heads now fits in a markdown file that another team member invokes via slash command. <strong>Encoded knowledge</strong>, executed by machine, scaled to the whole team.</p>
<p>Not magic. Doesn&rsquo;t replace seniority. But it&rsquo;s the first time I&rsquo;ve seen &ldquo;team process&rdquo; leave the page and become real, repeatable behavior, without depending on someone to police it.</p>
<p>And that changes the game. Full stop.</p>
<p>That&rsquo;s why the Nextside team runs Claude Code + superpowers in <a href="https://nextside.tech/#sprint"target="_blank" rel="noopener">every 4-week Sprint</a>. Not as a productivity tool. As a <strong>way of ensuring the Nextside way of working happens every time, without a human having to remember.</strong></p>
<p>Those who document process in PDF are fighting an old war. Those who encode process in skills are shipping while the others write playbooks.</p>
]]></content:encoded></item><item><title>ADRs in Notion, without the bureaucracy</title><link>https://blog.nextside.tech/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/</link><pubDate>Sat, 16 May 2026 10:00:00 -0300</pubDate><guid>https://blog.nextside.tech/en/posts/2026/05/16/adrs-decisao-no-notion-sem-burocracia/</guid><dc:creator>Pablo Winter</dc:creator><category>adr</category><category>technical-decision</category><category>notion</category><category>process</category><category>small-team</category><category>claude-code</category><description>ADR isn't corporate ceremony. It's the cheapest way to stop repeating the same mistakes, and to make Claude Code consult your decisions before coding.</description><content:encoded><![CDATA[<p>Every time someone says &ldquo;ADR&rdquo; in a meeting, half the room pictures a Sharepoint spreadsheet, an architecture committee, and a 14-page document nobody reads. I thought the same thing. So here&rsquo;s the real question: is ADR worth it for a small team? Short answer: yes, but not the way the book says.</p>
<p><dfn>ADR: Architecture Decision Record</dfn> is a record of a technical decision. Short. Dated. Immutable. You decide something important today, write down why you decided it, and six months from now when someone asks &ldquo;why on earth did we pick Postgres over Mongo?&rdquo;, the answer is right there. No need to re-summon the lost meeting buried in February&rsquo;s calendar.</p>
<p>The point isn&rsquo;t the template. The point is not losing history.</p>
<h2>Why most teams fail at ADR<span class="hx:absolute hx:-mt-20" id="why-most-teams-fail-at-adr"></span>
    <a href="#why-most-teams-fail-at-adr" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Most teams that try to adopt ADR copy Michael Nygard&rsquo;s template (or the AWS prescriptive guidance one, or ThoughtWorks&rsquo;) in week one, write 3 ADRs in 4 days, and abandon ship by day five. I&rsquo;ve done it. Small teams have zero patience for ritual.</p>
<p>The problem is simple: the traditional template has 6 sections (Context, Decision, Status, Consequences, Alternatives Considered, Stakeholders). In a 4-person team with tight deadlines, nobody writes out &ldquo;Alternatives Considered&rdquo; with bullet points. Nobody. You open the doc, stare at 6 empty headers, close the doc, and go back to the code.</p>
<p>Result: the ADR becomes a joke. &ldquo;Hey, remember when we were going to document decisions? Good times.&rdquo;</p>
<blockquote>
  <p>&ldquo;But if you don&rsquo;t document properly, how do you keep any history?&rdquo; Fair question. Answer: we DO document, just in a format that fits a small team. Not in the format that fits a corporate architecture book.</p>

</blockquote>
<p>And that&rsquo;s where the difference lives. ADR for a small team isn&rsquo;t &ldquo;Architecture Decision Record&rdquo; in the pompous sense. It&rsquo;s a <strong>note to your future self</strong>. You&rsquo;re writing for the version of you that shows up 4 months from now, who forgot why you chose Redis over Memcached. That&rsquo;s all.</p>
<h2>How we do it at Nextside, in Notion<span class="hx:absolute hx:-mt-20" id="how-we-do-it-at-nextside-in-notion"></span>
    <a href="#how-we-do-it-at-nextside-in-notion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No separate repo for ADRs. No <code>docs/adr/0001-use-postgres.md</code>. Just a database in Notion called <code>Decisions</code>. Simple schema:</p>
<ul>
<li><strong>Title</strong>: short declarative phrase: &ldquo;Use Postgres as the main database&rdquo;, &ldquo;Adopt Hugo instead of Next for the blog&rdquo;</li>
<li><strong>Status</strong>: Proposed / Accepted / Superseded / Rejected</li>
<li><strong>Date</strong>: when the decision was made</li>
<li><strong>Tags</strong>: area (backend, frontend, infra, process)</li>
<li><strong>Body</strong>: 3 sections: <strong>Context</strong> (1-3 paragraphs), <strong>Decision</strong> (1 dry paragraph), <strong>Consequences</strong> (short bullets: what we gained, what we gave up)</li>
</ul>
<p>That&rsquo;s it.</p>
<p>Notice what&rsquo;s NOT there: &ldquo;Stakeholders&rdquo;, &ldquo;Voting&rdquo;, &ldquo;Alternatives Considered&rdquo; as a formal section. If alternatives matter, they become a paragraph inside Context. If they don&rsquo;t, they don&rsquo;t appear at all. The criterion is simple: <strong>the ADR exists so someone can understand the decision 6 months from now, not to defend it in an Audit</strong>.</p>
<p>The golden rule we follow: <strong>if you decided something that would be expensive to reverse, write an ADR</strong>. If you can undo it in a 50-line PR, write nothing. Documenting everything is the same as documenting nothing: it becomes noise.</p>
<h2>Concrete example (real-ish decision)<span class="hx:absolute hx:-mt-20" id="concrete-example-real-ish-decision"></span>
    <a href="#concrete-example-real-ish-decision" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Typical scenario: the team needs to pick between two ORMs for a new Node project. Prisma vs Drizzle. Discussion runs 40 minutes on Slack. Someone opens Notion and writes:</p>
<blockquote>
  <p><strong>Title:</strong> Use Drizzle as the ORM for project X</p>
<p><strong>Status:</strong> Accepted</p>
<p><strong>Date:</strong> 2026-04-12</p>
<p><strong>Context:</strong> Project X needs an ORM with solid TypeScript support, versioned migrations, and predictable performance on analytics queries. We evaluated Prisma (more mature, better DX, but Rust runtime engine weighs on cold-start in serverless) and Drizzle (newer, zero-cost abstraction, SQL-first). The team already has familiarity with raw SQL.</p>
<p><strong>Decision:</strong> Adopt Drizzle. SQL-first fits the team&rsquo;s profile, cold-start in serverless is a concrete problem for this project, and the learning curve is smaller than the DX gain from Prisma.</p>
<p><strong>Consequences:</strong></p>
<ul>
<li>Faster cold-start on Vercel/AWS Lambda</li>
<li>We lose some advanced features Prisma has out-of-the-box (Prisma Studio, better introspection)</li>
<li>Migrations are more manual: requires greater discipline from the team</li>
<li>If it goes sideways, we can migrate to Prisma. Drizzle is thin, no heavy lock-in</li>
</ul>

</blockquote>
<p>Done. 180 words. 4 minutes to write. Six months from now, when a new dev joins and asks &ldquo;why Drizzle?&rdquo;, the answer is right there, dated, with context.</p>
<p>That&rsquo;s the whole secret. No magic.</p>
<h2>What happens when you DON&rsquo;T do this<span class="hx:absolute hx:-mt-20" id="what-happens-when-you-dont-do-this"></span>
    <a href="#what-happens-when-you-dont-do-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>What happens is what I call <strong>history losing</strong>. Decision made, nobody wrote it down, 6 months later the entire team has forgotten. Then comes the temptation to revisit. &ldquo;Hey, should we have used Prisma?&rdquo; 40-minute discussion. Again. Same 4 people. More or less the same arguments. Identical conclusion.</p>
<p>You just paid the price of that decision TWICE.</p>
<p>Worse: sometimes the conclusion is different, because someone forgot the critical argument that tipped the scales the first time. So the team switches from Drizzle to Prisma, refactors everything, and 3 months later hits the same cold-start problem that originally motivated Drizzle. Back to Drizzle. Another 3 months burned.</p>
<p>This is the worst thing that can happen in a small team: <strong>repeating the same mistake because nobody wrote down the previous mistake</strong>. Big companies can absorb it. A 4-person team can&rsquo;t.</p>
<p><strong>Institutional memory in a small team isn&rsquo;t Confluence. It&rsquo;s habit.</strong></p>
<p>ADR doesn&rsquo;t replace conversation. Doesn&rsquo;t replace pair programming. Doesn&rsquo;t replace <a href="https://nextside.tech/#discovery"target="_blank" rel="noopener">an RFC for something big, which fits better in a dedicated Discovery</a>. But it does replace the &ldquo;wait, let me try to remember why we decided that&hellip;&rdquo;. And that &ldquo;wait, let me try to remember&rdquo; costs more than it looks. It costs interrupted context, rework, and trust in the team&rsquo;s own history.</p>
<blockquote>
  <p>&ldquo;But nobody&rsquo;s going to go back and read the ADR!&rdquo; They will. I do. Every time I come back to an old project and ask myself &ldquo;why?&rdquo; The ADR is the shortcut to the why. Without it, the shortcut disappears.</p>

</blockquote>
<h2>How to start tomorrow (without turning it into a heavy process)<span class="hx:absolute hx:-mt-20" id="how-to-start-tomorrow-without-turning-it-into-a-heavy-process"></span>
    <a href="#how-to-start-tomorrow-without-turning-it-into-a-heavy-process" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you&rsquo;ve never had ADR in your team and want to start, three steps:</p>
<ul>
<li><strong>Create a database in Notion (or Linear, or Trello, or a <code>docs/decisions/</code> directory in the monorepo)</strong>. The tool doesn&rsquo;t matter. Having ONE place does.</li>
<li><strong>Define the trigger rule</strong>: any decision that would cost 1+ day to reverse deserves an ADR. Framework choice, database, auth pattern, queue choice, error pattern. Variable naming does NOT.</li>
<li><strong>Add a trigger to the PR template</strong>: optional question in the template: &ldquo;Does this PR introduce an architectural decision? If so, link the ADR.&rdquo; Soft enforcement. Without it, the habit dies in the second week.</li>
</ul>
<p>In 3 months, the team has 10-15 ADRs. In a year, 30-40. It&rsquo;s not volume. It&rsquo;s <strong>context density</strong>. Each ADR is a clear signal of &ldquo;here we made a decision that mattered.&rdquo;</p>
<p>And here&rsquo;s the detail nobody talks about: the real value of the ADR isn&rsquo;t in the document. It&rsquo;s in <strong>the act of writing</strong>. When you sit down to explain the decision in 3 paragraphs, you discover that half the decision was implicit and poorly formed. The ADR forces clarity. It&rsquo;s the pair programming of technical decision-making.</p>
<p>For those who want to go further and <a href="/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/">encode the process into a skill that AI executes</a>, so that writing an ADR becomes an automatic trigger, that&rsquo;s the natural next step. But start with the human habit. A skill without habit behind it is theater.</p>
<p>That&rsquo;s why I don&rsquo;t even mind if nobody reads it afterward. It was already worth it just for the act of writing.</p>
<h2>The ADR INDEX: the part nobody talks about yet<span class="hx:absolute hx:-mt-20" id="the-adr-index-the-part-nobody-talks-about-yet"></span>
    <a href="#the-adr-index-the-part-nobody-talks-about-yet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s what changed for me in 2026.</p>
<p>ADRs are great for humans. New partner joins the team, opens <code>docs/adr/0042-prisma-vs-sequelize.md</code>, gets the decision in 5min. Good.</p>
<p>But now AI also reads your repo. And it needs an <strong>index</strong>, not brute-force search.</p>
<h3>Can&rsquo;t AI just grep the directory?<span class="hx:absolute hx:-mt-20" id="cant-ai-just-grep-the-directory"></span>
    <a href="#cant-ai-just-grep-the-directory" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It can. And fills the context with 47 irrelevant ADRs to answer one question. Costs tokens, costs quality, costs time.</p>
<p>The solution came from Claude Code itself: its auto-memory system uses a <code>MEMORY.md</code> file that&rsquo;s just an <strong>index</strong>: each line points to a detailed memory file with a 1-line description. When Claude needs to decide something, it reads <code>MEMORY.md</code> (200 lines max), picks the relevant memory, and only then opens the detailed file.</p>
<p>The parallel for ADRs is exact. In your Notion (or <code>docs/adr/INDEX.md</code> if you use a repo), create an <code>INDEX</code> page at the same level as the ADRs:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="k">-</span> [<span class="nt">ADR-0042 Prisma over Sequelize</span>](<span class="na">./0042-prisma-vs-sequelize.md</span>): Postgres with strong typing; rejects Sequelize over migration pain
</span></span><span class="line"><span class="cl"><span class="k">-</span> [<span class="nt">ADR-0043 Server Components on Next 15</span>](<span class="na">./0043-rsc-next-15.md</span>): Default; &#34;use client&#34; only where real interaction exists
</span></span><span class="line"><span class="cl">- [<span class="nt">ADR-0044 No Redux</span>](<span class="na">./0044-sem-redux.md</span>): Zustand for small global state; URL state for the rest</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>One line per ADR. Description that fits in search.</p>
<p>Now Claude (or any AI) hits your repo, reads <code>INDEX.md</code> in 2s, picks which 2-3 ADRs are relevant to the problem at hand, loads only those in context. <strong>The difference between 3 ADRs read and 47 is the difference between useful AI and confused AI.</strong></p>
<p>And the best part: you get the index for free. New humans use it too. No extra cost.</p>
<p>Without an INDEX, your ADRs become a cemetery of great documentation nobody reads: neither human, nor AI.</p>
<h2>Wiring ADRs into your Claude<span class="hx:absolute hx:-mt-20" id="wiring-adrs-into-your-claude"></span>
    <a href="#wiring-adrs-into-your-claude" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>You have the INDEX. Humans use it. Good. But the real trick is making <strong>the AI use it the right way, without you having to remember to remind it</strong>.</p>
<p>This blog runs on Claude Code + superpowers. When we execute <a href="/en/posts/2026/05/16/claude-code-superpowers-plugin-na-pratica/">a superpowers spec, the skill that forces brainstorming, written plan, TDD, verification</a>, architectural decisions show up naturally along the way. &ldquo;Drizzle or Prisma?&rdquo; &ldquo;Server Component by default?&rdquo; Each one is an ADR candidate.</p>
<p>But AI forgets.</p>
<p>Ask it to write something down once, it does. Next session, gone. That&rsquo;s why the note has to become <strong>a system instruction</strong>, not a request.</p>
<h3>CLAUDE.md points at the ADRs (and the INDEX)<span class="hx:absolute hx:-mt-20" id="claudemd-points-at-the-adrs-and-the-index"></span>
    <a href="#claudemd-points-at-the-adrs-and-the-index" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Claude Code loads a <code>CLAUDE.md</code> file from the project root in EVERY session. It&rsquo;s the project&rsquo;s default memory, the AI equivalent of &ldquo;read this before anything else.&rdquo; You don&rsquo;t have to remind it. It reads on its own.</p>
<p>Drop this near the bottom, no ceremony:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gu">## Architecture Decision Records
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Check <span class="sb">`docs/adr/INDEX.md`</span> before making any significant technical decision.
</span></span><span class="line"><span class="cl"><span class="k">-</span> If an existing ADR covers the topic, follow it.
</span></span><span class="line"><span class="cl"><span class="k">-</span> If the decision is new and expensive to reverse, propose a new ADR at the end of the plan.
</span></span><span class="line"><span class="cl">- Every new ADR lands in the INDEX in the same PR.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done. 4 lines. The AI now consults the INDEX whenever it enters planning mode.</p>
<p>The detail that matters: don&rsquo;t stuff your <code>CLAUDE.md</code> with 47 ADRs inline. Point at the INDEX. <code>CLAUDE.md</code> is loaded in EVERY session: every token spent there steals context from something useful. Keep it light. Point. Trust the INDEX to do the rest.</p>
<h3>What if the AI ignores the instruction?<span class="hx:absolute hx:-mt-20" id="what-if-the-ai-ignores-the-instruction"></span>
    <a href="#what-if-the-ai-ignores-the-instruction" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It will, once in a while. That&rsquo;s where the second pillar comes in.</p>
<h3>Slash command <code>/adr</code> to enforce the ritual<span class="hx:absolute hx:-mt-20" id="slash-command-adr-to-enforce-the-ritual"></span>
    <a href="#slash-command-adr-to-enforce-the-ritual" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><code>CLAUDE.md</code> is passive reading: the AI uses it if it remembers. A slash command is ACTIVE: you trigger it, it executes. In Claude Code, you just create <code>.claude/commands/adr.md</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">Plan a new task:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Read <span class="sb">`docs/adr/INDEX.md`</span> and identify ADRs relevant to: $ARGUMENTS
</span></span><span class="line"><span class="cl"><span class="k">-</span> Load only the relevant ADRs into context (not all of them)
</span></span><span class="line"><span class="cl"><span class="k">-</span> If the task introduces a NEW architectural decision, propose a draft ADR before the technical plan
</span></span><span class="line"><span class="cl"><span class="k">-</span> If the task changes or supersedes an existing ADR, flag it explicitly
</span></span><span class="line"><span class="cl">- Every new ADR must be confirmed by me before becoming a file in <span class="sb">`docs/adr/`</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Daily flow becomes:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">/adr Migrate auth from JWT to session cookies</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Claude reads the INDEX, identifies ADR-0023 (the one that originally chose JWT), loads only that one, and proposes ADR-0044 superseding it. You review. You approve. You move to implementation.</p>
<p>Without <code>/adr</code>, you&rsquo;d depend on remembering to tell the AI to consult history. With <code>/adr</code>, the ritual lives in the slash command. <strong>The AI doesn&rsquo;t skip. You don&rsquo;t forget.</strong></p>
<h3>Integrating with superpowers<span class="hx:absolute hx:-mt-20" id="integrating-with-superpowers"></span>
    <a href="#integrating-with-superpowers" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is where it gets beautiful. If you already run superpowers, the <code>writing-plans</code> skill forces a written plan before code. The <code>brainstorming</code> skill forces exploration before implementation. Wiring ADRs into that flow is one line in <code>CLAUDE.md</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gu">## Inviolable rules
</span></span></span><span class="line"><span class="cl"><span class="k">-</span> Every plan generated by the <span class="sb">`writing-plans`</span> skill must reference relevant ADRs up front.
</span></span><span class="line"><span class="cl">- Every architectural decision detected by <span class="sb">`brainstorming`</span> becomes an ADR candidate. Propose a draft to the user.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The superpowers skill already has the &ldquo;before you code, plan&rdquo; trigger built in. Now the plan ships with relevant ADRs already cited. And a new decision ships with a draft ADR ready for the human to approve.</p>
<p>ADR stops being a separate task you forget. It becomes <strong>a natural byproduct of the spec → plan → code flow</strong>. Free of charge.</p>
<h3>Where to put what<span class="hx:absolute hx:-mt-20" id="where-to-put-what"></span>
    <a href="#where-to-put-what" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Claude Code loads <code>CLAUDE.md</code> at three levels: global (<code>~/.claude/CLAUDE.md</code>), project (<code>./CLAUDE.md</code>), and subdirectory (<code>./module/CLAUDE.md</code>). More specific beats more general.</p>
<p>For ADRs, the rule I use:</p>
<ul>
<li><strong>Global</strong>: no ADRs here. Your personal code conventions, sure. ADRs belong to the team, not to you.</li>
<li><strong>Project</strong>: references <code>docs/adr/INDEX.md</code>. Lists the 3-5 most critical ADRs explicitly (database, framework, auth pattern) so the AI doesn&rsquo;t even need to open the INDEX in 90% of cases.</li>
<li><strong>Subdirectory</strong>: only if a module has decisions that apply only there. Rare. Don&rsquo;t force it.</li>
</ul>
<p>Most teams only need the project level. Don&rsquo;t overengineer.</p>
<h3>Three traps<span class="hx:absolute hx:-mt-20" id="three-traps"></span>
    <a href="#three-traps" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Don&rsquo;t paste ADRs inline into <code>CLAUDE.md</code></strong>. It becomes an 800-line file, AI performance drops, and you lose the entire point of the INDEX.</li>
<li><strong>Don&rsquo;t let the AI write ADRs alone without human approval</strong>. An ADR is a decision. Decisions need humans. The AI proposes a draft, the human approves. Always.</li>
<li><strong>Don&rsquo;t forget to update the INDEX when you create a new ADR</strong>. The INDEX is the contract. If the ADR exists but isn&rsquo;t in the INDEX, it doesn&rsquo;t exist for the AI.</li>
</ul>
<p>Skill without human ritual is theater. Human ritual without skill is fatigue. The two together is how an ADR stays alive in a small team running heavy AI.</p>
<h2>What ADR actually protects you from<span class="hx:absolute hx:-mt-20" id="what-adr-actually-protects-you-from"></span>
    <a href="#what-adr-actually-protects-you-from" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ADR doesn&rsquo;t protect you from making the wrong decision. ABSOLUTELY NOT. You&rsquo;re going to make the wrong decision anyway. Every team does. What ADR protects you from is making the SAME wrong decision twice. Which is a different thing.</p>
<p>A good team isn&rsquo;t the one that gets everything right. It&rsquo;s the one that makes fewer mistakes with each iteration. ADR is the record that lets you know which mistake you made and why, so you don&rsquo;t make it again the next time a similar decision comes up. It&rsquo;s the equivalent, in product decisions, of the <a href="/en/posts/2026/05/16/mcp-playwright-validacao-local-com-qualidade/">local validation with real quality we do via MCP Playwright in frontend</a>: you don&rsquo;t prevent every mistake, but you ensure that mistakes become registered learning.</p>
<p>In a small team, the margin to repeat mistakes is zero. Every week burned on a redone decision is a week you didn&rsquo;t have. Discovery, MVP, refactor: there&rsquo;s no slack.</p>
<p>That&rsquo;s why the Nextside team writes ADRs in Notion. Short. Dated. Honest. No giant template. No ceremony. No extra meetings.</p>
<p>ADR isn&rsquo;t for impressing an auditor. It&rsquo;s for the team. And the team is small. And time is short.</p>
<p>Those who don&rsquo;t record history are doomed to repeat it. And repeating mistakes is a luxury a small team simply can&rsquo;t afford.</p>
]]></content:encoded></item><item><title>About this blog</title><link>https://blog.nextside.tech/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog.nextside.tech/about/</guid><description>Why this blog exists, who writes, who to talk to.</description><content:encoded><![CDATA[<h2>Why this blog exists<span class="hx:absolute hx:-mt-20" id="why-this-blog-exists"></span>
    <a href="#why-this-blog-exists" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nextside ships 4-week Sprints, technical Discoveries and Audits.
This blog is where we tell you — in first person, without corporate fluff —
how we think, what works, and what doesn&rsquo;t.</p>
<h2>Who writes<span class="hx:absolute hx:-mt-20" id="who-writes"></span>
    <a href="#who-writes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Senior partners and engineers at Nextside. Every post has a name,
a face and a LinkedIn at the bottom. No ghost-writers.</p>
<h2>What we write about<span class="hx:absolute hx:-mt-20" id="what-we-write-about"></span>
    <a href="#what-we-write-about" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><strong>Technology</strong> — applied AI, stacks, architecture, technical decisions</li>
<li><strong>Management</strong> — how we run small teams with expensive people</li>
<li><strong>Fast shipping</strong> — the Sprint method, fixed scope, 4-week MVPs</li>
<li><strong>Cases</strong> — client stories (authorized), behind-the-scenes, numbers</li>
</ul>
<h2>Who to talk to<span class="hx:absolute hx:-mt-20" id="who-to-talk-to"></span>
    <a href="#who-to-talk-to" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><strong>Want to hire a Sprint, Discovery or Audit?</strong> → <a href="https://nextside.tech"target="_blank" rel="noopener">nextside.tech</a></li>
<li><strong>Want to work with us?</strong> → <a href="https://linkedin.com/company/nextside-tech"target="_blank" rel="noopener">Nextside LinkedIn</a></li>
<li><strong>Just want to chat about a post?</strong> → Author&rsquo;s LinkedIn or X</li>
</ul>
<p>No newsletter, no pop-up, no formula. You read, you decide if you like it, you come back.</p>
]]></content:encoded></item><item><title>Bruno Raphael</title><link>https://blog.nextside.tech/en/autores/bruno-raphael/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog.nextside.tech/en/autores/bruno-raphael/</guid><content:encoded><![CDATA[<p>I&rsquo;m a Nextside partner and an engineer with 10+ years of experience. I&rsquo;ve
worked with geoprocessing and GIS, with mobile — from native Android to React
Native — and with distributed backends: microservices in Node.js/NestJS and
Java/Spring Boot, payments, distributed locks, and hexagonal architecture
running on Kubernetes on AWS.</p>
<p>Here on the blog I write about mobile development, distributed systems
architecture, and what I&rsquo;ve learned building software that can&rsquo;t get the
numbers wrong.</p>
]]></content:encoded></item><item><title>Lucas Israel</title><link>https://blog.nextside.tech/en/autores/lucas-israel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog.nextside.tech/en/autores/lucas-israel/</guid><content:encoded><![CDATA[<p>I&rsquo;m part of Nextside and have been building digital products for over 14
years. I started as a developer and became a systems architect — I went
through electronic toll collection (COMPSIS), was CTO of one of Brazil&rsquo;s
first legaltechs (Justto, which processed over R$1 billion on the platform
and was eventually acquired), and today I work on technology and product at
Projuris.</p>
<p>I like turning an idea into a solution that creates value fast — or killing
the idea fast so it doesn&rsquo;t burn investment. Focus on SaaS platforms, AWS
architecture, AI applied with pragmatism, and small high-performance teams. I
also build ventures, assess new businesses, and invest in startups. I like to
measure, test, and adjust.</p>
<p>Here on the blog I write about architecture that survives production, AI
applied with judgment, and how to get an MVP out of the garage without
turning it into duct tape.</p>
]]></content:encoded></item><item><title>Pablo Winter</title><link>https://blog.nextside.tech/en/autores/pablo-winter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog.nextside.tech/en/autores/pablo-winter/</guid><content:encoded><![CDATA[<p>I&rsquo;m a Nextside partner and CTO of digital products for mobility and revenue
collection. 10+ years of engineering — Java/Spring Boot, Node.js, Next.js,
Python. Focus on hexagonal architecture, event-driven systems (SQS, SNS,
RabbitMQ, Kafka), and senior integrations with ERPs and gateways.</p>
<p>Here on the blog I write about AI applied with judgment, managing small
teams, and why fast delivery isn&rsquo;t magic.</p>
]]></content:encoded></item></channel></rss>