<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David  (ダビッド )</title>
    <description>The latest articles on DEV Community by David  (ダビッド ) (@telco2011).</description>
    <link>https://dev.to/telco2011</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F234155%2F5b6a88ba-3b1d-4f5f-ad35-9f3239009803.png</url>
      <title>DEV Community: David  (ダビッド )</title>
      <link>https://dev.to/telco2011</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/telco2011"/>
    <language>en</language>
    <item>
      <title>The Four Engineerings of AI</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Fri, 17 Jul 2026 21:43:56 +0000</pubDate>
      <link>https://dev.to/thedavestack/the-four-engineerings-of-ai-482c</link>
      <guid>https://dev.to/thedavestack/the-four-engineerings-of-ai-482c</guid>
      <description>&lt;p&gt;The AI industry has just converged on the very same multi-agent architecture I've spent the last few weeks stumbling my way toward in my own code. I saw it all at once in two YouTube talks: one by &lt;a href="https://www.youtube.com/watch?v=esY99nYXxR4" rel="noopener noreferrer"&gt;Sally-Ann Delucia, from Arize&lt;/a&gt;, on how they solved context management in their agents; another by &lt;a href="https://www.youtube.com/watch?v=ow1we5PzK-o" rel="noopener noreferrer"&gt;Luke Alvoeiro, from Factory&lt;/a&gt;, presenting a multi-agent architecture capable of building and shipping software for days on end.&lt;/p&gt;

&lt;p&gt;I watched them with a strange mix of recognition and relief: the feeling of reading the design of something I had already built, and thinking "so I'm on the right track after all." Because I've spent the last few weeks writing a parallel-agent orchestration plugin —I call it &lt;strong&gt;parallel-work&lt;/strong&gt;— and I built it by tripping over things, not by reading papers. And yet there they were, two people who don't know me at all, describing from their own trenches the same conclusions I had reached the long way around.&lt;/p&gt;

&lt;p&gt;That's what this post is about: the four "engineerings" that are structuring how we work with AI —&lt;strong&gt;prompt, context, harness and loop engineering&lt;/strong&gt;—, what those two talks say, and —at the end— a third speaker who talks not about architecture but about us: about the role left to the human when code becomes free. And why I believe that convergence is the most reliable signal that an idea is right — including one objection I'll raise against myself before you get the chance to.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ladder: prompt → context → harness → loop
&lt;/h2&gt;

&lt;p&gt;I owe the framework to &lt;a href="https://addyosmani.com/" rel="noopener noreferrer"&gt;Addy Osmani&lt;/a&gt;, who organizes work with models into four rungs, each one wrapping the previous:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prompt engineering.&lt;/strong&gt; The model's native reasoning. You write the request well and trust what the model ships with. It's the rung we all started on, and the one the industry is already climbing out of.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context engineering.&lt;/strong&gt; The agent fetches into its own window whatever it needs: tools, files, MCP results. The focus shifts from &lt;em&gt;what you ask&lt;/em&gt; to &lt;em&gt;what it sees while it works&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Harness engineering.&lt;/strong&gt; An &lt;strong&gt;external&lt;/strong&gt; system manages context from the outside: it splits the requirement into a stable, structured task list, and survives the model's window instead of depending on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loop engineering.&lt;/strong&gt; External scaffolding so the agent prompts itself and runs continuously, with the human out of the loop.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;I'll also leave you a more visual, explanatory video on the topic: &lt;a href="https://youtu.be/4biXYSNkn9Y?si=RPzjgyoY_J4sUHG4" rel="noopener noreferrer"&gt;Loop Engineering Explained in 8 Minutes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The elegance of the model is that each rung doesn't replace the previous one — it wraps it. And if I had to pin my plugin to one point on that ladder, I'd say without hesitation that its center of gravity is the third: &lt;strong&gt;harness engineering&lt;/strong&gt;. A wink I wasn't expecting: both speakers use that very word, each on their own —Sally-Ann calls her product "an AI harness"; Luke introduces himself as responsible for Factory's "core agent harness"—. When the vocabulary converges without anyone agreeing on it beforehand, it's usually because the concept was real. But to explain it properly, first the two talks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arize: "agents don't fail because of prompts, they fail because of context"
&lt;/h2&gt;

&lt;p&gt;Sally-Ann Delucia's talk opens with an anecdote that's scary because it's so recognizable. At Arize they built an agent, Alyx, to analyze trace data from their own platform. The problem: every time Alyx ran, it generated more trace data, which bloated its context window, which made it hit the limit, which made it fail… and the failure's own trace added even more data to the next attempt. An agent drowning in its own data trail.&lt;/p&gt;

&lt;p&gt;The line that stuck with me: &lt;strong&gt;"agents don't fail because of prompts, they fail because of context."&lt;/strong&gt; It's the jump from rung 1 to rung 2 said in a single sentence.&lt;/p&gt;

&lt;p&gt;The interesting part is what &lt;em&gt;didn't&lt;/em&gt; work. The naive fix —truncating, keeping the beginning— produced amnesia: follow-up messages lost the thread. The "obvious" fix —asking an LLM to summarize— didn't work either: compression with no principle, no control over what got preserved. The two shortcuts we all think of first, ruled out with data.&lt;/p&gt;

&lt;p&gt;What did work was a three-piece architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart truncation&lt;/strong&gt;: keep the head and tail of the conversation in the active context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A retrievable memory store&lt;/strong&gt; for the middle: it isn't thrown away, it's moved somewhere the agent can pull from when it needs to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-agents&lt;/strong&gt; that take on the heavy operations (analyzing traces, searching) and return only the distilled result, keeping the main conversation light.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Her design principle sums it up perfectly: &lt;em&gt;"context decides what the model sees, memory decides what survives."&lt;/em&gt; And the detail that surprised me: Delucia says &lt;strong&gt;Claude Code independently converged on the same truncation-and-compression strategy&lt;/strong&gt;. She told it with a smile —when Anthropic published part of Claude Code's source, the Arize team read it "hoping to get a little bit of a secret from them," and found their own approach staring back—. It's not an Arize proprietary trick. It's a pattern that emerges when different people push against the same wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Factory: the multi-agent architecture that actually ships software
&lt;/h2&gt;

&lt;p&gt;Luke Alvoeiro's talk goes one rung higher. His opening thesis is a good provocation: &lt;strong&gt;the bottleneck in software engineering is no longer model intelligence — it's human attention.&lt;/strong&gt; We don't lack the capacity to generate code; we lack the capacity to supervise all the code being generated.&lt;/p&gt;

&lt;p&gt;His answer is an architecture —they call it &lt;em&gt;Missions&lt;/em&gt;— with three specialized roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator&lt;/strong&gt;: plans features and milestones and, crucially, &lt;strong&gt;writes the &lt;em&gt;validation contract&lt;/em&gt; before a single line of code is written&lt;/strong&gt;. It defines what "correct" means independently of how it will be implemented. It plays interlocutor, asks questions, closes requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker&lt;/strong&gt;: implements. And it does so with &lt;strong&gt;fresh context per feature&lt;/strong&gt; —it inherits a "clean slate," without the accumulated baggage of previous tasks—, commits via Git and does a structured handoff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validator&lt;/strong&gt;: verifies, and here's the refined part. There are actually &lt;em&gt;two&lt;/em&gt; validators launched at the close of each milestone: one for scrutiny (a battery of tests, types, lints and a review agent per feature) and one for user testing that behaves like a human QA —it spins up the application and actually uses it: fills in forms, clicks buttons, checks that the flows work end to end—. Neither of them &lt;strong&gt;has seen the code before&lt;/strong&gt;: validation is &lt;em&gt;adversarial by design&lt;/em&gt;. And they often run on &lt;strong&gt;a different model provider&lt;/strong&gt;, so that the same model that wrote the code isn't the one signing off on it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A couple more decisions that strike me as the important ones. First, &lt;strong&gt;serial execution&lt;/strong&gt;: a single worker or validator active at a time, because when you let agents run fully in parallel, "agents conflict, duplicate work, and make inconsistent architectural decisions." Second, &lt;strong&gt;model-agnostic design&lt;/strong&gt;: minimal hardcoded logic —all the orchestration lives in about 700 lines of prompts and skills, not in a state machine—, so the system "improves with every model release rather than becoming obsolete." His way of putting it stuck with me: &lt;em&gt;"missions ensure the discipline and the models provide the intelligence"&lt;/em&gt; —which is, word for word, how I think about my plugin: the machinery (hooks, skills, agents, commands and scripts) enforces the discipline, the model supplies the judgment—. The validation contract written &lt;em&gt;before&lt;/em&gt; the code strikes me as the gem of the talk, because it inverts the usual vice: tests written &lt;em&gt;after&lt;/em&gt; confirm the decisions you already made; they don't catch bugs.&lt;/p&gt;

&lt;p&gt;The result they show: a Slack clone built in a sustained 16-day "mission," with 90% of the code covered by tests that, in the end, make up half the lines in the repository. And an honest data point from the talk itself: validation &lt;strong&gt;almost never passes on the first try&lt;/strong&gt; —the system has to open corrective features over and over—, and the bulk of a mission's wall-clock time isn't spent generating code, but waiting for the user-testing validator to exercise the live application. That half the final code is tests, and that verification eats the clock, is not the system's toll: it &lt;em&gt;is&lt;/em&gt; the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where my plugin fits
&lt;/h2&gt;

&lt;p&gt;And this is where I went back to my own notes with a mix of vertigo and relief. Because &lt;strong&gt;I wrote parallel-work without having seen either talk&lt;/strong&gt;, tripping through real runs, and yet the correspondence is almost one to one.&lt;/p&gt;

&lt;p&gt;parallel-work is a Claude Code plugin that encodes a coordinator-driven parallel-agent methodology: Intake → Design Lock → lanes in worktrees → a reviewer per PR → QA → architect audit → merge exactly once. Five roles.&lt;/p&gt;

&lt;p&gt;Why a Claude Code plugin, and not a standalone system from scratch? Two reasons — one about design, one more prosaic. The design one fits everything above: Claude Code's harness is already very mature and very good —context management, tools, permissions, hooks, sub-agents—, so building my coordination layer &lt;em&gt;on top of&lt;/em&gt; that harness, instead of reinventing the base, is the right engineering call. I bring the rung I care about —the multi-agent orchestration harness— and Claude Code supplies the ones underneath. The prosaic one: this way I leverage my own Claude Code subscription instead of standing up and paying for separate infrastructure. Less scaffolding to maintain, more time on the problem I actually want to solve.&lt;/p&gt;

&lt;p&gt;And there's a sister question, the one I asked myself first: if Anthropic already offers &lt;strong&gt;Claude Code Teams&lt;/strong&gt; —its own native multi-agent orchestration layer—, why build my own? Because I tried it before deciding. A while back I put Teams to work on a production NestJS service, with four Linear tickets that were the four layers of a single feature, and &lt;a href="https://es.thedavestack.com/claude-code-teams/" rel="noopener noreferrer"&gt;I wrote about it on the blog&lt;/a&gt; (in Spanish). The code came out solid, but the failures were the revealing part: the supervisor was too passive; the "team lead" approved plans on its own without escalating them to me, skipping protocols I had made explicit; and the agents worked in parallel even though the dependencies were sequential. Three cracks that, funnily enough, are exactly the three things parallel-work turns into hard invariants: the human pinned to the Design Lock and to the merge gate —the latter enforced by a hook, not by the model's good will—, the &lt;strong&gt;waves&lt;/strong&gt; that order in time whatever depends on something else, and independent verification gates that don't rely on anyone remembering to look. It's not that Teams is bad —it's a solid foundation—; it's that I get out of the box what Teams gives me plus, on top, exactly the pieces its own trial showed me were missing. In the time I've been running the plugin it behaves much better for the way I work —with the usual caveat: it's my first-hand experience, not a benchmark, but it's precisely the experience that made me choose—.&lt;/p&gt;

