<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Jonathan Muszkat — Blog</title>
    <link>https://me.jonymusky.com/blog</link>
    <description>CTO &amp; Co-Founder at Selenios, building AI agents for recruiting. Nearly two decades of software engineering and technical leadership. Mentors early-stage startups and speaks at conferences about AI in enterprise environments. Notes on Next.js, AI agents, and running engineering at a startup.</description>
    <language>en</language>
    <atom:link href="https://me.jonymusky.com/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title><![CDATA[Next.js 16.3 From the CTO Seat: Five Apps, One Month, Three Bugs]]></title>
      <link>https://me.jonymusky.com/blog/nextjs-16-3-from-the-cto-seat</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/nextjs-16-3-from-the-cto-seat</guid>
      <pubDate>Thu, 03 Sep 2026 12:00:00 GMT</pubDate>
      <description><![CDATA[We adopted Next.js 16.3 across five production apps the week it shipped. What paid off, how Cache Components quietly changed our HTTP status codes, and why experimental still means experimental.]]></description>
      <content:encoded><![CDATA[<p>Next.js 16.3 shipped in early August with the headline "biggest update since 16.0". We adopted it the same week across five production apps, then spent a month living with it, and this week we moved everything to the latest patch and went back over every claim in the release post. This is what held up, what did not, and what I would tell another CTO before they flip the flags.</p>

<p>Context, so the numbers mean something: we run five Next.js apps. Three sit in one pnpm monorepo: a 56-route admin product behind auth, a public candidate-facing site with forms and AI interviews, and a small employee portal. The other two are separate repos: an internal analytics dashboard and a trilingual marketing site with an MDX blog. All five deploy to Vercel. All five now run the React Compiler and Cache Components.</p>

<h2>What paid off on day one</h2>

<p><strong>The build cache is real.</strong> Turbopack's filesystem cache for <code>next build</code> is on by default in 16.3. Measured this week on the latest patch, on a laptop: the 56-route app compiles in 30 seconds cold and 0.8 seconds when nothing changed. On 16.3.0 the same cached rebuild took 6.6 seconds, so the patch line got that eight times better without us touching anything. The smaller apps sit around 4 to 7 seconds cold and half a second cached. Wall-clock is higher (page-data collection and static generation are not cached), but the compile step used to be the part we waited on.</p>

<p><strong>Memory eviction changed a decision, not a number.</strong> We never measured dev memory, but it is why our marketing site finally dropped <code>next dev --webpack</code> as its default. Long Turbopack sessions used to grow until the laptop complained; with eviction on by default that stopped being a reason to keep webpack around. Webpack stays as a fallback script, which brings its own lesson below.</p>

<p><strong><code>catchError</code> is the error boundary we actually wanted.</strong> A classic <code>error.tsx</code> swallows <code>notFound()</code> and <code>redirect()</code>, and its reset only clears client state. The new boundary from <code>next/error</code> does neither: it lets those two through, and its <code>retry()</code> re-fetches the Server Components below it. We use it around pages that fetch on the server (with the fallback reporting to Sentry) and, on the blog, around the MDX body so a broken post degrades to a "try again" block instead of a blank page.</p>

<p><strong>TypeScript 7 in <code>next build</code>, with one pnpm gotcha.</strong> Four of the five apps type-check with the native <code>tsc</code>. The one that does not is the marketing site, because it lints with <code>typescript-eslint</code>, whose parser crashed on the TypeScript 7 API when we tried. The apps that lint with Biome never hit that. And under pnpm's isolated linker, the native compiler does not auto-include <code>node_modules/@types</code>, so each app needed an explicit <code>"types"</code> array in its tsconfig. Ten minutes, but ten confusing minutes.</p>

<h2>Cache Components change HTTP semantics, not just speed</h2>

<p>This is the part I would put in bold in every migration guide. Under Cache Components a page streams over a prerendered shell, and the shell goes out with a 200. If your page then calls <code>notFound()</code> while rendering the dynamic part, the status is already on the wire. The user sees your not-found UI. Google sees a 200.</p>

<p>We measured it on the marketing site before fixing it: an unknown blog slug, an unknown ad-landing slug and an unknown comparison-page slug all answered 200. Three whole route families returning "found" for garbage, on the one property where crawlers are the customer. The fix follows the framework's own guidance: establish existence <em>before</em> the first byte. Our proxy now checks blog slugs against a manifest generated at build time (so it cannot go stale in production, and it carries publish dates so scheduled posts still work), checks the other two against their static tables, and rewrites misses to a path no route matches. The router then serves the branded not-found page with a real 404.</p>

<p>The second semantic change is that segment configs are gone. <code>export const revalidate = 3600</code>, <code>dynamic = "force-static"</code>, <code>dynamic = "force-dynamic"</code>: none are allowed once the flag is on. That is not a rename. <code>revalidate</code> becomes a <code>'use cache'</code> scope with <code>cacheLife('hours')</code>, and whatever reads the clock has to move <em>inside</em> that scope. Our blog gates posts by publish date with <code>new Date()</code>; outside a cache scope that is request-time data and a hard prerender error, inside it the clock is read once per cache entry and scheduled posts still appear within the hour. Once we did that, 204 pages prerendered at build and a second hit on a post went from 129 ms to 29 ms.</p>

<h2>Root params is the unlock for i18n, and we have not pulled it yet</h2>

<p>The release post's <code>import.meta.glob</code> example is a blog reading MDX files with <code>gray-matter</code>. That is literally ours, so we tried it in August. It compiled, and it flipped the blog routes from dynamic to fully static, which broke next-intl's request-time locale with 500s at runtime. The synchronous <code>fs</code> reads are load-bearing until the layout stops deriving the locale from <code>params</code>.</p>

<p>That same layout is why the marketing site carries <code>export const instant = false</code> on its whole locale tree: a layout that picks <code>&lt;html lang&gt;</code> and its messages from <code>params</code> cannot produce an instant static shell. Root params (<code>lang()</code> from <code>next/root-params</code>) plus <code>setRequestLocale</code> is the fix, and it is the next step for that app. If your app is internationalized with a <code>[locale]</code> segment, that migration is the price of Instant Navigations, and it is worth budgeting for it up front rather than discovering it through <code>instant = false</code>.</p>

<h2>Experimental means experimental</h2>

<p>The Rust-based React Compiler is the feature I was most excited about and the one that cost the most. Two things happened.</p>

<p>First, on our largest app it OOM-kills the build on Vercel's standard container, about 25 seconds into a cold compile. The same app builds fine through the Babel path (twice as slow, but it fits), and the smaller apps build fine with the Rust port. We reported it, a maintainer engaged the same day, and by late August they had cut the compiler's peak allocation by half, with a quadratic-growth path as the likely trigger for our code. That work is on canary. We re-ran the experiment this week on the latest 16.3 patch, on a preview deployment, and got the same SIGKILL. So our config keeps a per-target guard: Rust port everywhere except Vercel builds of that one app, where the compiler runs through Babel.</p>

<p>Second, the Rust port drops the <code>jsx-&lt;hash&gt;</code> scoping class from conditionally rendered elements inside stateful components, so scoped <code>&lt;style jsx&gt;</code> rules silently stop matching. It shipped our sidebar labels invisible. We kept a minimal repro repository (<a href="https://github.com/vercel/next.js/issues/96694">vercel/next.js#96694</a>) and re-ran it this week against three versions: still broken on the latest 16.3 patch, fixed on the 16.4 canary. That turned "maybe fixed by now" into a version number, and it means our "no scoped styled-jsx" rule stays exactly until 16.4.</p>

<p>Two smaller things from the same bucket. <code>output: 'standalone'</code> combined with an adapter broke Vercel deploys on 16.3.0 (a missing trace file); the fix was merged to canary two days later and, as of this week, has still not shipped in any stable 16.3 patch. Check the tag, not the PR. And the config guard for our webpack fallback originally tested <code>process.argv</code> for <code>--webpack</code>, which never matches because <code>next.config</code> is evaluated in Next's internal server process. A reviewer caught it by actually running the fallback. Guards you never exercise are guards you do not have.</p>

<h2>The bug that had nothing to do with Next.js</h2>

<p>The marketing site's whole 16.3 adoption was reviewed, approved and merged on August 4. It was merged into the feature branch it had been stacked on, and that branch was never merged again. For a month the site ran a 16.3 binary with webpack in dev, no compiler and the old segment configs. Nothing broke, which is exactly why nobody noticed, and I only found it this week by grepping <code>main</code> for a flag that should have been there. We re-applied the intent by hand; a cherry-pick had ten conflicting files against a month of design work. Stacked PRs are fine. Stacked PRs whose base is not <code>main</code> need a reminder on the base.</p>

<h2>What I would tell another CTO</h2>

<ul>
<li><strong>Take the patches.</strong> 16.3.3 fixed two critical remote-code-execution advisories, one of them in image optimization with AVIF, which is the first format our marketing site serves. Nothing in the 16.3.x line required code changes from us. There is no reason to sit on 16.3.0.</li>
<li><strong>Measure your 404s after flipping Cache Components.</strong> One <code>curl</code> per route family. If you see 200 where you expect 404, move existence checks into the proxy.</li>
<li><strong>Treat <code>revalidate</code> as a migration.</strong> Find every segment config, find what reads the clock, move it inside a cache scope.</li>
<li><strong>Give every experimental flag a per-target escape hatch and a way to re-test it.</strong> Ours is one commit on a pull-request preview and a revert. Six minutes, and now we know the answer for this patch.</li>
<li><strong>Keep a repro repo for every bug you report.</strong> Re-running it against a new version costs two minutes and answers the question upstream comments cannot.</li>
<li><strong>A fix on canary is not a fix in your build.</strong> Check the release tag.</li>
<li><strong>If you are internationalized, plan the root-params migration before you plan Instant Navigations.</strong> It is the same project.</li>
</ul>

<p>16.3 is a good release. The build cache and the error boundary alone were worth the upgrade, and Cache Components is the right model for the apps we build. But the release post describes a destination, and the road there runs through your proxy, your i18n layout and your build container's memory limit. Knowing that before you start is most of the work.</p>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Ralph Loop: The AI Development Methodology Taking Over 2026]]></title>
      <link>https://me.jonymusky.com/blog/ralph-loop-autonomous-ai-development</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/ralph-loop-autonomous-ai-development</guid>
      <pubDate>Thu, 16 Jan 2025 12:00:00 GMT</pubDate>
      <description><![CDATA[Discover the Ralph Wiggum technique—an autonomous AI agent loop that lets Claude Code work continuously until your project is complete.]]></description>
      <content:encoded><![CDATA[The Ralph Loop (or Ralph Wiggum technique) is revolutionizing how developers work with AI coding assistants. Created by Geoffrey Huntley, this elegantly simple methodology keeps an AI agent working on a task until it's truly done.<br /><br /><strong>What is Ralph Loop?</strong><br /><br />At its core, Ralph is just a Bash loop. It repeatedly feeds the same prompt to an AI coding agent like Claude Code. The clever part? Progress doesn't persist in the LLM's context window—it lives in your files and git history.<br /><br />Where traditional agentic workflows stop when an LLM finishes calling tools, Ralph keeps going: verifying completion, providing feedback, and running another iteration until the task actually succeeds.<br /><br /><strong>How It Works</strong><br /><br />The Ralph plugin utilizes a stop hook that executes when Claude attempts to end a session. Instead of letting the process terminate, the hook intercepts the exit and scans for a 'safe word' or completion promise. If the agent tries to quit without that specific word (e.g., 'COMPLETE'), the hook blocks the exit and continues working.<br /><br />Each iteration starts fresh with clean context, treating files and git as memory rather than the model context. This philosophical shift embraces fresh starts and lets git be the memory layer.<br /><br /><strong>Why It Matters</strong><br /><br />Boris Cherny, Anthropic's Head of Claude Code, formalized this into the official ralph-wiggum plugin. VentureBeat declared Ralph Wiggum 'the biggest name in AI right now.'<br /><br />For developers, this means you can set up autonomous development cycles where Claude Code iteratively improves your project until completion, with built-in safeguards to prevent infinite loops and API overuse.<br /><br /><strong>Getting Started</strong><br /><br />Check out these implementations:<br />- <a href="https://github.com/snarktank/ralph" target="_blank" rel="noopener noreferrer">snarktank/ralph</a> - Autonomous AI agent loop for PRD completion<br />- <a href="https://github.com/vercel-labs/ralph-loop-agent" target="_blank" rel="noopener noreferrer">vercel-labs/ralph-loop-agent</a> - Continuous Autonomy for the AI SDK<br />- <a href="https://github.com/frankbria/ralph-claude-code" target="_blank" rel="noopener noreferrer">frankbria/ralph-claude-code</a> - Autonomous AI development loop for Claude Code<br /><br />The Ralph Loop represents a paradigm shift in AI-assisted development. Instead of micromanaging every interaction, you define the goal and let the agent work until it's done. Welcome to the future of coding.]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[MCP: The Protocol Connecting AI to Everything]]></title>
      <link>https://me.jonymusky.com/blog/mcp-model-context-protocol</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/mcp-model-context-protocol</guid>
      <pubDate>Fri, 10 Jan 2025 12:00:00 GMT</pubDate>
      <description><![CDATA[Exploring Anthropic's Model Context Protocol (MCP) and how it's revolutionizing the way AI models interact with external tools and data sources.]]></description>
      <content:encoded><![CDATA[The Model Context Protocol (MCP) by Anthropic is changing how we build AI applications. Instead of creating custom integrations for each tool, MCP provides a standardized way for AI models to connect with databases, APIs, file systems, and more.<br /><br />What makes MCP special is its simplicity. You define 'tools' that your AI can use, and the protocol handles the communication. This means you can build once and connect everywhere.<br /><br />I've been experimenting with MCP servers for various use cases: connecting to GitHub for code reviews, integrating with Slack for team updates, and even building custom tools for specific workflows.<br /><br />The ecosystem is growing rapidly. Check out the official documentation: <a href="https://modelcontextprotocol.io" target="_blank" rel="noopener noreferrer">MCP Documentation</a>.<br /><br />If you're building AI-powered applications, MCP should definitely be on your radar. It's the kind of protocol that makes you wonder why we didn't have it sooner.]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Claude Code: AI-Powered Development in Your Terminal]]></title>
      <link>https://me.jonymusky.com/blog/claude-code-cli-experience</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/claude-code-cli-experience</guid>
      <pubDate>Wed, 08 Jan 2025 12:00:00 GMT</pubDate>
      <description><![CDATA[My experience using Claude Code CLI for everyday development tasks and why it's become an essential part of my workflow.]]></description>
      <content:encoded><![CDATA[After weeks of using Claude Code as my primary coding assistant, I wanted to share my thoughts on how it has transformed my development workflow.<br /><br />The CLI experience is incredibly smooth. You can ask questions about your codebase, refactor code, write tests, and even debug issues—all without leaving your terminal. The context awareness is impressive; it understands your project structure and can navigate complex codebases effectively.<br /><br />Some features I use daily:<br />- Code exploration and understanding legacy code<br />- Writing unit tests for existing functions<br />- Refactoring with confidence<br />- Quick prototyping of new features<br /><br />The integration with Git is particularly useful. You can review changes, write commit messages, and even create pull requests directly from the conversation.<br /><br />For developers who live in the terminal, Claude Code feels like a natural extension of your workflow rather than a separate tool.]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Why Hono is My Go-To Framework for Edge Computing]]></title>
      <link>https://me.jonymusky.com/blog/hono-framework-2025</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/hono-framework-2025</guid>
      <pubDate>Sun, 05 Jan 2025 12:00:00 GMT</pubDate>
      <description><![CDATA[A deep dive into Hono, the ultrafast web framework that works seamlessly across Cloudflare Workers, Deno, Bun, and Node.js.]]></description>
      <content:encoded><![CDATA[After building several projects with Hono, I can confidently say it's become my favorite framework for edge computing and serverless applications.<br /><br />What sets Hono apart:<br />- Zero dependencies and incredibly small bundle size<br />- Works everywhere: Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda<br />- Express-like API that feels familiar<br />- Built-in middleware for common tasks<br />- TypeScript-first with excellent type inference<br /><br />The performance is remarkable. On Cloudflare Workers, Hono adds virtually no overhead to your cold start times. Combined with its intuitive API, you can go from idea to deployed API in minutes.<br /><br />I particularly love the middleware ecosystem. JWT authentication, CORS, compression, and caching are all available as simple imports.<br /><br />If you're building APIs for the edge, give Hono a try: <a href="https://hono.dev" target="_blank" rel="noopener noreferrer">Hono Documentation</a>.]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Durable Execution: Building Reliable Systems with Temporal]]></title>
      <link>https://me.jonymusky.com/blog/temporal-durable-execution</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/temporal-durable-execution</guid>
      <pubDate>Fri, 20 Dec 2024 12:00:00 GMT</pubDate>
      <description><![CDATA[Understanding durable execution patterns and how Temporal makes building fault-tolerant distributed systems accessible.]]></description>
      <content:encoded><![CDATA[Following up on my Replay Conference post, I wanted to dive deeper into the concept of durable execution and why it matters for modern applications.<br /><br />Traditional error handling often leads to complex retry logic, state management headaches, and difficult-to-debug failures. Durable execution flips this model: your code runs as if failures don't exist, and the framework handles the rest.<br /><br />With Temporal, you write workflows as simple functions. If a server crashes mid-execution, the workflow automatically resumes exactly where it left off. No manual checkpointing, no complex state machines.<br /><br />Real-world use cases I've implemented:<br />- Long-running order processing pipelines<br />- Multi-step user onboarding flows<br />- Scheduled batch jobs with complex dependencies<br />- Saga patterns for distributed transactions<br /><br />The mental model shift is significant, but once it clicks, you'll wonder how you ever built reliable systems without it.<br /><br />Start exploring: <a href="https://temporal.io" target="_blank" rel="noopener noreferrer">Temporal.io</a>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Replay Conference 2024 Highlights]]></title>
      <link>https://me.jonymusky.com/blog/replay-conference-2024</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/replay-conference-2024</guid>
      <pubDate>Tue, 26 Nov 2024 12:00:00 GMT</pubDate>
      <description><![CDATA[Highlights and resources from the Temporal Replay Conference 2024 in Seattle.]]></description>
      <content:encoded><![CDATA[Last week, I attended the Replay Conference 2024 by Temporal in Seattle, and it was an incredible experience! Here are some highlights and insights I gathered during the event.<br /><br />I’ve compiled a summary of what I’ve been exploring here: <a href="https://gist.github.com/jonymusky/8d1f2bbf2ed3168f37b1383b77fa2cfb" target="_blank" rel="noopener noreferrer">Replay Conference Summary</a>.<br /><br />I highly recommend checking out the talks—they were packed with useful information for developers and architects. You can find them on YouTube: <a href="https://www.youtube.com/watch?v=2floQta7GNs&list=PLl9kRkvFJrlR0xieUwBN_nNHW0oijCZa6" target="_blank" rel="noopener noreferrer">Replay Conference Talks</a>.<br /><br />Temporal continues to redefine how we think about workflows and distributed systems, and this conference was no exception. Whether you're new to Temporal or an experienced user, there's so much value in these resources!]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Exploring Cloudflare's Hidden Gems]]></title>
      <link>https://me.jonymusky.com/blog/exploring-cloudflare</link>
      <guid isPermaLink="true">https://me.jonymusky.com/blog/exploring-cloudflare</guid>
      <pubDate>Tue, 26 Nov 2024 12:00:00 GMT</pubDate>
      <description><![CDATA[Discover how Cloudflare Tunnels, Workers, and Email Redirects can supercharge development for startups and proof-of-concepts.]]></description>
      <content:encoded><![CDATA[This weekend, I dove into some of Cloudflare’s lesser-known but powerful features: Tunnels, Workers (serverless functions), Email Workers, and Email Redirects.<br /><br />While most companies use Cloudflare for request optimization, WAF, bot protection, and general site performance, there’s so much more to explore! Many of these functionalities are often free and, in my opinion, can significantly speed up development.<br /><br />For startups or proof-of-concepts, Cloudflare can be a game-changer. With Cloudflare Tunnels (50 free seats like ngrok but with more features), for instance, you could have a Raspberry Pi or a Mac Mini running a simple API from home, cutting down on initial infrastructure costs.<br /><br />What’s also exciting is the ability to connect with Llama 3.1 (<a href="https://lnkd.in/deyeXCA9" target="_blank" rel="noopener noreferrer">Llama 3.1</a>) directly from Workers, enabling easy integrations with AI—completely free.<br /><br />I’d highly recommend giving it a try! My only critique would be that the documentation could be stronger, but the potential these tools offer is well worth exploring.<br /><br />For more details, check out my LinkedIn post: <a href="https://www.linkedin.com/feed/update/urn:li:activity:7264245965698519040/" target="_blank" rel="noopener noreferrer">Cloudflare Insights</a>.]]></content:encoded>
    </item>
  </channel>
</rss>