&lt;p&gt;If I put my vocabulary side by side with Factory's and Arize's, this is what comes out:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Industry concept&lt;/th&gt;
&lt;th&gt;parallel-work equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Orchestrator (Factory)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Coordinator&lt;/strong&gt; — the persistent session, with the human&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker with fresh context per task&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Builder&lt;/strong&gt; in its own worktree — &lt;em&gt;my central thesis&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validator that has never seen the code (creator ≠ verifier)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Reviewer / QA / Architect&lt;/strong&gt; — fresh context; reviewer and architect additionally read-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation contract &lt;em&gt;before&lt;/em&gt; the code&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Design Lock&lt;/strong&gt; (glossary + ADRs before building)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured handoffs&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;handoff&lt;/code&gt; skill writing its &lt;strong&gt;&lt;code&gt;HANDOFF.md&lt;/code&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context manager that survives the window&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;STATE.md&lt;/code&gt;&lt;/strong&gt; — always re-read, survives compaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub-agents returning distilled results, not raw data&lt;/td&gt;
&lt;td&gt;Reviewer and architect return &lt;strong&gt;verdicts&lt;/strong&gt;, not work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human on the goal, agent on the execution&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;The merge gate&lt;/strong&gt; — the human-shaped hole&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model-agnostic scaffolding&lt;/td&gt;
&lt;td&gt;The discipline lives in prompts and skills, not a state machine — improves with every model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Two confessions about that table, so you don't buy it wholesale. First: the Factory piece I &lt;strong&gt;don't have yet&lt;/strong&gt; is validator model diversity —having the verifier run on a different provider than the one that wrote the code—. My independence is built with a different mechanism: fresh context (the reviewer never watched the builder reason, so it can't rationalize its decisions) plus read-only enforced in the agent's definition. I stand by that mechanism, but it's not the same axis, and adding model diversity is in my backlog, not in my code. Second: "model-agnostic" does not mean &lt;em&gt;executor&lt;/em&gt;-agnostic. The plugin is deliberately coupled to Claude Code, because its enforcement layer —the hooks that make it physically impossible for a builder to merge— is precisely the part that wouldn't port cleanly to another platform, and it's also the differentiating asset. The discipline survives every model release; it doesn't pretend to survive a change of executor, and that's a decision, not an oversight.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Osmani's definition of "harness" —"an external system that manages context from outside, dividing the requirement into a stable, structured task list"— is, literally, my &lt;code&gt;STATE.md&lt;/code&gt; plus the coordinator. It survives compaction, splits the epic into lanes and waves, and gives every role &lt;strong&gt;fresh context&lt;/strong&gt; instead of a self-summarized context that leaks. Arize's answer to the context problem is retrievable memory; &lt;strong&gt;my answer to the same problem is to never let the context get dirty in the first place&lt;/strong&gt; —every role starts clean—. Different paths, same mountain.&lt;/p&gt;

&lt;p&gt;There's another coincidence I especially liked. Luke lists five multi-agent communication patterns, and Missions uses four: it deliberately discards &lt;strong&gt;direct communication&lt;/strong&gt; between agents, because without a coordinator the state fragments and the single source of truth disappears. In parallel-work the builders never talk to each other either: everything goes through the coordinator and through &lt;code&gt;STATE.md&lt;/code&gt;, which is the single source of truth. Two systems landing on the same rule without knowing each other —agents don't coordinate peer-to-peer, they coordinate against a central state— is exactly the kind of coincidence that made me write this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest divergence: serial vs parallel
&lt;/h2&gt;

&lt;p&gt;Not everything fits, and the point where it doesn't is the most interesting one to tell. Factory &lt;strong&gt;serializes&lt;/strong&gt; features to keep agents from colliding. I do exactly the opposite: I &lt;strong&gt;parallelize&lt;/strong&gt; the lanes. It's the word that gives the plugin its name.&lt;/p&gt;

&lt;p&gt;A contradiction? Not if you look at how the conflict is resolved in each case. Factory avoids the collision by executing one at a time. I avoid the same collision with &lt;strong&gt;worktree isolation&lt;/strong&gt; (each builder works in a separate git tree), a shared &lt;strong&gt;integration branch&lt;/strong&gt; every PR targets, and a &lt;strong&gt;single merge&lt;/strong&gt; once the epic is whole. Same problem —agents stepping on each other, inconsistent architectural decisions—, two valid solutions: they solve it in time (serial), I solve it in space (worktrees). That two designs arrive at different answers to the same risk doesn't weaken either one; it delineates when to choose each.&lt;/p&gt;

&lt;p&gt;And here is where anyone who has suffered through concurrency raises an eyebrow, rightly: the worktree only solves the &lt;strong&gt;physical&lt;/strong&gt; clash —two agents editing the same file—. What about the &lt;strong&gt;logical&lt;/strong&gt; one, when lane A changes a method signature or a schema that lane B depends on? The worktree doesn't touch that one; it's governed by three other layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Design Lock&lt;/strong&gt; pins the shared contracts &lt;em&gt;before&lt;/em&gt; a single lane opens: the glossary and the ADRs close off shared signatures, schemas and architectural decisions. Builders don't &lt;em&gt;invent&lt;/em&gt; divergent interfaces; they start from the ones already sealed.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;waves&lt;/strong&gt; order dependencies in time. The coordinator only parallelizes deliberately independent lanes; whatever touches a shared surface goes in an earlier wave, so the dependents already inherit the change. The parallelism is &lt;em&gt;within&lt;/em&gt; the wave, not indiscriminate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QA and the architect's audit at the seams&lt;/strong&gt; catch whatever drift slipped through anyway: the architect reads the converged whole —not each lane separately— looking precisely for cross-lane inconsistency; QA tests the joints. And all of that happens &lt;em&gt;before&lt;/em&gt; the single merge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if the contract itself turns out to be unworkable mid-execution —lane A discovers that the agreed signature doesn't hold? That's where isolation doesn't mean losing the ability to speak up. Every role still runs inside interactive Claude Code sessions, so a builder that sees the contract collide with reality doesn't keep building on something broken: it raises an alert, and the user —or even the coordinator, which also has the ability to look at the builders' state— can decide whether to pause the wave and go back to the design table with the human, to update the Design Lock and &lt;code&gt;STATE.md&lt;/code&gt; before resuming or redirecting the builders. The plugin automates and parallelizes everything it can, but it puts the human in the loop exactly when reality breaks the plan. A Design Lock that couldn't be renegotiated would be dogma; this one gets renegotiated when it has to.&lt;/p&gt;

&lt;p&gt;In one sentence: Factory avoids the logical conflict &lt;em&gt;by never giving it the chance&lt;/em&gt; —one agent at a time—; I avoid it &lt;strong&gt;by bounding the shared surface up front and auditing it at convergence&lt;/strong&gt;. Without those three layers, parallelizing would be reckless; with them, the worktree becomes the most visible of the defenses, not the only one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The line I don't cross
&lt;/h2&gt;

&lt;p&gt;The fourth rung, loop engineering, is where I choose to stop on purpose. The move that defines loop engineering is the agent prompting itself in a closed loop, with no human. My plugin has the machinery for that —a watch loop in which the coordinator re-prompts itself to detect finished lanes— but it keeps the human pinned to two anchors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Triggering the epic and the Design Lock decisions.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The merge gate.&lt;/strong&gt; Only the coordinator can merge, and since a recent version not even the coordinator can do it while the watch loop is active: a marker file the loop drops blocks merging until the loop ends. Merging went back to being a deliberate act, not something the loop does on its own.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Osmani breaks that loop rung down into six components. Doing the tally against the plugin is the part that surprised me most when watching the videos, because it comes out at five and a half out of six:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Loop component (Osmani)&lt;/th&gt;
&lt;th&gt;In parallel-work&lt;/th&gt;
&lt;th&gt;Match?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Worktree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Self-provisioned lanes under &lt;code&gt;.worktrees/&lt;/code&gt;, in parallel, never contaminating the main tree&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sub-agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reviewer, architect and QA: agents that verify and audit &lt;em&gt;before&lt;/em&gt; anything is called done&lt;/td&gt;
&lt;td&gt;✅ Full — and it's &lt;em&gt;the thesis&lt;/em&gt; of the plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;STATE.md&lt;/code&gt; / &lt;code&gt;HANDOFF.md&lt;/code&gt; / &lt;code&gt;DEBT.md&lt;/code&gt;, per-epic source of truth, survives compaction&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skills&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The plugin &lt;em&gt;ships as&lt;/em&gt; modular skills (coordinator, builder, qa, guide, harness, backlog, steward)&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plugins &amp;amp; Connectors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It &lt;em&gt;is&lt;/em&gt; a Claude Code plugin; it connects herdr, &lt;code&gt;gh&lt;/code&gt;, trackers and the GitNexus MCP&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;/loop&lt;/code&gt; is a &lt;em&gt;watch heartbeat&lt;/em&gt;, not a cron writing code alone and unsupervised&lt;/td&gt;
&lt;td&gt;⚠️ Partial — &lt;em&gt;on purpose&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And here's the beautiful part: the only component I leave half-done —Automation— is exactly the one that would be needed to &lt;em&gt;close the loop&lt;/em&gt; entirely, the one that would hand the irreversible step to the machine. It's not a box I forgot to tick; it's the same line as before, seen from another angle. I have the whole ladder assembled except the last rung, and that gap is person-shaped on purpose.&lt;/p&gt;

&lt;p&gt;This connects with the part of Alvoeiro's talk that resonates with me most: if the bottleneck is human attention, the right design isn't to &lt;em&gt;remove&lt;/em&gt; the human — it's to &lt;strong&gt;place them where their attention yields the most&lt;/strong&gt; —on the goal and on the irreversible step— and remove them from everything else. My bet is that the value is in the scaffolding —parallel isolation, independent verification, durable state—, not in taking the human out of the last step. It's loop-engineering machinery with a person-shaped hole in exactly the right place.&lt;/p&gt;

&lt;p&gt;And so this doesn't stay a pose: the plugin carries an evidence instrument that measures precisely this. In the first epic it ran on itself, the independent gates —reviewer, QA, architect— produced 18 findings: none critical —15 low and 3 medium—, but 17 of them would have shipped to production without those gates, and one of the mediums was &lt;strong&gt;against the coordinator itself&lt;/strong&gt; — exactly the kind of failure a monolithic system cannot see in itself. With the honest caveat that this number is &lt;code&gt;n=1&lt;/code&gt;, on a shell-and-documentation repo —the real stress test, unleashing the five roles on a decoupled, strictly-typed backend, is still to come—. Since that first epic the plugin has already driven several more, real ones, which have been hardening it into today's version: it's not a weekend experiment. But I'm not going to sell you that it competes in maturity with Arize or Factory — far more consolidated, far better-backed products than mine. And maybe that's the most revealing part: arriving at their same shape in barely a few weeks, working side by side with very capable models (Opus 4.8 and Fable 5), says less about my merit than about how hard the convergence pushes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the convergence matters to me
&lt;/h2&gt;

&lt;p&gt;I could tell all of this as "look, I'd already done it." But that's not the interesting part. The interesting part is something else: how can you come to know a design decision is right when you make it alone, with nobody pushing back?&lt;/p&gt;

&lt;p&gt;When you build something alone, your greatest fear is being in love with an idea that only works inside your head. Convergent evolution is the antidote: when people who don't know each other, working on different problems, with different incentives, land on the same shape —fresh context per unit of work, verification by an independent agent, an external state manager that survives the context window, and a human guarding the irreversible step— that stops being an opinion and starts looking like a constraint of the problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now, the objection I promised to raise against myself before you do: &lt;strong&gt;what if the convergence isn't about the problem, but about the substrate?&lt;/strong&gt; I built on top of Claude Code, whose primitives —sub-agents, compaction, worktrees, skills— already channel you toward this shape; Arize says they read Claude Code's source; and these talks circulate on the same conference circuit. Maybe it's not that we were all pushing against the same wall, but that we were all walking down the same corridor. It's a serious rebuttal, and it lowers the degree of independence I can honestly claim: from "three separate paths" to "three paths sharing a landscape." But it only moves the question up one level — it doesn't dissolve it: someone designed that corridor, and got there on their own — Delucia herself tells how Arize and Anthropic converged on the same context strategy &lt;em&gt;without copying each other&lt;/em&gt;, each against their own wall. That the substrate channels you toward a shape is also evidence that the shape is a real constraint; it's just that the evidence is worth somewhat less than it appears at first glance, and I'd rather discount it myself than have you discount it for me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;None of the three of us has to be right. But that all three of us point at the same place, along paths that are at least partly separate, is the best clue I have that the place exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;finally { }&lt;/code&gt;: and still, someone has to read the code
&lt;/h2&gt;

&lt;p&gt;And here comes the third speaker I promised, the one who isn't about architecture but about us. Alex Volkov describes the debate running through the profession: at one end, "code is free… not a thing to get hung up on anymore"; at the other, "slow down… read every line." His twist is that the question is badly framed: &lt;strong&gt;it's not about the people, it's about the tasks.&lt;/strong&gt; The same engineer reads every line of the payments code and waves through the non-critical stuff without looking. You route each change to the scrutiny it needs.&lt;/p&gt;

&lt;p&gt;What made me smile is that his "routing table" includes, without knowing it, two rules I had already turned into code. One: &lt;strong&gt;separate&lt;/strong&gt;. Don't let the same agent write, inspect, and grade itself —"it's like if I came up with an exam and then I took the exam and I scored myself on it"—. That is, exactly, the reason my reviewer and my architect start with fresh context and read-only. And two: &lt;strong&gt;build a system that builds the system&lt;/strong&gt;; reading spends your attention once, but designing makes the system remember it. That's the entire plugin: the machinery that enforces the rules and executes the method so I don't have to police everything by hand.&lt;/p&gt;

&lt;p&gt;The other two videos validated my architecture; this one validates my decision to leave a person-shaped hole. Because, as he says, "loops don't remove judgment, but they do raise the stakes on where you put it" — and that's why I leave that hole where I leave it: not on every line —that no longer scales—, but on the goal and on the merge, the one place where my judgment still earns its keep. &lt;strong&gt;Not every line of 2026 needs your eyes; every system still needs your judgment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And with that I throw down the gauntlet, because these are debatable decisions and I want you to debate them. Parallelizing instead of serializing; forbidding agents from talking to each other and forcing them to coordinate against a central state; putting the human-shaped hole exactly at the merge and nowhere else. The plugin is still private —I can't show you the code, but I can show you the design, which is precisely what I've dissected here—, so what I'm offering is the conversation: where do &lt;em&gt;you&lt;/em&gt; draw the line? How do &lt;em&gt;you&lt;/em&gt; avoid logical collisions when several agents work at once? Have you already hit the context wall, and how did you get out? Tell me in the comments. This is a field we're all sketching out together, and I'd rather you push back than nod and close the tab.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Talks cited: &lt;a href="https://www.youtube.com/watch?v=esY99nYXxR4" rel="noopener noreferrer"&gt;Sally-Ann Delucia — How we solved Context Management in Agents&lt;/a&gt; · &lt;a href="https://www.youtube.com/watch?v=ow1we5PzK-o" rel="noopener noreferrer"&gt;Luke Alvoeiro — The Multi-Agent Architecture That Actually Ships&lt;/a&gt; · &lt;a href="https://www.youtube.com/watch?v=ZpK5PWX2YRM" rel="noopener noreferrer"&gt;Alex Volkov — should we still be reading code in 2026? (the ZL continuum, AI Engineer)&lt;/a&gt;. The four-engineerings framework: Addy Osmani's writing on loop engineering (&lt;a href="https://youtu.be/4biXYSNkn9Y" rel="noopener noreferrer"&gt;explained in 8 minutes&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
    </item>
    <item>
      <title>Nx vs. Turborepo: Integrated Ecosystem or High-Speed Task Runner? The Key Decision for Your Monorepo</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Wed, 12 Nov 2025 10:53:47 +0000</pubDate>
      <link>https://dev.to/thedavestack/nx-vs-turborepo-integrated-ecosystem-or-high-speed-task-runner-the-key-decision-for-your-monorepo-279</link>
      <guid>https://dev.to/thedavestack/nx-vs-turborepo-integrated-ecosystem-or-high-speed-task-runner-the-key-decision-for-your-monorepo-279</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.thedavestack.com/nx-vs-turborepo/" rel="noopener noreferrer"&gt;Original Post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Introduction: The Monorepo "Problem"
&lt;/h3&gt;

&lt;p&gt;In modern software development, monorepos have become a standard solution for managing complexity. Housing multiple applications and libraries in a single repository offers undeniable advantages, though it's a strategy that must be weighed carefully. (If you're still debating between a monorepo and a multi-repo, I've explored that decision in detail in my article &lt;strong&gt;&lt;a href="https://es.thedavestack.com/git-repositories-architecture/" rel="noopener noreferrer"&gt;Repository Architecture: Exploring Monorepo, Multi-repo, and Beyond&lt;/a&gt;&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Once you commit to a monorepo, it brings a headache that grows over time: &lt;strong&gt;speed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As the project expands, &lt;em&gt;build&lt;/em&gt;, &lt;em&gt;test&lt;/em&gt;, and &lt;em&gt;linting&lt;/em&gt; times skyrocket. Tasks that once took seconds now take minutes (or hours). This is where modern &lt;em&gt;build systems&lt;/em&gt; come into play.&lt;/p&gt;

&lt;p&gt;Today, two titans dominate this conversation: &lt;strong&gt;Nx&lt;/strong&gt; and &lt;strong&gt;Turborepo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I've helped multiple teams scale their projects and have dealt with the consequences of choosing the wrong tool. The truth is, a feature-by-feature comparison doesn't tell the whole story. This isn't just a technical decision; &lt;strong&gt;it's a philosophical decision&lt;/strong&gt; about how you want to manage your &lt;em&gt;workspace&lt;/em&gt; and your team.&lt;/p&gt;

&lt;p&gt;In this article, we won't just compare features; we'll analyze what you are &lt;em&gt;really&lt;/em&gt; "buying" with each.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Fundamental Question: What Are You Buying?
&lt;/h3&gt;

&lt;p&gt;Before looking at the tools, you must decide what problem you're trying to solve:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Are you buying speed?&lt;/strong&gt; Do you want a minimalist task runner that you can add to your existing project to make your &lt;em&gt;scripts&lt;/em&gt; fly, without getting in your way?&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Are you buying an ecosystem?&lt;/strong&gt; Do you want a complete framework that guides you, offers code generators, enforces architectural rules, and helps you manage complexity long-term, in addition to being fast?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your answer to this question will almost instantly lean you toward one of the two solutions.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 Option A: Turborepo (The F1 Engine)
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://turborepo.com/" rel="noopener noreferrer"&gt;Turborepo&lt;/a&gt; (acquired by &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;) is a &lt;strong&gt;high-performance task runner&lt;/strong&gt;. Its philosophy is minimalism and pure speed.&lt;/p&gt;

&lt;p&gt;It focuses on one thing and does it exceptionally well: understanding the dependencies of your &lt;code&gt;package.json&lt;/code&gt; &lt;em&gt;scripts&lt;/em&gt; and executing tasks in parallel, aggressively caching the results.&lt;/p&gt;

&lt;p&gt;Its configuration is simple, often a single &lt;code&gt;turbo.json&lt;/code&gt; file in the root, where you define your &lt;em&gt;pipelines&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ The Good: The Speed Argument
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adoption in Minutes:&lt;/strong&gt; You can add Turborepo to an existing monorepo (managed with pnpm, yarn, etc.) in under 10 minutes and see immediate speed improvements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimalist (Not Intrusive):&lt;/strong&gt; It doesn't force you to restructure your project. It's still "your" monorepo; Turborepo just handles running the &lt;em&gt;scripts&lt;/em&gt; defined in your &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple Remote Caching:&lt;/strong&gt; It integrates natively with Vercel for shared remote caching, which is pure gold for CI pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ⛔ The Critique: Speed Without Direction
&lt;/h4&gt;

&lt;p&gt;Turborepo gives you an incredibly fast car, but &lt;strong&gt;it doesn't give you a map or a seatbelt&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It only solves the problem of execution speed. &lt;strong&gt;It doesn't help you with architecture.&lt;/strong&gt; It doesn't stop you from creating circular dependencies, offer generators to create new components consistently, or give you a visualizer for the chaos you might be creating.&lt;/p&gt;

&lt;p&gt;The responsibility for architecture, coherence, and best practices falls 100% on your team's discipline.&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠️ Option B: Nx (The Construction Kit)
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx (by Nrwl)&lt;/a&gt; is an &lt;strong&gt;integrated workspace ecosystem&lt;/strong&gt;. Speed is just &lt;em&gt;one&lt;/em&gt; of its features, not its sole purpose.&lt;/p&gt;

&lt;p&gt;Nx's philosophy is that a healthy monorepo needs more than speed: it needs &lt;strong&gt;structure, consistency, and governance&lt;/strong&gt;. It offers a set of "opinionated" tools to build, test, and deploy your code.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✅ The Good: The Architecture Argument
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code Generators:&lt;/strong&gt; Its strongest feature. It allows you to generate applications, libraries, and components with a single command, ensuring they all follow the same structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Analysis (&lt;code&gt;affected&lt;/code&gt;):&lt;/strong&gt; Nx understands your code at a deep level. It can run tasks (like &lt;em&gt;tests&lt;/em&gt;) &lt;strong&gt;only&lt;/strong&gt; on the projects that have been affected by your changes. This is much smarter than a simple cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module Boundaries (Governance):&lt;/strong&gt; For me, this is its hidden gem. Nx allows you to define architectural rules. For example: "The &lt;code&gt;frontend&lt;/code&gt; app cannot import code directly from the &lt;code&gt;backend&lt;/code&gt; app." This actively prevents technical debt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualization:&lt;/strong&gt; It includes an interactive visualizer for your project's dependency graph.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ⛔ The Critique: The Price of an Opinion
&lt;/h4&gt;

&lt;p&gt;Nx is "heavy" and "magical." Its power comes at a cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learning Curve:&lt;/strong&gt; You have to "buy into" the Nx philosophy. It requires a more complex setup (multiple &lt;code&gt;project.json&lt;/code&gt; files or &lt;code&gt;package.json&lt;/code&gt; configuration) and learning its CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intrusive:&lt;/strong&gt; Migrating an existing project to Nx is much more complex than adding Turborepo. Nx &lt;em&gt;wants&lt;/em&gt; to manage your &lt;em&gt;workspace&lt;/em&gt; its way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cognitive Overhead:&lt;/strong&gt; Sometimes, doing something simple that falls outside the standard generators can be frustrating if you don't understand how the "magic" works under the hood.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Quick Comparison: Nx vs. Turborepo
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;🚀 Turborepo&lt;/th&gt;
&lt;th&gt;🛠️ Nx&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast Task Execution&lt;/td&gt;
&lt;td&gt;Workspace Management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minimalist (&lt;code&gt;turbo.json&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Detailed (&lt;code&gt;nx.json&lt;/code&gt;, &lt;code&gt;project.json&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (Extensive, plugin-based)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Architecture Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (Module Boundaries)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dependency Graph&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (Interactive)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;affected&lt;/code&gt; Commands&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (Cache-based)&lt;/td&gt;
&lt;td&gt;Yes (Deep Graph Analysis)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adoption Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very Low&lt;/td&gt;
&lt;td&gt;Medium / High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for...&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Speeding up existing projects&lt;/td&gt;
&lt;td&gt;Starting new, complex projects&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  The Verdict: What Should You Choose?
&lt;/h3&gt;

&lt;p&gt;As an &lt;strong&gt;experienced software engineer&lt;/strong&gt;, my answer always goes beyond the tool itself: &lt;strong&gt;"It depends on your strategic and team goals."&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  ➡️ You should choose Turborepo if...
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Your main (and perhaps only) problem is that &lt;strong&gt;your CI/CD and local builds are slow&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You have an existing monorepo and &lt;strong&gt;don't want to perform a costly migration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You have a &lt;strong&gt;senior, disciplined team&lt;/strong&gt; that can self-manage architecture without needing tools to enforce it.&lt;/li&gt;
&lt;li&gt;You value &lt;strong&gt;minimalism&lt;/strong&gt; and flexibility over structured guidance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ➡️ You should choose Nx if...
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You are &lt;strong&gt;starting a new project&lt;/strong&gt; and want a solid structure from day zero.&lt;/li&gt;
&lt;li&gt;Your project is &lt;strong&gt;large, complex&lt;/strong&gt;, and needs long-term maintainability.&lt;/li&gt;
&lt;li&gt;You have &lt;strong&gt;teams of varying seniority&lt;/strong&gt; and need tools to ensure consistency and best practices.&lt;/li&gt;
&lt;li&gt;You value &lt;strong&gt;architectural governance&lt;/strong&gt; (avoiding "spaghetti code") as much as or more than execution speed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion (The Dave Stack's Take)
&lt;/h3&gt;

&lt;p&gt;The choice between Nx and Turborepo defines your project's trajectory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Turborepo&lt;/strong&gt; is a &lt;strong&gt;tactical&lt;/strong&gt; tool that offers a quick, impressive win.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nx&lt;/strong&gt; is a &lt;strong&gt;strategic&lt;/strong&gt; tool that requires an initial investment but pays dividends in long-term maintainability and scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At &lt;strong&gt;The Dave Stack&lt;/strong&gt;, the approach I want to &lt;strong&gt;promote and share&lt;/strong&gt; is that of building software that not only works today but is &lt;strong&gt;sustainable tomorrow&lt;/strong&gt;. That's why, for most new and complex projects, I tend to lean towards the governance and structure that Nx provides. In fact, for TypeScript-based projects, &lt;strong&gt;Nx has become my go-to tool&lt;/strong&gt;, as I explain in detail in my article &lt;strong&gt;&lt;a href="https://es.thedavestack.com/nx-smart-repos-fast-builds/" rel="noopener noreferrer"&gt;Nx: Why It's Become My Favorite Tool for TypeScript Projects&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At the end of the day, the right tool is the one that aligns with your team and business strategy.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Now it's your turn: Nx or Turborepo?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You've read my analysis, now I want to know yours. What tool do you use in your day-to-day, and why? Do you value Nx's governance more, or Turborepo's minimalist speed?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Share your experience in the comments.&lt;/strong&gt; The discussion enriches the entire community.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>monorepo</category>
      <category>nx</category>
      <category>turborepo</category>
      <category>typescript</category>
    </item>
    <item>
      <title>DeepSeek Does It Again: From MoE to DSA, The New Era of LLM Efficiency</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Mon, 20 Oct 2025 15:09:43 +0000</pubDate>
      <link>https://dev.to/thedavestack/deepseek-does-it-again-from-moe-to-dsa-the-new-era-of-llm-efficiency-o9h</link>
      <guid>https://dev.to/thedavestack/deepseek-does-it-again-from-moe-to-dsa-the-new-era-of-llm-efficiency-o9h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Header image sourced from &lt;a href="https://chat-deep.ai/models/deepseek-v3-2-exp/" rel="noopener noreferrer"&gt;Chat-Deep&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.thedavestack.com/deepseek-sparse-attention/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Introduction: The Invisible Wall of LLMs
&lt;/h3&gt;

&lt;p&gt;In the fast-paced world of Artificial Intelligence, we often marvel at the size and capabilities of new Large Language Models (LLMs). However, behind every breakthrough lies an invisible wall—a fundamental challenge that limits their scalability and accessibility: &lt;strong&gt;computational cost&lt;/strong&gt;. The team at &lt;a href="https://www.deepseek.com" rel="noopener noreferrer"&gt;DeepSeek AI&lt;/a&gt; seems to have made tearing down this wall their specialty.&lt;/p&gt;

&lt;p&gt;First, they introduced us to their &lt;a href="https://api-docs.deepseek.com/news/news0905" rel="noopener noreferrer"&gt;DeepSeek-V2&lt;/a&gt; model with its groundbreaking &lt;strong&gt;&lt;a href="https://huggingface.co/blog/moe" rel="noopener noreferrer"&gt;Mixture-of-Experts (MoE)&lt;/a&gt;&lt;/strong&gt; architecture, a clever way to scale models by activating only a fraction of their parameters for each task. And now, they've done it again. With the release of &lt;strong&gt;&lt;a href="https://api-docs.deepseek.com/news/news250929" rel="noopener noreferrer"&gt;DeepSeek-V3.2-Exp&lt;/a&gt;&lt;/strong&gt;, they are tackling another pillar holding up that wall: the complexity of the &lt;strong&gt;&lt;a href="https://www.datacamp.com/en/blog/attention-mechanism-in-llms-intuition" rel="noopener noreferrer"&gt;attention mechanism&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Problem: The Tyranny of Quadratic Complexity ($O(L^2)$)
&lt;/h3&gt;

&lt;p&gt;To grasp the magnitude of this innovation, we first need to talk about the enemy: &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Time_complexity" rel="noopener noreferrer"&gt;quadratic complexity ($O(L^2)$)&lt;/a&gt;&lt;/strong&gt; within the Transformer's attention mechanism.&lt;/p&gt;

&lt;p&gt;Since its inception, attention has allowed models to understand the relationships between words in a text. To do this, each new token being processed must "attend" to every single token that came before it. This is incredibly powerful, but it comes at a cost.&lt;/p&gt;

&lt;p&gt;In simple terms, quadratic complexity means that if you double the length of the text (the context), the computational cost and processing time don't just double—&lt;strong&gt;they quadruple&lt;/strong&gt;. If you triple it, the cost multiplies by nine. This creates an exponential bottleneck that makes processing very long documents, entire codebases, or books prohibitively expensive and slow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution: DeepSeek Sparse Attention (DSA)
&lt;/h3&gt;

&lt;p&gt;DeepSeek-V3.2-Exp introduces an elegant solution to this problem: &lt;strong&gt;DeepSeek Sparse Attention (DSA)&lt;/strong&gt;. Instead of "dense" attention (all-to-all), DSA implements "sparse" attention, where each token only attends to the most relevant preceding tokens.&lt;/p&gt;

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

&lt;p&gt;How does it achieve this? The architecture relies on two main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Lightning Indexer&lt;/strong&gt;: This is the brains of the operation. It's a highly efficient component that, before the main attention calculation, computes an "index score" ($I_{t,s}$) between the current query token and all previous tokens. This score determines relevance. Its design is key to its efficiency, as it uses few heads and can be implemented in FP8.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Fine-grained Token Selection&lt;/strong&gt;: Based on the indexer's scores, this mechanism is purely selective. It retrieves only the key-value entries corresponding to the &lt;code&gt;top-k&lt;/code&gt; (the 'k' best) index scores. In the paper, for instance, they mention selecting 2048 key-value tokens for each query.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is that the main attention calculation is no longer performed over the entire sequence but on a small, relevant subset of tokens. This changes the game, &lt;strong&gt;reducing the attention complexity from $O(L^2)$ to $O(Lk)$&lt;/strong&gt;, where 'k' is a fixed number far smaller than the context length 'L'.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Results: Radical Efficiency Without Sacrificing Performance
&lt;/h3&gt;

&lt;p&gt;This is where DeepSeek's approach truly shines. This isn't just a theoretical optimization; the results are tangible and, most importantly, achieved without a significant drop in performance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On-Par Performance&lt;/strong&gt;: Benchmark comparisons show that DeepSeek-V3.2-Exp does not exhibit substantial performance degradation compared to its predecessor, DeepSeek-V3.1-Terminus. On key benchmarks like MMLU-Pro, the score is identical (85.0), and variations in others are minimal.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Drastic Cost Reduction&lt;/strong&gt;: Figure 3 from the paper is conclusive. It shows how the cost per million tokens—for both prefilling (processing the initial prompt) and decoding (generating the response)—skyrockets linearly for the older model as the context length increases. In contrast, with DSA, the cost curve flattens dramatically, demonstrating massive savings in long-context scenarios.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;You can find a more detailed analysis in their &lt;a href="https://github.com/deepseek-ai/DeepSeek-V3.2-Exp/blob/main/DeepSeek_V3_2.pdf" rel="noopener noreferrer"&gt;paper&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What This Means for the Future
&lt;/h3&gt;

&lt;p&gt;From my perspective, focusing on custom software development and AI implementation, this breakthrough is more than just an incremental improvement; it's an enabler.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Era of Hybrid Architectures&lt;/strong&gt;: DeepSeek is showing us the way forward. The future isn't a single solution but the intelligent combination of efficient architectures. Imagine a model that combines the parameter efficiency of &lt;strong&gt;MoE&lt;/strong&gt; with the context efficiency of &lt;strong&gt;DSA&lt;/strong&gt;. We would be looking at a new generation of LLMs that are fundamentally more scalable and cost-effective.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;New Frontiers for Applications&lt;/strong&gt;: With lower costs for long-context tasks, use cases that were once prohibitive are now viable. Think of AI agents that can analyze and reason over entire code repositories in real-time, legal assistants that can review thousands of pages of case law instantly, or financial analysis systems that process full annual reports in a single pass.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Democratization of Power&lt;/strong&gt;: Efficiency doesn't just benefit large corporations. Lower training and, crucially, inference costs allow startups, freelance developers, and smaller companies to access and deploy state-of-the-art models to build custom solutions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ultimately, DeepSeek is cementing its reputation as a team that doesn't just chase raw performance but tackles the fundamental engineering problems that will allow us to build the next generation of AI applications. And it's fascinating to see how this race for efficiency—driven in part by US hardware restrictions on China—is sparking software innovations that benefit us all. It's the classic story of necessity breeding ingenuity, and in the AI race, architectural ingenuity may prove to be more decisive than the brute force of silicon.&lt;/p&gt;

&lt;p&gt;First MoE, now DSA. They are, without a doubt, a team to watch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What are your thoughts? How do you see these new advancements shaping the future? Leave a comment below!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm also leaving a link to their &lt;a href="https://huggingface.co/deepseek-ai/DeepSeek-V3.2-Exp" rel="noopener noreferrer"&gt;card&lt;/a&gt; on Hugging Face so you can dig deeper into this new model.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>deepseek</category>
    </item>
    <item>
      <title>Your Website Speaks to Humans, But Does AI Understand It? A Deep Dive into the Dual Web Strategy</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Tue, 14 Oct 2025 18:05:40 +0000</pubDate>
      <link>https://dev.to/thedavestack/your-website-speaks-to-humans-but-does-ai-understand-it-a-deep-dive-into-the-dual-web-strategy-4bp1</link>
      <guid>https://dev.to/thedavestack/your-website-speaks-to-humans-but-does-ai-understand-it-a-deep-dive-into-the-dual-web-strategy-4bp1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.thedavestack.com/dual-web-strategy/" rel="noopener noreferrer"&gt;Original Post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For years, we've been obsessed with SEO, optimizing every &lt;code&gt;H1&lt;/code&gt;, every &lt;code&gt;alt&lt;/code&gt; tag, and every &lt;code&gt;meta description&lt;/code&gt; to please Google. But the game has changed. A new audience is now consuming our content without ever visiting our websites: generative artificial intelligence.&lt;/p&gt;

&lt;p&gt;Many organizations are creating incredible content—detailed technical articles, product documentation—only to find that when you ask ChatGPT or Google's SGE about it, they are either ignored or, worse, given a mediocre or flat-out incorrect summary.&lt;/p&gt;

&lt;p&gt;This is one of the biggest challenges facing the web today. A recent &lt;em&gt;&lt;a href="https://dualweb.ai/paper.pdf" rel="noopener noreferrer"&gt;whitepaper&lt;/a&gt;&lt;/em&gt; from &lt;strong&gt;&lt;a href="https://dualweb.ai/" rel="noopener noreferrer"&gt;DualWeb.AI&lt;/a&gt;&lt;/strong&gt; has given a name and a method to a fascinating solution, and in this post, we're going to break it down in detail.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Diagnosis: Why AI Gets Lost on Your Website
&lt;/h3&gt;

&lt;p&gt;The modern web—rich with JavaScript, frameworks like React and Vue, interactive designs, and dynamic content loading—is a fantastic experience for humans. But for an AI crawler, it's a minefield.&lt;/p&gt;

&lt;p&gt;These crawlers often only read the initial HTML returned by the server. Anything loaded dynamically or dependent on complex user interactions is, in practice, invisible to them. Furthermore, our marketing language, full of metaphors and suggestive copy, is ambiguous to a machine searching for concrete facts and data.&lt;/p&gt;

&lt;p&gt;The result is a twofold problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Invisibility:&lt;/strong&gt; The AI doesn't "see" key information, so your brand gets omitted from generated answers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inaccuracy:&lt;/strong&gt; The AI misinterprets the content it &lt;em&gt;does&lt;/em&gt; see, mixing up data or "hallucinating" information that damages your brand's credibility.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is critical in a world where the "zero-click" trend—getting the answer without visiting the source—is becoming increasingly dominant. Being featured in these AI summaries isn't an option; it's the new SEO battleground.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Proposed Solution: "Dual Web"
&lt;/h3&gt;

&lt;p&gt;The "Dual Web" concept is as simple in its logic as it is powerful in its execution: &lt;strong&gt;serve each audience the format it needs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The strategy relies on a technical framework that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detects Traffic Type:&lt;/strong&gt; It distinguishes in real-time whether a visitor is a human or a known AI crawler (like those from OpenAI or Perplexity).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivers Tailored Content:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;To humans,&lt;/strong&gt; it serves the canonical, visual, and interactive website, keeping the user experience and traditional SEO intact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;To AI,&lt;/strong&gt; it serves a simplified version of the same page—structured content with clear data points and no visual or navigational "noise," making it ideal for automated processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The results presented in their 100-page study are striking, to say the least: the inclusion rate in AI answers &lt;strong&gt;jumped from 38% to 88%&lt;/strong&gt;, and data accuracy &lt;strong&gt;improved from 63% to 85%&lt;/strong&gt;. These are numbers you simply can't ignore.&lt;/p&gt;




&lt;h3&gt;
  
  
  This Isn't Theory, It's Happening Now: The Market is Moving
&lt;/h3&gt;

&lt;p&gt;This approach isn't just an idea in a whitepaper. Major players are already implementing similar solutions.&lt;/p&gt;

&lt;p&gt;A brilliant example is &lt;strong&gt;&lt;a href="https://docs.docker.com/get-started/get-docker/" rel="noopener noreferrer"&gt;Docker's documentation&lt;/a&gt;&lt;/strong&gt;. If you browse their pages, you'll find a "Page Options" menu with a feature called &lt;strong&gt;"Copy page as Markdown for LLMs."&lt;/strong&gt; With a single click, you get a clean, structured version of the content, ready to be pasted into an AI prompt. They aren't waiting for AI to understand them; they're handing it the content on a silver platter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inspired by this proactive vision, at &lt;strong&gt;The Dave Stack&lt;/strong&gt;, we are developing a similar solution for our own website. We're building a &lt;strong&gt;service in NestJS that connects to our Ghost CMS and automatically generates a Markdown version of each post&lt;/strong&gt;. The idea is simple: if our server detects a request from a known AI crawler, instead of serving the full webpage, it will deliver this clean, direct Markdown. It's a demonstration that we practice what we preach. We'll showcase this project in future posts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  A Critical Look: It's Not That Simple
&lt;/h3&gt;

&lt;p&gt;However, it's crucial to apply a critical eye to this proposal. The "Dual Web" approach is powerful, but it opens up an important technical debate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Shadow of "Cloaking":&lt;/strong&gt; The first thing a seasoned SEO expert will think is, "Isn't this cloaking?" Cloaking—showing different content to bots and humans to manipulate rankings—is a practice penalized by Google. The argument from Dual Web is that the &lt;strong&gt;intent&lt;/strong&gt; is not to deceive but to &lt;strong&gt;clarify&lt;/strong&gt;, and the substance of the information remains the same. It's a fine line. The current perspective is that as long as the goal is to improve accuracy and not to alter traditional search rankings, the risk is low. But this is a debate the SEO and AI communities will have to navigate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical Feasibility:&lt;/strong&gt; The implementation is not trivial. It requires server-level or edge-level access to intercept requests and rewrite responses based on user-agents. How can this be done in modern architectures?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;Vercel or Netlify,&lt;/strong&gt; you could use &lt;em&gt;Edge Functions&lt;/em&gt; to run this logic.&lt;/li&gt;
&lt;li&gt;With &lt;strong&gt;Cloudflare,&lt;/strong&gt; &lt;em&gt;Workers&lt;/em&gt; are the perfect tool for the job.&lt;/li&gt;
&lt;li&gt;On a &lt;strong&gt;VPS,&lt;/strong&gt; a configuration in Nginx or an application middleware (like the one we're developing with NestJS) is the way to go.
 The solution is not plug-and-play; it requires technical expertise.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Alternatives to Consider:&lt;/strong&gt; Is Dual Web the only way? No. Other alternatives could be:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extreme Structured Data (Schema.org):&lt;/strong&gt; Taking Schema.org markup to an obsessive level of detail to give AI as much context as possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt; Files:&lt;/strong&gt; A proposed standard (even mentioned in the Dual Web whitepaper itself) where you offer a curated summary of your site in a text file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content APIs:&lt;/strong&gt; Exposing your content through an API so AIs can consume it in a structured way.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion: The Next Step in Digital Evolution
&lt;/h3&gt;

&lt;p&gt;The AI era doesn't ask us to abandon SEO; it demands that we expand it. The concept of &lt;strong&gt;Generative Engine Optimization (GEO)&lt;/strong&gt; is already here, and strategies like "Dual Web" are at the forefront.&lt;/p&gt;

&lt;p&gt;It's no longer enough to write for humans and hope that machines will understand. We must be proactive, bilingual, and make their job easier. The reward is enormous: &lt;strong&gt;visibility, accuracy, and control over our brand's narrative&lt;/strong&gt; in the world's new default interface—the conversation with an AI.&lt;/p&gt;

&lt;p&gt;For those of us who make a living building and communicating in the digital world, the question is no longer &lt;em&gt;if&lt;/em&gt; we should optimize for AI, but &lt;em&gt;how&lt;/em&gt; and with what urgency. And the answer is: now.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>geo</category>
    </item>
    <item>
      <title>PostgreSQL 18 Uncovered: Asynchronous I/O, UUIDv7, and Pain-Free Upgrades</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Tue, 30 Sep 2025 11:32:41 +0000</pubDate>
      <link>https://dev.to/thedavestack/postgresql-18-uncovered-asynchronous-io-uuidv7-and-pain-free-upgrades-3kna</link>
      <guid>https://dev.to/thedavestack/postgresql-18-uncovered-asynchronous-io-uuidv7-and-pain-free-upgrades-3kna</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.thedavestack.com/postgresql-18/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As is tradition around this time of year, the global PostgreSQL community has surprised us with a new major version, and this time is no exception. On September 25th, the &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL Global Development Group&lt;/a&gt; officially released &lt;strong&gt;&lt;a href="https://www.postgresql.org/docs/18/release-18.html" rel="noopener noreferrer"&gt;PostgreSQL 18&lt;/a&gt;&lt;/strong&gt;. I'll tell you right now: it's one of the most exciting updates in recent years, especially if you're obsessed with performance and operational efficiency.&lt;/p&gt;

&lt;p&gt;In this article, we'll break down the official announcement to uncover the new features that will genuinely change the way we work—from developing custom software to deploying high-availability architectures. Forget minor tweaks; these are game-changing improvements. Let's dive in!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Key New Features in PostgreSQL 18
&lt;/h2&gt;

&lt;p&gt;After analyzing the announcement, I've identified four areas that I consider revolutionary.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 The Headliner: Asynchronous I/O (AIO) for a Massive Performance Boost
&lt;/h3&gt;

&lt;p&gt;This is the crown jewel of PostgreSQL 18. Until now, Postgres relied on the operating system's &lt;code&gt;readahead&lt;/code&gt; mechanisms to speed up data retrieval, but this isn't always efficient.&lt;/p&gt;

&lt;p&gt;PostgreSQL 18 introduces a &lt;strong&gt;new Asynchronous I/O (AIO) subsystem&lt;/strong&gt;. Instead of requesting a block of data and waiting, it can now issue multiple I/O requests in parallel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What does this mean?&lt;/strong&gt; For operations that read a lot of data from disk (like sequential scans, &lt;code&gt;VACUUM&lt;/code&gt;, etc.), the impact is huge. Community benchmarks have shown &lt;strong&gt;performance improvements of up to 3x&lt;/strong&gt; in certain scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you use it?&lt;/strong&gt; It's controlled by the new &lt;code&gt;io_method&lt;/code&gt; parameter, which lets you choose between different implementations like &lt;code&gt;io_uring&lt;/code&gt; (on Linux) or stick with the classic synchronous behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; If you have a read-intensive (I/O-bound) workload, like analytics systems or applications with large datasets, you're going to see a night-and-day difference.&lt;/p&gt;




&lt;h3&gt;
  
  
  😌 Upgrades Are Finally Pain-Free
&lt;/h3&gt;

&lt;p&gt;Anyone who has managed a production database knows the post-upgrade dread: queries run slow until &lt;code&gt;ANALYZE&lt;/code&gt; rebuilds the planner statistics. PostgreSQL 18 tackles this problem head-on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Statistics Preservation:&lt;/strong&gt; Finally! It's now possible to &lt;strong&gt;keep planner statistics during a major version upgrade&lt;/strong&gt;. This means your database will perform at its optimal level almost immediately after upgrading, eliminating that painful performance degradation phase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster &lt;code&gt;pg_upgrade&lt;/code&gt;:&lt;/strong&gt; The upgrade utility itself has been optimized. It can now run checks in parallel (&lt;code&gt;--jobs&lt;/code&gt;) and has a new &lt;code&gt;--swap&lt;/code&gt; option that exchanges data directories instead of copying them, dramatically speeding up the process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; The process of upgrading to a new major version will be much faster and less disruptive to your applications.&lt;/p&gt;




&lt;h3&gt;
  
  
  💻 Developer Gems You'll Love
&lt;/h3&gt;

&lt;p&gt;This release is packed with features that make our lives easier and allow us to write more modern and efficient code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Say Hello to &lt;code&gt;uuidv7()&lt;/code&gt;!:&lt;/strong&gt; A native function to generate v7 UUIDs has been added. Unlike random v4 UUIDs, v7 UUIDs are &lt;strong&gt;time-ordered&lt;/strong&gt;. Using them as primary keys drastically improves B-Tree index performance by reducing fragmentation and improving data locality. This is a fundamental change for high-insertion tables!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Generated Columns:&lt;/strong&gt; Generated columns (&lt;code&gt;GENERATED COLUMNS&lt;/code&gt;) are now virtual by default. This means the &lt;strong&gt;value is computed at query time&lt;/strong&gt; instead of being stored on disk, saving space for values that aren't needed constantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;RETURNING&lt;/code&gt; with &lt;code&gt;OLD&lt;/code&gt; and &lt;code&gt;NEW&lt;/code&gt;:&lt;/strong&gt; DML statements (&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;MERGE&lt;/code&gt;) can now access both the old (&lt;code&gt;OLD&lt;/code&gt;) and new (&lt;code&gt;NEW&lt;/code&gt;) values directly in the &lt;code&gt;RETURNING&lt;/code&gt; clause. This is fantastic for creating audit logs or implementing change data capture logic in a single query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; Native tools for modern design patterns that previously required more complex workarounds.&lt;/p&gt;




&lt;h3&gt;
  
  
  🛡️ Authentication, Security, and Important Changes to Note
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native OAuth 2.0 Support:&lt;/strong&gt; This is one of the hidden gems of the release, especially for professional environments. In practice, it means you can now authenticate database users through external identity providers like Auth0, Okta, Microsoft Entra ID (Azure AD), or Google. Technically, this is enabled directly in the &lt;code&gt;pg_hba.conf&lt;/code&gt; file with a new &lt;code&gt;oauth&lt;/code&gt; authentication method. You configure key parameters like the &lt;code&gt;issuer&lt;/code&gt; (your identity provider's URL) and the &lt;code&gt;scope&lt;/code&gt; (the permissions the access token must have). The token validation itself is modular and delegated to specialized libraries, making the system highly flexible. The result is that instead of managing local passwords, you can delegate authentication to your central Single Sign-On (SSO) system. This not only radically simplifies user management but also elevates security by enabling centralized policies like multi-factor authentication (MFA).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The End of an Era: MD5 Deprecation:&lt;/strong&gt; Although secure authentication with SCRAM has been available for several versions, PostgreSQL 18 takes the final step: it &lt;strong&gt;officially deprecates the use of MD5 for passwords&lt;/strong&gt;. Support will be completely removed in a future release, so there are no more excuses. The community's message is clear: if you're still using MD5, migrating to SCRAM is an urgent and high-priority task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default Checksums:&lt;/strong&gt; New clusters created with &lt;code&gt;initdb&lt;/code&gt; will now have &lt;strong&gt;page checksums enabled by default&lt;/strong&gt;. This improves data integrity but is a crucial detail to consider when planning an upgrade from a cluster without them.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  My Critical Perspective: What This Means for Your Projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is Asynchronous I/O a silver bullet?&lt;/strong&gt; No. It's a powerful tool for I/O-bound workloads. If your bottleneck is the CPU, you won't see a magical improvement. But for deploying analytics applications or AI services that process large volumes of data, the impact will be enormous.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Real Operational Game-Changer:&lt;/strong&gt; While AIO gets the headlines, I believe &lt;strong&gt;preserving statistics on upgrades is the single most important feature for production systems&lt;/strong&gt;. It eliminates one of the biggest headaches and risks associated with an upgrade, reducing uncertainty and making it easier to keep your tech stack up to date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Custom Software Development:&lt;/strong&gt; My recommendation is to start using &lt;strong&gt;&lt;code&gt;uuidv7()&lt;/code&gt; as the default primary key&lt;/strong&gt; on all new tables where it makes sense. It's an easy and free performance win. The improvements to &lt;code&gt;RETURNING&lt;/code&gt; will also greatly simplify audit logic in the backends I build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Ace Up Your Sleeve for Professional Projects (OAuth 2.0):&lt;/strong&gt; Don't underestimate this feature. If you build custom software for businesses, as I do, offering integration with their SSO system (like Microsoft 365 or Google Workspace) is no longer a nightmare. It's an enterprise-grade feature that now comes standard, allowing you to sell more secure and better-integrated projects into your clients' ecosystems. It's a powerful differentiator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immediate Call to Action:&lt;/strong&gt; Audit your systems. If you're still using MD5 authentication, &lt;strong&gt;plan your migration to SCRAM now&lt;/strong&gt;. This isn't a suggestion; it's an imminent security requirement.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Hands-On: Test PostgreSQL 18 with Docker and Examples
&lt;/h2&gt;

&lt;p&gt;To understand why the deprecation of MD5 is such a big deal, there's nothing like seeing it in action. We'll use Docker to set up a lab with two parallel instances of PostgreSQL 18: one configured to use the old and now-obsolete &lt;strong&gt;MD5&lt;/strong&gt; method, and another using the modern and secure &lt;strong&gt;SCRAM&lt;/strong&gt;, which has been the recommended method for years. This way, you can see the security difference for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;To execute these examples you will need to install &lt;a href="https://docs.docker.com/get-started/get-docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Set Up the Comparison Environment
&lt;/h3&gt;

&lt;p&gt;Create a file named &lt;code&gt;docker-compose.yml&lt;/code&gt;. Notice that we're defining the two databases (&lt;code&gt;db_md5&lt;/code&gt; and &lt;code&gt;db_scram&lt;/code&gt;), the &lt;code&gt;adminer&lt;/code&gt; web interface, and an extra container named &lt;code&gt;pg_client&lt;/code&gt; that will act as our toolbox with &lt;code&gt;psql&lt;/code&gt; pre-installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; (MD5 vs. SCRAM Comparison)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db_md5&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:18&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres18_md5&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres -c password_encryption=md5 -c io_method=sync&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;testdb&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres_data_md5:/var/lib/postgresql/data&lt;/span&gt;

  &lt;span class="na"&gt;db_scram&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:18&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres18_scram&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;testdb&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5433:5432"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres_data_scram:/var/lib/postgresql/data&lt;/span&gt;

  &lt;span class="na"&gt;pg_client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:18&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pg_client&lt;/span&gt;
    &lt;span class="c1"&gt;# This command keeps the container running so we can exec into it&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tail -f /dev/null&lt;/span&gt;

  &lt;span class="na"&gt;adminer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adminer&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres18_adminer&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres_data_md5&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres_data_scram&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a terminal, run &lt;code&gt;docker-compose up -d&lt;/code&gt; or &lt;code&gt;docker compose up -d&lt;/code&gt;. Your entire environment is now ready, with no need to install anything else on your machine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The password for the &lt;code&gt;user&lt;/code&gt; in all connections that require it (psql, Adminer) is &lt;code&gt;password&lt;/code&gt;, as defined in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Run the Examples and Compare
&lt;/h3&gt;

&lt;p&gt;For the terminal examples, we'll use our &lt;code&gt;pg_client&lt;/code&gt; container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to use the terminal:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a shell session inside the client container with this command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; pg_client bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Once inside (you'll see a prompt like &lt;code&gt;root@...:/#&lt;/code&gt;), you can run &lt;code&gt;psql&lt;/code&gt; commands against the databases using their service names (&lt;code&gt;db_scram&lt;/code&gt; or &lt;code&gt;db_md5&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Connect to the SCRAM (secure) instance:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal:&lt;/strong&gt; Inside the &lt;code&gt;pg_client&lt;/code&gt; container, run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_scram &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adminer (&lt;a href="http://localhost:8080/?pgsql=db_scram&amp;amp;username=user&amp;amp;db=testdb" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;):&lt;/strong&gt; Server: &lt;code&gt;db_scram&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h4&gt;
  
  
  Example 1: The new &lt;code&gt;uuidv7()&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Compare the results of the two UUID types&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;uuidv7&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the query a few times. You'll notice that &lt;code&gt;uuidv4()&lt;/code&gt; values are completely random, while &lt;code&gt;uuidv7()&lt;/code&gt; values start with a similar sequence that changes slightly. That initial part is the timestamp, which allows the index to sort them efficiently!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT uuidv4(), uuidv7();&lt;/span&gt;
                uuidv4                |                uuidv7                
&lt;span class="nt"&gt;--------------------------------------&lt;/span&gt;+--------------------------------------
 a3c361d2-4aa2-49fe-84fd-247d249484e0 | 019999e7-70ce-7e41-ad73-97cd6e42f2a8
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT uuidv4(), uuidv7();&lt;/span&gt;
                uuidv4                |                uuidv7                
&lt;span class="nt"&gt;--------------------------------------&lt;/span&gt;+--------------------------------------
 3c8115a7-8667-47e2-971c-b7ce61504572 | 019999e7-7713-75db-a7ff-e7c2ebbfb47f
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT uuidv4(), uuidv7();&lt;/span&gt;
                uuidv4                |                uuidv7                
&lt;span class="nt"&gt;--------------------------------------&lt;/span&gt;+--------------------------------------
 1fc5216d-a874-418b-abcb-0fd389823abc | 019999e7-7c0f-7a0a-a364-6a3a536a0b6c
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 2: Virtual Generated Columns
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price_eur&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price_usd&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="n"&gt;ALWAYS&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price_eur&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;07&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;VIRTUAL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price_eur&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Mechanical Keyboard'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;price_usd&lt;/code&gt; column doesn't take up disk space; it's calculated every time you query it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# CREATE TABLE products (&lt;/span&gt;
    name TEXT,
    price_eur NUMERIC,
    price_usd NUMERIC GENERATED ALWAYS AS &lt;span class="o"&gt;(&lt;/span&gt;price_eur &lt;span class="k"&gt;*&lt;/span&gt; 1.07&lt;span class="o"&gt;)&lt;/span&gt; VIRTUAL
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
CREATE TABLE
&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# INSERT INTO products (name, price_eur) VALUES ('Mechanical Keyboard', 80);&lt;/span&gt;
INSERT 0 1
&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT * FROM products;&lt;/span&gt;
        name         | price_eur | price_usd 
&lt;span class="nt"&gt;---------------------&lt;/span&gt;+-----------+-----------
 Mechanical Keyboard |        80 |     85.60
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 3: &lt;code&gt;RETURNING&lt;/code&gt; with &lt;code&gt;OLD&lt;/code&gt; and &lt;code&gt;NEW&lt;/code&gt; Values
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;price_audit&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;old_price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;new_price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;changed_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;price_eur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mechanical Keyboard'&lt;/span&gt;
    &lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price_eur&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;old_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price_eur&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;new_price&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;price_audit&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_price&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;price_audit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's like magic! No complex triggers or double queries needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# CREATE TABLE price_audit (&lt;/span&gt;
    product_name TEXT,
    old_price NUMERIC,
    new_price NUMERIC,
    changed_at TIMESTAMPTZ DEFAULT now&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
CREATE TABLE
&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# WITH updated AS (&lt;/span&gt;
    UPDATE products
    SET price_eur &lt;span class="o"&gt;=&lt;/span&gt; 85
    WHERE name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mechanical Keyboard'&lt;/span&gt;
    RETURNING OLD.name, OLD.price_eur AS old_price, NEW.price_eur AS new_price
&lt;span class="o"&gt;)&lt;/span&gt;
INSERT INTO price_audit &lt;span class="o"&gt;(&lt;/span&gt;product_name, old_price, new_price&lt;span class="o"&gt;)&lt;/span&gt;
SELECT name, old_price, new_price FROM updated&lt;span class="p"&gt;;&lt;/span&gt;
INSERT 0 1
&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT * FROM price_audit;&lt;/span&gt;
    product_name     | old_price | new_price |          changed_at           
&lt;span class="nt"&gt;---------------------&lt;/span&gt;+-----------+-----------+-------------------------------
 Mechanical Keyboard |        80 |        85 | 2025-09-30 09:16:50.260192+00
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Experimenting with Asynchronous I/O (AIO)
&lt;/h3&gt;

&lt;p&gt;Demonstrating a performance improvement like AIO in a simple example is tricky, as it heavily depends on your hardware (especially your disk speed). However, we can set up a small lab for you to experiment and measure the impact on your own system.&lt;/p&gt;

&lt;p&gt;With our Docker setup, we have the perfect lab: the &lt;code&gt;db_md5&lt;/code&gt; service starts with synchronous I/O (&lt;code&gt;io_method=sync&lt;/code&gt;), and the &lt;code&gt;db_scram&lt;/code&gt; service uses the PostgreSQL 18 default, which is with AIO enabled.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Prepare a Large Dataset
&lt;/h4&gt;

&lt;p&gt;We'll use &lt;strong&gt;pgbench&lt;/strong&gt;, a tool included with PostgreSQL, to create test data in &lt;strong&gt;both&lt;/strong&gt; instances.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From your terminal, run these two commands. Each will take a couple of minutes to populate its respective database with ~1.5 GB of data:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;# Populate the database WITHOUT AIO (db_md5)&lt;/span&gt;
  docker &lt;span class="nb"&gt;exec &lt;/span&gt;pg_client bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"PGPASSWORD=password pgbench -i -s 100 -h db_md5 -U user testdb"&lt;/span&gt;

  &lt;span class="c"&gt;# Populate the database WITH AIO (db_scram)&lt;/span&gt;
  docker &lt;span class="nb"&gt;exec &lt;/span&gt;pg_client bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"PGPASSWORD=password pgbench -i -s 100 -h db_scram -U user testdb"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Run the Tests and Compare
&lt;/h4&gt;

&lt;p&gt;For a fair comparison, we'll first restart both containers to clear memory caches.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From your terminal, run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  docker restart postgres18_md5 postgres18_scram
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Wait a few seconds for the databases to start up.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, enter the client container to run the tests:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; pg_client bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test on the server WITHOUT AIO:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;# Connect to db_md5 and measure the time&lt;/span&gt;
  &lt;span class="nv"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_md5 &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;iming on"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT count(*) FROM pgbench_accounts;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Take note of the time it returns.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  root@5dfdfaef5e1a:/# &lt;span class="nv"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_md5 &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;iming on"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT count(*) FROM pgbench_accounts;"&lt;/span&gt;
  Timing is on.
    count   
  &lt;span class="nt"&gt;----------&lt;/span&gt;
   10000000
  &lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

  Time: 828.820 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test on the server WITH AIO:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;# Connect to db_scram and measure the time&lt;/span&gt;
  &lt;span class="nv"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_scram &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;iming on"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT count(*) FROM pgbench_accounts;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Take note of this second time.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  root@5dfdfaef5e1a:/# &lt;span class="nv"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_scram &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;iming on"&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT count(*) FROM pgbench_accounts;"&lt;/span&gt;
  Timing is on.
    count   
  &lt;span class="nt"&gt;----------&lt;/span&gt;
   10000000
  &lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

  Time: 539.800 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Analyze the Results
&lt;/h4&gt;

&lt;p&gt;Compare the time from the second test (WITH AIO) with the first (WITHOUT AIO). On a system with fast disks (SSD/NVMe), you &lt;strong&gt;should see a noticeable reduction in execution time&lt;/strong&gt;. In my case, the time dropped from &lt;strong&gt;828.820 ms&lt;/strong&gt; to &lt;strong&gt;539.800 ms&lt;/strong&gt;, an improvement of &lt;strong&gt;34.87%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The improvement you see will depend heavily on your hardware, operating system, and Docker configuration. The goal of this experiment is to give you the tools to measure it in your own environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: The Definitive Authentication Comparison
&lt;/h3&gt;

&lt;p&gt;Now, let's create a user on each database to see the crucial difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. On the MD5 (insecure) instance:&lt;/strong&gt;&lt;br&gt;
Connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal:&lt;/strong&gt; Inside the &lt;code&gt;pg_client&lt;/code&gt; container, run:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_md5 &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adminer:&lt;/strong&gt; Server: &lt;code&gt;db_md5&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And run the following SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;test_md5_user&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="s1"&gt;'a_simple_password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;rolname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rolpassword&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_authid&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;rolname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'test_md5_user'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result will show the easily identifiable MD5 hash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# CREATE USER test_md5_user WITH PASSWORD 'a_simple_password';&lt;/span&gt;
WARNING:  setting an MD5-encrypted password
DETAIL:  MD5 password support is deprecated and will be removed &lt;span class="k"&gt;in &lt;/span&gt;a future release of PostgreSQL.
HINT:  Refer to the PostgreSQL documentation &lt;span class="k"&gt;for &lt;/span&gt;details about migrating to another password type.
CREATE ROLE
&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT rolname, rolpassword FROM pg_authid WHERE rolname = 'test_md5_user';&lt;/span&gt;
    rolname    |             rolpassword             
&lt;span class="nt"&gt;---------------&lt;/span&gt;+-------------------------------------
 test_md5_user | md5fb0260dca3cede73533e7b3a2878807b
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. On the SCRAM (secure) instance:&lt;/strong&gt;&lt;br&gt;
Connect to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal:&lt;/strong&gt; Inside the &lt;code&gt;pg_client&lt;/code&gt; container, run:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  psql &lt;span class="nt"&gt;-h&lt;/span&gt; db_scram &lt;span class="nt"&gt;-U&lt;/span&gt; user &lt;span class="nt"&gt;-d&lt;/span&gt; testdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adminer:&lt;/strong&gt; Server: &lt;code&gt;db_scram&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And run this other SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;test_scram_user&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="s1"&gt;'a_better_password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;rolname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rolpassword&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_authid&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;rolname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'test_scram_user'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is radically different and much more robust:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# CREATE USER test_scram_user WITH PASSWORD 'a_better_password';&lt;/span&gt;
CREATE ROLE
&lt;span class="nv"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c"&gt;# SELECT rolname, rolpassword FROM pg_authid WHERE rolname = 'test_scram_user';&lt;/span&gt;
     rolname     |                                                              rolpassword                                                              
&lt;span class="nt"&gt;-----------------&lt;/span&gt;+---------------------------------------------------------------------------------------------------------------------------------------
 test_scram_user | SCRAM-SHA-256&lt;span class="nv"&gt;$4096&lt;/span&gt;:aZ2+SHpETCGDXKENOKupcA&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="nv"&gt;$RlOpd&lt;/span&gt;+bI6rtWQmrqsQg69v7m1A1WPeL+tYqG1IUz9wk&lt;span class="o"&gt;=&lt;/span&gt;:hJfldXgHIIhsZR35pzJ5EiGbp7MPGEKkljho2Ju2dxY&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This side-by-side comparison leaves no room for doubt. With a single &lt;code&gt;docker-compose up&lt;/code&gt; command, we've created a perfect lab to visualize why the community has finally decided to pull the plug on MD5 and why SCRAM is the standard you should already be using.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;PostgreSQL 18 is a mature and impactful release. It doesn't focus on adding hundreds of minor features but instead on solving fundamental problems at scale: I/O performance, the pain of upgrades, and efficiency in modern development patterns.&lt;/p&gt;

&lt;p&gt;It's a statement of intent that solidifies PostgreSQL not just as a robust and reliable database, but as a high-performance data platform ready for the challenges of the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now it's your turn. What feature are you most excited about? Are you going to start testing Asynchronous I/O? Let me know in the comments!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Source and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Official Announcement:&lt;/strong&gt; &lt;a href="https://www.postgresql.org/about/news/postgresql-18-released-3142/" rel="noopener noreferrer"&gt;PostgreSQL 18 Released!&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>docker</category>
    </item>
    <item>
      <title>Don't Miss the Java 25 Launch Livestream Today!</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Tue, 16 Sep 2025 07:50:23 +0000</pubDate>
      <link>https://dev.to/thedavestack/dont-miss-the-java-25-launch-livestream-today-5e1d</link>
      <guid>https://dev.to/thedavestack/dont-miss-the-java-25-launch-livestream-today-5e1d</guid>
      <description>&lt;p&gt;Today is a big day for the Java community! The official launch livestream for Java 25 is happening, and the schedule is packed with deep dives into the new features and the future of the platform.&lt;/p&gt;

&lt;p&gt;Here's everything you need to know to catch the event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When:&lt;/strong&gt; Today, September 16th, starting at 15:00 UTC.&lt;br&gt;
&lt;strong&gt;Where to Watch:&lt;/strong&gt; &lt;a href="https://dev.java/community/java-25-launch/" rel="noopener noreferrer"&gt;Official Event Page&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Livestream Schedule (UTC)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;15:00&lt;/strong&gt; - Welcome and Event Agenda 🗓️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15:05&lt;/strong&gt; - Performance Updates from Java 21 to 25 📈&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15:15&lt;/strong&gt; - Method Timing &amp;amp; Tracing with JDK Flight Recorder ✈️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15:25&lt;/strong&gt; - Using Flexible Constructor Bodies 🤸&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15:30&lt;/strong&gt; - Exploring Java's On-Ramp and Scripting Features 🧩&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15:50&lt;/strong&gt; - Amber, OpenJDK, and Community 🌎&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;16:15&lt;/strong&gt; - Upgrading to Java 25 ⬆️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;16:25&lt;/strong&gt; - Security Updates 🔐&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;16:40&lt;/strong&gt; - Scoped Values 🔬&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;16:50&lt;/strong&gt; - Stream Gatherers 🌊&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;17:10&lt;/strong&gt; - Evolution of Java AI Libraries 📚&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;17:20&lt;/strong&gt; - Ahead-of-Time In-Action 🏋️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;17:25&lt;/strong&gt; - Beyond Java 21 at Netflix Scale 🍿&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;17:55&lt;/strong&gt; - API Updates Post-Java 21 🔌&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18:10&lt;/strong&gt; - Java for AI 🤖&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18:40&lt;/strong&gt; - Growing the Java Platform ☕️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18:55&lt;/strong&gt; - Closing 🏁&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What About You?
&lt;/h2&gt;

&lt;p&gt;Which talks are on your must-watch list? Are there any specific JEPs you've been following that are landing in Java 25?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drop your thoughts in the comments below!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>news</category>
      <category>developer</category>
    </item>
    <item>
      <title>Designing APIs for the AI Era with Spring AI and MCP</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Mon, 08 Sep 2025 08:59:32 +0000</pubDate>
      <link>https://dev.to/thedavestack/designing-apis-for-the-ai-era-with-spring-ai-and-mcp-3ahg</link>
      <guid>https://dev.to/thedavestack/designing-apis-for-the-ai-era-with-spring-ai-and-mcp-3ahg</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.thedavestack.com/spring-ai-mcp/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As backend developers, we've been building robust REST APIs for years. We design them to be consumed by our UIs, mobile apps, or other microservices. It's a paradigm we've mastered. But what if I told you that with minimal effort, that same API could have a second interface—one that allows AI agents to interact with your business logic using natural language?&lt;/p&gt;

&lt;p&gt;Today, thinking about artificial intelligence isn't an afterthought; it's a design strategy. It's not just about creating a service that responds to GET or POST requests, but about asking ourselves: &lt;strong&gt;how can an AI model consume my service to provide extra value?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For those of us developing with Java, thanks to &lt;strong&gt;Spring AI&lt;/strong&gt;, this idea has shifted from a complex task to a simple extension of what we already do. In this post, we'll explore how incredibly easy it is to add an &lt;strong&gt;MCP (Model Context Protocol) Server&lt;/strong&gt; to an existing Spring Boot application, using a real-world API for managing a product catalog as our example.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dual API Paradigm: REST for Machines, MCP for AI 🤖
&lt;/h2&gt;

&lt;p&gt;A REST API is great for structured machine-to-machine communication. But an AI agent doesn't think in terms of JSON or endpoints.&lt;/p&gt;

&lt;p&gt;This is where the MCP Server comes in. It acts as a translator, exposing your application's logic in a way that an LLM (Large Language Model) can understand and use. This allows you to have the best of both worlds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your traditional REST API&lt;/strong&gt;, stable and reliable for your applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An MCP Server&lt;/strong&gt;, offering a native interface for AI integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach forces you to design from the outset with the functions (&lt;code&gt;Tools&lt;/code&gt;), data (&lt;code&gt;Resources&lt;/code&gt;), and guides (&lt;code&gt;Prompts&lt;/code&gt;) that an intelligent agent would need to operate autonomously within your domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Model Context Protocol?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Model Context Protocol&lt;/strong&gt; (MCP) is the standard that defines how an AI model can discover and use your application's capabilities in a secure and structured way. It provides the AI with the necessary &lt;strong&gt;context&lt;/strong&gt; about what actions it can perform and what information it can query.&lt;/p&gt;

&lt;p&gt;This protocol is built on three pillars: &lt;strong&gt;Tools, Resources, and Prompts&lt;/strong&gt;. If you want to dive deeper into how it works and what each of these concepts means, you can read my more detailed post: &lt;strong&gt;&lt;a href="https://es.thedavestack.com/model-context-protocol-exposed/" rel="noopener noreferrer"&gt;Model Context Protocol Exposed: The Power of Resources and Prompts Beyond Tools&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For this article, the key takeaway is seeing how easy it is to implement these three pillars with Spring AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  From @RestController to MCP Server
&lt;/h2&gt;

&lt;p&gt;To demonstrate this, I'll use my &lt;a href="https://github.com/The-Dave-Stack/product-catalog" rel="noopener noreferrer"&gt;Product Catalog&lt;/a&gt; project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 0: Build Your Traditional Spring Boot Service
&lt;/h3&gt;

&lt;p&gt;I won't spend much time on this point because creating the foundation for a Spring Boot project is almost trivial using &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;https://start.spring.io/&lt;/a&gt;. I'll also leave a link to their documentation if you want more details: &lt;a href="https://spring.io/guides/gs/spring-boot" rel="noopener noreferrer"&gt;Getting Started | Building an Application with Spring Boot&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Configuration is a Breeze
&lt;/h3&gt;

&lt;p&gt;Once you have your Spring Boot service, you just need to add the Spring AI dependency and enable the server. To manage versions centrally, we add the Spring AI "Bill of Materials" (BOM) to the &lt;code&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/code&gt; section of your &lt;code&gt;pom.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;  
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;  
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;  
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;  
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;  
            &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;  
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;  
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in your &lt;code&gt;&amp;lt;dependencies&amp;gt;&lt;/code&gt; section, you only need to add the MCP server &lt;a href="https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_starters" rel="noopener noreferrer"&gt;starter&lt;/a&gt;, which in this case is &lt;code&gt;spring-ai-starter-mcp-server-webmvc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;  
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;  
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-starter-mcp-server-webmvc&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in your &lt;code&gt;application.properties&lt;/code&gt;, you enable and configure the server. It's that simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# application.properties
&lt;/span&gt;
&lt;span class="c"&gt;# Enable the MCP server  
&lt;/span&gt;&lt;span class="py"&gt;spring.ai.mcp.server.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true  &lt;/span&gt;
&lt;span class="py"&gt;spring.ai.mcp.server.name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;product-catalog-mcp-server  &lt;/span&gt;
&lt;span class="py"&gt;spring.ai.mcp.server.version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;

&lt;span class="c"&gt;# Define general instructions for the AI  
&lt;/span&gt;&lt;span class="py"&gt;spring.ai.mcp.server.instructions&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;A server for managing a product catalog with AI-powered tools, resources, and guides.&lt;/span&gt;

&lt;span class="c"&gt;# Enable the capabilities you want to expose  
&lt;/span&gt;&lt;span class="py"&gt;spring.ai.mcp.server.capabilities.tool&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true  &lt;/span&gt;
&lt;span class="py"&gt;spring.ai.mcp.server.capabilities.resource&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true  &lt;/span&gt;
&lt;span class="py"&gt;spring.ai.mcp.server.capabilities.prompt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With just these few lines, your application now has a functional MCP server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Implementing the MCP Features
&lt;/h3&gt;

&lt;p&gt;Now that we have the Spring AI dependencies and the MCP starter, it's time to dive in.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2.1: Expose Your Services as Tools&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You already have the business logic in your &lt;code&gt;@Service&lt;/code&gt; classes. To expose a method as a tool for the AI, you just need one annotation: &lt;code&gt;@Tool&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="s"&gt;"Creates a new product in the catalog with comprehensive validation and audit logging. Required fields: name, price, category, stockQuantity, minStockLevel. Optional fields: description, SKU (auto-generated if not provided), weight, dimensions, imageUrl. SKU must be globally unique if provided. Automatically creates audit log entry. Throws DuplicateSkuException for duplicate SKUs. Use this for adding new products to the inventory system."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Transactional&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="nf"&gt;createProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="s"&gt;"Product object with required fields: name, price, category, stockQuantity, minStockLevel. Optional: description, sku, weight, dimensions, imageUrl"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! Your &lt;code&gt;createProduct&lt;/code&gt; method is now a tool that any AI agent can invoke.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2.2: Expose Live Data with Resources&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;A &lt;code&gt;Resource&lt;/code&gt; acts as a live data feed for the AI. Instead of having static data in a prompt, you can expose information that changes within your application, like a list of product categories.&lt;/p&gt;

&lt;p&gt;To do this, we define a &lt;code&gt;URI&lt;/code&gt; (e.g., &lt;code&gt;categories://overview/all&lt;/code&gt;) and associate it with a function that returns the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncResourceSpecification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getResourceSpecifications&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;// All categories overview resource&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncResourceSpecification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                            &lt;span class="s"&gt;"categories://overview/all"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="s"&gt;"All Categories Overview"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="s"&gt;"Complete overview of all product categories with descriptions and guidelines"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;getAllCategoriesResource&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="o"&gt;...&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ReadResourceResult&lt;/span&gt; &lt;span class="nf"&gt;getAllCategoriesResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;McpSyncServerExchange&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ReadResourceRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;categoriesInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;createCategoryOverview&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;jsonContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeValueAsString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                &lt;span class="s"&gt;"totalCategories"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="s"&gt;"categories"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;categoriesInfo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="s"&gt;"Complete catalog of product categories with their descriptions and key characteristics"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="s"&gt;"lastUpdated"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ReadResourceResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TextResourceContents&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonContent&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to get all categories resource"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to retrieve categories overview"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;2.3: Expose Your Workflows with Prompts&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Prompts&lt;/code&gt; are structured guides that teach the AI how to perform complex, multi-step tasks. They are like pre-designed prompt templates that you can invoke, combining instructions, data from &lt;code&gt;Resources&lt;/code&gt;, and &lt;code&gt;Tools&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Imagine you want a guide for analyzing inventory. You could create a &lt;code&gt;Prompt&lt;/code&gt; named &lt;code&gt;inventory-analysis&lt;/code&gt; that instructs the AI to first fetch low-stock products (using a &lt;code&gt;Tool&lt;/code&gt;) and then generate a report.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncPromptSpecification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getPromptSpecifications&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;...&lt;/span&gt;

            &lt;span class="c1"&gt;// Inventory analysis prompt&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncPromptSpecification&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Prompt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                            &lt;span class="s"&gt;"inventory-analysis"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="s"&gt;"Inventory Analysis and Recommendations"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PromptArgument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                            &lt;span class="s"&gt;"analysisType"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                            &lt;span class="s"&gt;"Type of analysis (stock-health/reorder/turnover)"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                            &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PromptArgument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                            &lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Focus on specific category"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt;
                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;createInventoryAnalysisPrompt&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;

            &lt;span class="o"&gt;...&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GetPromptResult&lt;/span&gt; &lt;span class="nf"&gt;createInventoryAnalysisPrompt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;McpSyncServerExchange&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GetPromptRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;analysisType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"analysisType"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ALL"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;promptText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createInventoryAnalysisPromptText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analysisType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PromptMessage&lt;/span&gt; &lt;span class="n"&gt;promptMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PromptMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ASSISTANT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TextContent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;promptText&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GetPromptResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Inventory analysis guidance for "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;analysisType&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" analysis"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;promptMessage&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to create inventory analysis prompt"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to generate inventory analysis prompt"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;createInventoryAnalysisPromptText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;analysisType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analysisType&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"stock-health"&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"""
            You are an inventory management specialist conducting a stock health analysis%s.

            ## Stock Health Analysis Framework

            ### Key Metrics to Evaluate:
            1. **Out of Stock Items** - Immediate attention required
            2. **Low Stock Warnings** - Items below minimum levels
            3. **Overstock Situations** - Items with excessive inventory
            4. **Stock Turnover Rates** - How quickly inventory moves
            5. **Dead Stock** - Items with no recent sales

            ### Analysis Process:
            1. Retrieve current inventory levels using available tools
            2. Compare against minimum stock thresholds
            3. Identify critical alerts requiring immediate action
            4. Calculate stock health scores by category
            5. Generate actionable recommendations

            ### Recommended Actions:
            - **Critical**: Immediate reorders for out-of-stock items
            - **Warning**: Schedule reorders for low-stock items
            - **Optimization**: Review slow-moving inventory for discounts
            - **Planning**: Adjust minimum stock levels based on trends

            Please conduct a comprehensive stock health analysis and provide prioritized recommendations.
            """&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ALL"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;" for "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" category"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"reorder"&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"""
            You are a procurement specialist developing reorder recommendations%s.

            ## Reorder Analysis Framework

            ### Reorder Triggers:
            1. Current stock ≤ minimum stock level
            2. Projected stockouts based on demand trends
            3. Lead time considerations
            4. Economic order quantities
            5. Seasonal demand adjustments

            ### Analysis Steps:
            1. Identify products below reorder points
            2. Calculate optimal order quantities
            3. Consider supplier minimums and volume discounts
            4. Factor in lead times and safety stock
            5. Prioritize based on sales velocity and margin

            ### Reorder Recommendations:
            - High priority: Fast-moving items near stockout
            - Medium priority: Steady sellers below minimum
            - Low priority: Slow movers with adequate runway

            Please generate a prioritized reorder plan with specific quantities and timing.
            """&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ALL"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;" for "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" category"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"turnover"&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"""
            You are a financial analyst evaluating inventory turnover performance%s.

            ## Inventory Turnover Analysis

            ### Key Calculations:
            1. **Turnover Ratio** = Cost of Goods Sold / Average Inventory Value
            2. **Days Sales Inventory** = 365 / Turnover Ratio
            3. **Stock Velocity** = Units Sold / Average Units in Stock
            4. **Carrying Cost Impact** = Average Inventory × Carrying Cost Rate

            ### Performance Benchmarks:
            - Electronics: 8-12 turns/year (Fast-moving technology)
            - Books: 3-5 turns/year (Diverse demand patterns)
            - Clothing: 4-6 turns/year (Seasonal collections)
            - General: 6-8 turns/year (Standard retail)

            ### Analysis Focus:
            1. Compare actual vs. target turnover rates
            2. Identify slow-moving inventory
            3. Calculate carrying cost implications
            4. Recommend optimization strategies

            Please analyze turnover performance and suggest improvements for capital efficiency.
            """&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ALL"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;" for "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" category"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Please specify analysis type: stock-health, reorder, or turnover."&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Configure the Beans to Expose Everything
&lt;/h3&gt;

&lt;p&gt;Once you have all the pieces, exposing &lt;code&gt;Tools&lt;/code&gt;, &lt;code&gt;Resources&lt;/code&gt;, and &lt;code&gt;Prompts&lt;/code&gt; is as simple as creating Spring Beans for them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductCatalogSpringApplication&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductCatalogSpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ToolCallbackProvider&lt;/span&gt; &lt;span class="nf"&gt;productCatalogTools&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductService&lt;/span&gt; &lt;span class="n"&gt;productService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MethodToolCallbackProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toolObjects&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productService&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncResourceSpecification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;productCatalogResources&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncResourceSpecification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;productCatalogResources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;productCatalogResources&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;McpServerFeatures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SyncPromptSpecification&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;productCatalogPrompts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;ProductManagementPromptProvider&lt;/span&gt; &lt;span class="n"&gt;productManagementPromptProvider&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;productManagementPromptProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPromptSpecifications&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these simple steps, you've built a direct and secure bridge between your business logic and the world of AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: The Next Natural Step for Your APIs
&lt;/h2&gt;

&lt;p&gt;As we've seen, adding an MCP Server to your Spring Boot application isn't a Herculean task. It's the next logical step in the evolution of our services. Spring AI abstracts away all the complexity, allowing us to reuse the code we already have to open our applications to a universe of new possibilities with artificial intelligence.&lt;/p&gt;

&lt;p&gt;Designing with AI in mind from the start is no longer an option—it's a competitive advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next? Your Turn to Act 🚀
&lt;/h2&gt;

&lt;p&gt;I hope this post has inspired you to look at your APIs from a new perspective. Here are a few ideas to get you started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Explore the source code&lt;/strong&gt;: All the code from this example is available in my &lt;a href="https://github.com/The-Dave-Stack/product-catalog" rel="noopener noreferrer"&gt;&lt;strong&gt;Product Catalog API&lt;/strong&gt;&lt;/a&gt; GitHub repository. Clone it, run it with Docker, and experiment for yourself. The best way to learn is by doing!&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start small&lt;/strong&gt;: You don't need a complex architecture. Pick a key method from one of your current Spring Boot applications and try exposing it as a &lt;code&gt;@Tool&lt;/code&gt;. You'll see how simple it is.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Join the conversation&lt;/strong&gt;: What do you think of this approach to AI-native APIs? What other use cases can you think of for an MCP Server in your projects?&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Dive into the documentation&lt;/strong&gt;: If you want to learn all the details, the &lt;a href="https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html" rel="noopener noreferrer"&gt;&lt;strong&gt;official Spring AI documentation&lt;/strong&gt;&lt;/a&gt; is the best place to keep learning.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;The internet is full of articles that can also help you learn more about the world of Spring AI and MCP. Here are a couple I've found very interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/spring-ai-model-context-protocol-mcp" rel="noopener noreferrer"&gt;Exploring Model Context Protocol (MCP) With Spring AI | Baeldung&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/blog/2025/05/04/spring-ai-dynamic-tool-updates-with-mcp" rel="noopener noreferrer"&gt;Dynamic Tool Updates in Spring AI's Model Context Protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>springboot</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Transform Project Management with Git and AI: backlog.md</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Wed, 27 Aug 2025 09:51:20 +0000</pubDate>
      <link>https://dev.to/thedavestack/transform-project-management-with-git-and-ai-backlogmd-28d0</link>
      <guid>https://dev.to/thedavestack/transform-project-management-with-git-and-ai-backlogmd-28d0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.thedavestack.com/backlog-md/" rel="noopener noreferrer"&gt;Original post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;In modern software development, project management usually lives separately from the code itself. Tools like &lt;a href="https://www.atlassian.com/software/jira" rel="noopener noreferrer"&gt;JIRA&lt;/a&gt;, &lt;a href="https://asana.com/" rel="noopener noreferrer"&gt;Asana&lt;/a&gt;, &lt;a href="https://monday.com/" rel="noopener noreferrer"&gt;Monday&lt;/a&gt;, &lt;a href="https://clickup.com/" rel="noopener noreferrer"&gt;ClickUp&lt;/a&gt;, or &lt;a href="https://trello.com/" rel="noopener noreferrer"&gt;Trello&lt;/a&gt; are the industry standard for managing tasks. However, this practice, while powerful, creates a disconnect from where the magic really happens: the code repository. It often forces developers to lose focus by context-switching.&lt;/p&gt;

&lt;p&gt;What if you could stay focused and manage the entire project—tasks, documentation, and decisions—directly from the command line, using Markdown files and a Git-native approach?&lt;/p&gt;

&lt;p&gt;Today, we're going to explore a tool that does just that. 🚀&lt;/p&gt;




&lt;h3&gt;
  
  
  Backlog.md: Git-Native Project Management
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/MrLesk/Backlog.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Backlog.md&lt;/strong&gt;&lt;/a&gt; is an innovative command-line interface (CLI) tool that transforms any Git repository into a self-contained project board. Its approach is simple yet revolutionary: it uses Markdown files to manage everything, allowing project administration to live directly inside your code, versioned and accessible to anyone with access to the repository.&lt;/p&gt;

&lt;h4&gt;
  
  
  Principles and Architecture
&lt;/h4&gt;

&lt;p&gt;Built with &lt;a href="https://bun.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Bun&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/a&gt;, &lt;code&gt;backlog.md&lt;/code&gt; is a zero-configuration npm package. All tasks, drafts, documents, and decisions are stored as Markdown files with YAML metadata in a &lt;code&gt;backlog/&lt;/code&gt; directory. This means every change to the project is a Git commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
└── backlog
    ├── archive
    │   ├── drafts
    │   └── tasks
    ├── completed
    ├── config.yml
    ├── decisions
    ├── docs
    ├── drafts
    └── tasks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its CLI, based on &lt;a href="https://www.npmjs.com/package/commander" rel="noopener noreferrer"&gt;&lt;strong&gt;Commander.js&lt;/strong&gt;&lt;/a&gt;, offers an intuitive set of commands for the entire project lifecycle, from &lt;code&gt;backlog task create&lt;/code&gt; to &lt;code&gt;backlog board view&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;backlog &lt;span class="nt"&gt;--help&lt;/span&gt;
Usage: backlog &lt;span class="o"&gt;[&lt;/span&gt;options] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

Backlog.md - Project management CLI

Options:
  &lt;span class="nt"&gt;-v&lt;/span&gt;, &lt;span class="nt"&gt;--version&lt;/span&gt;           display version number
  &lt;span class="nt"&gt;-h&lt;/span&gt;, &lt;span class="nt"&gt;--help&lt;/span&gt;              display &lt;span class="nb"&gt;help &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;command

&lt;/span&gt;Commands:
  init &lt;span class="o"&gt;[&lt;/span&gt;options] &lt;span class="o"&gt;[&lt;/span&gt;projectName]   initialize backlog project &lt;span class="k"&gt;in &lt;/span&gt;the current repository
  task|tasks &lt;span class="o"&gt;[&lt;/span&gt;options] &lt;span class="o"&gt;[&lt;/span&gt;taskId]
  draft &lt;span class="o"&gt;[&lt;/span&gt;options] &lt;span class="o"&gt;[&lt;/span&gt;taskId]
  board &lt;span class="o"&gt;[&lt;/span&gt;options]           display tasks &lt;span class="k"&gt;in &lt;/span&gt;a Kanban board
  doc
  decision
  agents &lt;span class="o"&gt;[&lt;/span&gt;options]          manage agent instruction files
  config
  cleanup                   move completed tasks to completed folder based on age
  browser &lt;span class="o"&gt;[&lt;/span&gt;options]         open browser interface &lt;span class="k"&gt;for &lt;/span&gt;task management &lt;span class="o"&gt;(&lt;/span&gt;press Ctrl+C or Cmd+C to stop&lt;span class="o"&gt;)&lt;/span&gt;
  overview                  display project statistics and metrics
  &lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;            display &lt;span class="nb"&gt;help &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key Features That Make a Difference
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hierarchical Task Management&lt;/strong&gt;: Tasks are organized with a clear numbering system (e.g., &lt;code&gt;task-42&lt;/code&gt;, &lt;code&gt;task-42.1&lt;/code&gt;), facilitating parent-child relationships and the breakdown of complex problems.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;backlog task create &lt;span class="s2"&gt;"Parent Test task"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"This is the parent test task description"&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt; &lt;span class="nt"&gt;--ac&lt;/span&gt; &lt;span class="s2"&gt;"ac1,ac2,ac3"&lt;/span&gt;
Created task task-1
File: /home/kratos/Development/the-dave-stack/social/backlog.md/backlog/tasks/task-1 - Parent-Test-task.md
&lt;span class="nv"&gt;$ &lt;/span&gt;backlog task create &lt;span class="s2"&gt;"Child Test task"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"This is the child test task description"&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt; &lt;span class="nt"&gt;--ac&lt;/span&gt; &lt;span class="s2"&gt;"ac1,ac2,ac3"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"task-1"&lt;/span&gt;
Created task task-1.1
File: /home/kratos/Development/the-dave-stack/social/backlog.md/backlog/tasks/task-1.1 - Child-Test-task.md
&lt;span class="nv"&gt;$ &lt;/span&gt;tree &lt;span class="nt"&gt;-L&lt;/span&gt; 3 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
└── backlog
    ├── archive
    │   ├── drafts
    │   └── tasks
    ├── completed
    ├── config.yml
    ├── decisions
    ├── docs
    ├── drafts
    └── tasks
        ├── task-1.1 - Child-Test-task.md
        └── task-1 - Parent-Test-task.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Focus on Outcomes&lt;/strong&gt;: One of its best ideas is the distinction between &lt;strong&gt;Acceptance Criteria&lt;/strong&gt; (the &lt;em&gt;what&lt;/em&gt; must be achieved, in a measurable way) and &lt;strong&gt;Implementation Plans&lt;/strong&gt; (the &lt;em&gt;how&lt;/em&gt; it will be technically solved). This brings immense clarity to the process.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task-1&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Parent Test task&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;To Do&lt;/span&gt;
&lt;span class="na"&gt;assignee&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="na"&gt;created_date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2025-08-23&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;14:20'&lt;/span&gt;
&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gu"&gt;## Description&lt;/span&gt;

This is the parent test task description

&lt;span class="gu"&gt;## Acceptance Criteria&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] ac1
&lt;span class="p"&gt;-&lt;/span&gt; [ ] ac2
&lt;span class="p"&gt;-&lt;/span&gt; [ ] ac3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Designed for AI&lt;/strong&gt;: &lt;code&gt;backlog.md&lt;/code&gt; treats AI agents as first-class citizens. It provides structured plain-text outputs and even instruction files (&lt;code&gt;AGENTS.md&lt;/code&gt;) to guide language models, preparing them for true collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Git Integration&lt;/strong&gt;: Every operation is an atomic and descriptive commit. Its ability to synchronize tasks between different branches is simply brilliant, intelligently resolving conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Interface&lt;/strong&gt;: Although it's a CLI-first tool, it also features a &lt;strong&gt;React&lt;/strong&gt; web interface that includes interactive Kanban boards, complementing the terminal experience.&lt;/li&gt;
&lt;/ul&gt;

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




&lt;h3&gt;
  
  
  Taking Backlog.md to the Next Level with AI: &lt;code&gt;mcp-backlog-md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The AI-oriented design of &lt;code&gt;backlog.md&lt;/code&gt; solves a major initial problem: &lt;em&gt;it presents project information in a structured way&lt;/em&gt;. Thanks to this, an AI agent can easily &lt;strong&gt;understand&lt;/strong&gt; the status of tasks. However, this doesn't solve the next challenge: how do we give that AI the ability to &lt;strong&gt;execute actions&lt;/strong&gt; safely and in a standardized way? Historically, every tool that wanted to connect with an AI needed a unique, custom connector, resulting in a fragile and costly-to-maintain ecosystem of integrations.&lt;/p&gt;

&lt;p&gt;To solve this, the &lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro" rel="noopener noreferrer"&gt;&lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;&lt;/a&gt; was born—an open standard aiming to be the &lt;strong&gt;"USB-C of AI."&lt;/strong&gt; Just as USB-C unified peripheral connections, MCP standardizes how LLMs connect to external tools and data sources.&lt;/p&gt;

&lt;p&gt;Instead of forcing the AI to parse CLI output, an MCP server offers it a catalog of &lt;strong&gt;capabilities&lt;/strong&gt; (tools, resources, and prompts) that it understands natively. It's the difference between having to "read a manual" and plugging in a device that "just works."&lt;/p&gt;

&lt;p&gt;This is exactly what I've built with &lt;code&gt;mcp-backlog-md&lt;/code&gt;: an MCP server that exposes the functionalities of &lt;code&gt;backlog.md&lt;/code&gt; as a set of native tools for AI. This eliminates the fragility of text parsing and adopts a robust, standard protocol, enabling much deeper and more reliable collaboration.&lt;/p&gt;

&lt;h4&gt;
  
  
  Full Integration via MCP Tools
&lt;/h4&gt;

&lt;p&gt;My implementation exposes the entire functionality of &lt;code&gt;backlog.md&lt;/code&gt; through a set of MCP tools, allowing an AI agent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manage tasks&lt;/strong&gt;: &lt;code&gt;createTask&lt;/code&gt;, &lt;code&gt;editTask&lt;/code&gt;, &lt;code&gt;viewTask&lt;/code&gt;, &lt;code&gt;listTasks&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Work with drafts and documents&lt;/strong&gt;: &lt;code&gt;createDraft&lt;/code&gt;, &lt;code&gt;promoteDraft&lt;/code&gt;, &lt;code&gt;createDoc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the project status&lt;/strong&gt;: &lt;code&gt;exportBoard&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;And much more...&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, &lt;code&gt;mcp-backlog-md&lt;/code&gt; offers &lt;strong&gt;full feature parity&lt;/strong&gt; with the original CLI, ensuring that the AI has the same power and flexibility as a human user.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In a world dominated by complex project management platforms that are often disconnected from our workflow, &lt;strong&gt;&lt;code&gt;backlog.md&lt;/code&gt;&lt;/strong&gt; emerges as a refreshing and powerful alternative. Its "Git-native" philosophy gives control back to the developer, integrating task management directly where the code is born. It offers an agile and transparent solution for teams and professionals who value simplicity and efficiency over overwhelming features.&lt;/p&gt;

&lt;p&gt;And for those who, in addition to this simplicity, want to explore the frontier of AI collaboration, the ecosystem is ready. My project, &lt;strong&gt;&lt;code&gt;mcp-backlog-md&lt;/code&gt;&lt;/strong&gt;, acts as that precise &lt;strong&gt;connector&lt;/strong&gt;, allowing an AI agent to safely integrate into this system to assist with management.&lt;/p&gt;

&lt;p&gt;Thus, &lt;code&gt;backlog.md&lt;/code&gt; is not only an excellent tool in itself but also a solid foundation on which to build advanced, AI-assisted workflows.&lt;/p&gt;




&lt;h3&gt;
  
  
  Want to try it out?
&lt;/h3&gt;

&lt;p&gt;I invite you to explore both projects. You can find the original tool in its repository and my MCP server implementation in mine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Backlog.md&lt;/code&gt; Repository&lt;/strong&gt;: &lt;a href="https://github.com/MrLesk/Backlog.md" rel="noopener noreferrer"&gt;https://github.com/MrLesk/Backlog.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My MCP Server &lt;code&gt;mcp-backlog-md&lt;/code&gt;&lt;/strong&gt;: &lt;a href="https://github.com/The-Dave-Stack/mcp-backlog-md" rel="noopener noreferrer"&gt;https://github.com/The-Dave-Stack/mcp-backlog-md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear your thoughts in the comments! Do you think this "Git-native" approach has a future? What tasks would you delegate to an AI agent in your projects?&lt;/p&gt;




&lt;h3&gt;
  
  
  To learn more about the Model Context Protocol
&lt;/h3&gt;

&lt;p&gt;If you want to dive deeper into the technology I've implemented in the server, this video offers an excellent explanation of MCP:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/embed/CQywdSdi5iA?feature=oembed" rel="noopener noreferrer"&gt;The Model Context Protocol (MCP) - YouTube&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;You can also find more information on how to use this protocol in my dedicated article about it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.thedavestack.com/model-context-protocol-exposed/" rel="noopener noreferrer"&gt;Model Context Protocol Exposed: The Power of Resources and Prompts Beyond Tools&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>git</category>
      <category>mcp</category>
    </item>
    <item>
      <title>I Tested the 3 Major Terminal AI Agents—And This Is My Winner</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Wed, 20 Aug 2025 11:22:51 +0000</pubDate>
      <link>https://dev.to/thedavestack/i-tested-the-3-major-terminal-ai-agents-and-this-is-my-winner-6oj</link>
      <guid>https://dev.to/thedavestack/i-tested-the-3-major-terminal-ai-agents-and-this-is-my-winner-6oj</guid>
      <description>&lt;p&gt;In the world of software development, we're in a constant race to optimize our workflows. AI tools like GitHub Copilot were game-changers inside the editor, but the new frontier—the one that truly promises a quantum leap in productivity—is the terminal.&lt;/p&gt;

&lt;p&gt;My motivation for diving into this ecosystem is clear: I want to boost my productivity as a developer. I see these tools as a "&lt;strong&gt;small army of junior developers&lt;/strong&gt;" at my disposal, capable of handling repetitive tasks or generating boilerplate so I can focus on architecture, business logic, and complex problems.&lt;/p&gt;

&lt;p&gt;With that mission in mind, I put the three major contenders of the moment to the test: Anthropic's &lt;a href="https://docs.anthropic.com/en/docs/claude-code/overview" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, the model-agnostic &lt;a href="https://opencode.ai/" rel="noopener noreferrer"&gt;OpenCode&lt;/a&gt;, and Google's official &lt;a href="https://github.com/google-gemini/gemini-cli" rel="noopener noreferrer"&gt;Gemini CLI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started: A Surprisingly Smooth Beginning
&lt;/h2&gt;

&lt;p&gt;First things first: getting started with any of these three tools is incredibly simple. I used &lt;code&gt;npm&lt;/code&gt; to install them, but they all offer other methods that get you up and running in your terminal in minutes. There's no fuss and no barrier to entry, which is always appreciated.&lt;/p&gt;


  


&lt;h2&gt;
  
  
  A Deep Dive: My Experience with Each Agent
&lt;/h2&gt;

&lt;p&gt;This is where things get interesting, and the differences become night and day.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Claude Code: The Agent with "Magic" Under the Hood
&lt;/h3&gt;

&lt;p&gt;I have to say it outright: of the three, &lt;strong&gt;Claude Code was the only one that truly amazed me&lt;/strong&gt;. I don't know what magic they've baked into it, but it performs spectacularly well for virtually any task I've thrown at it.&lt;/p&gt;

&lt;p&gt;Its greatest superpower is its workflow: &lt;strong&gt;first, it plans, then it acts&lt;/strong&gt;. Having tested visual coding assistants—especially my favorite, &lt;a href="https://en.thedavestack.com/cline-bot/" rel="noopener noreferrer"&gt;Cline&lt;/a&gt;—I was quite skeptical about agents in the terminal, but this one completely blew me away right from the start.&lt;/p&gt;

&lt;p&gt;Just as with Cline, which I covered in a previous post, instead of blindly starting to write code, Claude Code gives you the option to review a detailed plan. I strongly recommend you use this feature for any significant task. It outlines the steps it will take, the files it will create or modify, and the commands it will execute. You can discuss this plan, adjust it, and once you agree, give it the green light to get to work. This ability to collaborate on the strategy is, simply put, the best I've seen in a tool of this kind.&lt;/p&gt;


  


&lt;p&gt;I've used it to &lt;strong&gt;create projects from scratch&lt;/strong&gt;, giving it all the necessary context, and the experience has been fantastic. Obviously, you still need to review its work, but I consider that a normal and necessary step with any current AI. Furthermore, its integration with the Model Context Protocol (MCP) servers I use is flawless.&lt;/p&gt;


  


&lt;p&gt;Of course, not all that glitters is gold. Claude Code works wonders, but one of the trade-offs is being tied to &lt;a href="https://docs.anthropic.com/en/docs/about-claude/models/overview" rel="noopener noreferrer"&gt;Anthropic's models&lt;/a&gt;. That said, it's not a huge downside, as their models are exceptional for coding.&lt;/p&gt;

&lt;p&gt;Finally, if you're as thrilled with Claude Code as I am, here are a few links to help you enjoy it even more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The classic "Awesome" repository with interesting resources.

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hesreallyhim/awesome-claude-code" rel="noopener noreferrer"&gt;Awesome Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Several courses for more in-depth details on Claude Code.

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.deeplearning.ai/search?q=Claude+Code%3A+A+Highly+Agentic+Coding+Assistant" rel="noopener noreferrer"&gt;Claude Code: A Highly Agentic Coding Assistant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anthropic.skilljar.com/claude-code-in-action" rel="noopener noreferrer"&gt;Claude Code in Action&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. OpenCode: The Swiss Army Knife of Flexibility
&lt;/h3&gt;

&lt;p&gt;If I had to pick a runner-up, it would be OpenCode. Its main advantage is one that no other contender has: it's model-agnostic.&lt;/p&gt;


  


&lt;p&gt;This is its winning ticket. With OpenCode, you aren't tied to a single provider. You can use models from Anthropic, Google, OpenAI, or connect to OpenRouter for access to dozens of options. This versatility is a massive point in its favor, especially if you need to adapt to different projects and budgets.&lt;/p&gt;

&lt;p&gt;I haven't used this agent extensively because its most notable weakness is its integration with MCP servers. For me, these are quite important as I use them heavily to enrich the working context. In my tests, &lt;strong&gt;this integration failed frequently and needs significant improvement&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Gemini CLI: The Power of a Giant Context Window
&lt;/h3&gt;

&lt;p&gt;In the last place of my personal ranking is Gemini CLI. Although it never gave me a "wow" moment that left me speechless, it has an undeniable technical advantage: &lt;strong&gt;it uses Google's Gemini models, which offer the largest context window on the market&lt;/strong&gt; (though that might change soon: &lt;a href="https://www.anthropic.com/news/1m-context" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/1m-context&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This is tremendously useful for tasks that require understanding a large amount of code or documentation. You can feed it entire codebases and trust that it will grasp the interconnections. It's a very strong selling point.&lt;/p&gt;

&lt;p&gt;Unfortunately, like OpenCode, I found that &lt;strong&gt;its integration with MCP servers has a long way to go&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Final Verdict: My Choice as a Developer
&lt;/h2&gt;

&lt;p&gt;After several weeks of intensive testing, my final choice has a clear order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First Place:&lt;/strong&gt; Claude Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Second Place (Tie):&lt;/strong&gt; OpenCode and Gemini CLI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Right now, &lt;strong&gt;Claude Code&lt;/strong&gt; is in a league of its own. Its ability to plan, collaborate, and reliably execute complex tasks makes it the ultimate AI assistant for the terminal. It's the leader of my "army of junior devs."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenCode&lt;/strong&gt; and &lt;strong&gt;Gemini CLI&lt;/strong&gt; are very capable tools, but for different reasons. OpenCode's flexibility is its biggest draw, while Gemini's massive context window gives it a unique edge for certain types of tasks. Both are excellent, but they need to polish their integrations to compete head-to-head with the user experience that Claude offers.&lt;/p&gt;

&lt;p&gt;My final recommendation is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you're looking for the most powerful and polished tool on the market&lt;/strong&gt; and don't mind being within a proprietary ecosystem, go for &lt;strong&gt;Claude Code&lt;/strong&gt; without hesitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you value freedom, control, and the ability to switch AI models&lt;/strong&gt; based on your needs, &lt;strong&gt;OpenCode&lt;/strong&gt; is your best ally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you work with very large projects and need the largest possible context window&lt;/strong&gt;, or simply want a powerful entry point into the world of terminal agents, &lt;strong&gt;Gemini CLI&lt;/strong&gt; is a fantastic option.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI revolution in the terminal is here, and it's here to stay.&lt;/p&gt;

&lt;p&gt;What about you? Have you tried these agents? Which one is your favorite, or is there one you think I missed? Let me know in the comments or find me on social media!&lt;/p&gt;




&lt;h3&gt;
  
  
  P.S. A New Contender on the Radar: Cursor CLI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.cursor.com/en/cli/overview" rel="noopener noreferrer"&gt;Cursor – Overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The world of AI tools moves at breakneck speed. Just as I was finishing this post, I came across another project that deserves a special mention: &lt;strong&gt;Cursor CLI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For those unfamiliar, Cursor is a very popular "AI-first" code editor, and this is its command-line version. The promise is very appealing: the ability to use all the intelligence and context of your codebase that the editor already has, but directly from the terminal.&lt;/p&gt;

&lt;p&gt;Looking at its documentation, I was particularly struck by its &lt;code&gt;cursor --edit&lt;/code&gt; command, which allows for "agentic" edits on files—something along the lines of what I loved so much about Claude Code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I haven't tested it thoroughly yet&lt;/strong&gt;, but I'm adding it to my to-do list. It definitely seems like a competitor to watch in this space.&lt;/p&gt;

&lt;p&gt;Have you tried it? I'd love to hear your thoughts in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>terminal</category>
    </item>
    <item>
      <title>March 2025 AI Roundup: What Top Labs Published Last Month</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Mon, 07 Apr 2025 19:25:16 +0000</pubDate>
      <link>https://dev.to/thedavestack/march-2025-ai-roundup-what-top-labs-published-last-month-1k15</link>
      <guid>https://dev.to/thedavestack/march-2025-ai-roundup-what-top-labs-published-last-month-1k15</guid>
      <description>&lt;p&gt;Hey Community!&lt;/p&gt;

&lt;p&gt;If you’re trying to keep up with everything the major AI labs are doing — but don’t have hours to dig through blog posts and papers — I’ve got you covered.&lt;/p&gt;

&lt;p&gt;In my latest post on The Dave Stack, I curated a March 2025 roundup of the most relevant updates from top AI research labs including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI&lt;/strong&gt; – Latest insights and model updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic&lt;/strong&gt; – Research on alignment and Claude’s evolution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepMind&lt;/strong&gt; – New papers and applied AI use cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mistral&lt;/strong&gt; – Open-source activity and big releases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other key players&lt;/strong&gt; pushing the boundaries of LLMs and agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a fast way to catch up and stay sharp in a rapidly moving field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the full post here:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.thedavestack.com/march-2025-tech-roundup/" rel="noopener noreferrer"&gt;March 2025 AI Roundup – The Dave Stack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know if I missed something great from March — I’d love to include it in April’s edition.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>Exploring GPT-4o's Latest Enhancements</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Wed, 02 Apr 2025 12:35:01 +0000</pubDate>
      <link>https://dev.to/thedavestack/exploring-gpt-4os-latest-enhancements-lok</link>
      <guid>https://dev.to/thedavestack/exploring-gpt-4os-latest-enhancements-lok</guid>
      <description>&lt;h2&gt;
  
  
  🚀 Exploring GPT-4o's Latest Enhancements
&lt;/h2&gt;

&lt;p&gt;OpenAI's GPT-4o has recently received a significant update, rolled out on &lt;strong&gt;March 27, 2025&lt;/strong&gt;, bringing major improvements to its capabilities:&lt;/p&gt;

&lt;p&gt;✅ Smarter instruction adherence&lt;br&gt;&lt;br&gt;
✅ Cleaner and more efficient coding assistance&lt;br&gt;&lt;br&gt;
✅ More natural and concise communication&lt;br&gt;&lt;br&gt;
✅ Native image generation capabilities&lt;br&gt;&lt;br&gt;
✅ And now ranked &lt;strong&gt;#2&lt;/strong&gt; in the Chatbot Arena LLM Leaderboard!&lt;/p&gt;

&lt;p&gt;These enhancements make GPT-4o an even more powerful tool for developers, creators, and AI enthusiasts.&lt;/p&gt;

&lt;p&gt;I’ve written an in-depth analysis of these updates and what they mean for the future of AI interaction on my tech blog &lt;strong&gt;The Dave Stack&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://www.thedavestack.com/gpt-4o-march-27-update/" rel="noopener noreferrer"&gt;Read the full article here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts! Have you tried the new GPT-4o experience? What improvements have you noticed?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>news</category>
      <category>gpt4o</category>
      <category>openai</category>
    </item>
    <item>
      <title>The Nx Dev Tool for Monorepos</title>
      <dc:creator>David  (ダビッド )</dc:creator>
      <pubDate>Fri, 21 Aug 2020 14:45:33 +0000</pubDate>
      <link>https://dev.to/yggdrasilts/the-nx-dev-tool-for-monorepos-l84</link>
      <guid>https://dev.to/yggdrasilts/the-nx-dev-tool-for-monorepos-l84</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://blog.yggdrasilts.com/nx-dev-tool-monorepos/" rel="noopener noreferrer"&gt;Original Post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In JavaScript world, we already know the battles to be the most popular framework or library in the community. There are lots of these creating awesome sites to attract developers for its documentation and usability, showing how easy is to create an application using them, etc.&lt;/p&gt;

&lt;p&gt;Over time, some of these frameworks / libraries achieved this popularity but not alone and instead of talking about only frameworks or libraries, we started to listen the &lt;strong&gt;JavaScript Stacks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These JavaScript Stacks are just a selection of some of those popular frameworks / libraries to build the different parts of an application. The popular known stacks are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/MEAN_(solution_stack)" rel="noopener noreferrer"&gt;MEAN&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://wikitia.com/index.php?title=MERN_(solution_stack)&amp;amp;mobileaction=toggle_view_desktop" rel="noopener noreferrer"&gt;MERN&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://mevn.madlabs.xyz/?ref=madewithvuejs.com" rel="noopener noreferrer"&gt;MEVN&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, all of these stacks are nearly the same but the frontend framework, and all of them are also valid to build whatever web application you want.&lt;/p&gt;

&lt;p&gt;Enterprises are adopting this JavaScript Stacks to build its web applications even its backend as well. Due to their amount of applications and/or libraries, they have necessities not to only solve what JavaScript Stack to choose, they want to know how to organize the code, architecture patterns to build a scalable application and share components or libraries between their applications as well. In this case, the &lt;a href="https://nx.dev/angular" rel="noopener noreferrer"&gt;Nx Dev Tools&lt;/a&gt; it is the evolution of this JavaScript Stacks to choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Nx Dev Tools
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nx.dev/angular" rel="noopener noreferrer"&gt;Nx Dev Tools&lt;/a&gt;, as its website says, &lt;em&gt;is a set of extensible dev tools for monorepos, which helps you develop like Google, Facebook, and Microsoft&lt;/em&gt; and was created in &lt;a href="https://nrwl.io/" rel="noopener noreferrer"&gt;Nrwl.io&lt;/a&gt;, founded by two ex-Googlers, &lt;strong&gt;&lt;a href="https://twitter.com/victorsavkin" rel="noopener noreferrer"&gt;Victor Savkin&lt;/a&gt;&lt;/strong&gt; &amp;amp; &lt;strong&gt;&lt;a href="https://twitter.com/jeffbcross" rel="noopener noreferrer"&gt;Jeff Cross&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the current version, Nx workspace has different options to build projects with the following stacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Frameworks to build &lt;strong&gt;FRONTEND&lt;/strong&gt; applications&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.webcomponents.org/" rel="noopener noreferrer"&gt;Web Components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Framework to build &lt;strong&gt;BACKEND&lt;/strong&gt; applications&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Nextjs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In the current version there is no support for &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; but you can find some comments talking about its support &lt;a href="https://github.com/nrwl/nx/issues/1541#issuecomment-613768164" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see, &lt;a href="https://nx.dev/angular" rel="noopener noreferrer"&gt;Nx Dev Tools&lt;/a&gt; is an awesome resource thought to help developers and enterprises to build whatever they want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nx Dev Tools - Resources
&lt;/h2&gt;

&lt;p&gt;Besides its core features, &lt;a href="https://nx.dev/angular" rel="noopener noreferrer"&gt;Nx Dev Tools&lt;/a&gt; also has a CLI that helps you setup, develop, build, and maintain applications and more and more Plugins, build by their own or by the community, that contain schematics and builders to extend a Nx workspace.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/angular/cli/overview" rel="noopener noreferrer"&gt;Nx CLI&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nx.dev/angular/plugins/overview" rel="noopener noreferrer"&gt;Nx Plugins&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Start
&lt;/h2&gt;

&lt;p&gt;At this stage, you should want to know how to start using it, shouldn't it? To start, you can check the above links or if you want to get to work, then you can check its Angular tutorial in the following link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nx.dev/angular/tutorial/01-create-application" rel="noopener noreferrer"&gt;Tutorial: Step 1: Create Application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; and &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt; are my prefered options to build applications 🤓&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you are thinking to start a big, medium or small project, I recommend you to take a look its &lt;a href="https://nx.dev/angular/getting-started/why-nx" rel="noopener noreferrer"&gt;Getting Started Page&lt;/a&gt; to see how this tool can help you to organize your entire project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In next posts I will show you examples using this Nx Dev Tools 🙂.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nx</category>
      <category>angular</category>
      <category>react</category>
      <category>nestframework</category>
    </item>
  </channel>
</rss>
