<?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: Amit</title>
    <description>The latest articles on DEV Community by Amit (@amitrix).</description>
    <link>https://dev.to/amitrix</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%2F3962358%2F978a8f18-68b0-409b-9b3a-2156d0be550c.png</url>
      <title>DEV Community: Amit</title>
      <link>https://dev.to/amitrix</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amitrix"/>
    <language>en</language>
    <item>
      <title>The AI Chips After NVIDIA</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Wed, 05 Aug 2026 05:44:59 +0000</pubDate>
      <link>https://dev.to/amitrix/the-ai-chips-after-nvidia-4ibo</link>
      <guid>https://dev.to/amitrix/the-ai-chips-after-nvidia-4ibo</guid>
      <description>&lt;p&gt;NVIDIA does not have one competitor. It has a queue of startups and hyperscaler platforms attacking different parts of the AI compute problem.&lt;/p&gt;

&lt;p&gt;That distinction matters. A wafer-scale processor, a transformer-specific ASIC, a RISC-V accelerator, and a photonic interconnect are not interchangeable products. They solve different constraints, sell into different parts of the stack, and require different kinds of proof before a customer can trust them with production workloads.&lt;/p&gt;

&lt;p&gt;The useful question is not, “Which startup beats NVIDIA?” The useful question is, “Which bottleneck is each company removing, and what does that make possible?”&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison model
&lt;/h2&gt;

&lt;p&gt;The market map asks five questions: what workload the product targets, which bottleneck it attacks, whether it replaces or complements a GPU, how much software travels with it, and what evidence exists beyond a chip announcement.&lt;/p&gt;

&lt;p&gt;The fifth question is the filter. AI hardware companies can raise large rounds before their products reach volume production. A private valuation measures investor expectations at a point in time; it does not prove performance or customer retention. For performance, &lt;a href="https://mlcommons.org/benchmarks/inference-datacenter/" rel="noopener noreferrer"&gt;MLPerf Inference&lt;/a&gt; is a useful reference because it separates latency, throughput, quality targets, and system power.&lt;/p&gt;

&lt;h2&gt;
  
  
  The market is splitting around inference
&lt;/h2&gt;

&lt;p&gt;Training builds a model. Inference serves it to users. Training rewards parallel compute and software flexibility; inference adds time to first token, tokens per second, memory bandwidth, power per request, and cost per query.&lt;/p&gt;

&lt;p&gt;That creates room for specialized architectures. A chip does not need to replace every GPU if it wins a workload where the GPU carries more flexibility than the customer needs.&lt;/p&gt;

&lt;p&gt;The companies below take different positions on that trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hyperscaler platforms
&lt;/h2&gt;

&lt;p&gt;The startup map is incomplete without the other large-scale accelerator platforms. &lt;a href="https://www.nvidia.com/en-us/data-center/vera-rubin-nvl72" rel="noopener noreferrer"&gt;NVIDIA Vera Rubin NVL72&lt;/a&gt; is the current NVIDIA reference point, while &lt;a href="https://cloud.google.com/blog/products/compute/ironwood-tpus-and-new-axion-vms-for-your-ai-workloads" rel="noopener noreferrer"&gt;Google Ironwood&lt;/a&gt; and &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/12/amazon-ec2-trn3-ultraservers/" rel="noopener noreferrer"&gt;Amazon Trainium3&lt;/a&gt; represent cloud providers building their own alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  NVIDIA Vera Rubin NVL72: the rack is the product
&lt;/h3&gt;

&lt;p&gt;Vera Rubin is not a single GPU release. The NVL72 is a rack-scale system with 72 Rubin GPUs, 36 Vera CPUs, and NVLink 6 for high-speed GPU-to-GPU communication. Each Rubin GPU carries &lt;strong&gt;288 GB of HBM4&lt;/strong&gt; with &lt;strong&gt;22 TB/s of memory bandwidth&lt;/strong&gt;. Its NVLink 6 fabric provides &lt;strong&gt;3.6 TB/s of all-to-all GPU-to-GPU scale-up bandwidth per GPU&lt;/strong&gt;, or about &lt;strong&gt;260 TB/s across the rack&lt;/strong&gt;. These are different numbers: HBM bandwidth moves data between a GPU and its local memory; NVLink moves data between GPUs.&lt;/p&gt;

&lt;p&gt;The rack scales across systems through NVIDIA's Quantum-X800 InfiniBand and Spectrum-X Ethernet. That networking lineage came through NVIDIA's &lt;a href="https://nvidianews.nvidia.com/news/nvidia-completes-acquisition-of-mellanox-creating-major-force-driving-next-gen-data-centers" rel="noopener noreferrer"&gt;acquisition of Mellanox&lt;/a&gt;, whose InfiniBand and Ethernet products became the foundation of NVIDIA's networking business. Quantum-X800 and Spectrum-X are newer NVIDIA product families; NVLink remains NVIDIA's separate GPU scale-up fabric.&lt;/p&gt;

&lt;p&gt;The architecture extends NVIDIA's existing advantage: general-purpose accelerators, a tightly integrated scale-up fabric, networking, CPUs, system software, and CUDA compatibility. For inference, NVIDIA also positions the &lt;a href="https://www.nvidia.com/en-us/data-center/vera-rubin-nvl72" rel="noopener noreferrer"&gt;Groq 3 LPX rack&lt;/a&gt; beside Vera Rubin for low-latency decode and large-context workloads. Rubin GPUs provide general-purpose compute and attention processing, while Groq-derived LPUs in the LPX rack accelerate latency-sensitive feed-forward decode. NVIDIA Dynamo coordinates the two, combining broad GPU flexibility with specialized low-latency inference in one system. CUDA remains the foundation for the broader platform.&lt;/p&gt;

&lt;p&gt;NVIDIA claims one-fourth the GPU count for training some mixture-of-experts models and one-tenth the cost per million tokens versus Blackwell. Those are vendor comparisons, not neutral benchmark results. The strategic point is more durable: NVIDIA is competing at rack and data-center level, where a startup must replace an entire system relationship rather than one accelerator card.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Ironwood: a TPU pod built around co-design
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.cloud.google.com/tpu/docs/tpu7x" rel="noopener noreferrer"&gt;Google Ironwood, also called TPU7x&lt;/a&gt;, is Google's seventh-generation TPU and its first generation explicitly focused on inference. Each chip has 192 GiB of HBM3E and about 7.4 TB/s of memory bandwidth. A pod scales to 9,216 chips through Google's Inter-Chip Interconnect, optical circuit switching, data-center networking, and liquid cooling.&lt;/p&gt;

&lt;p&gt;Ironwood's differentiator is system-level co-design. The hardware, &lt;a href="https://cloud.google.com/blog/products/compute/inside-the-ironwood-tpu-codesigned-ai-stack" rel="noopener noreferrer"&gt;XLA compiler and Pallas kernel system&lt;/a&gt; are built together, and Google presents the pod as one large computer rather than a loose collection of accelerators. The trade is portability: Google Cloud access, JAX and PyTorch support, and a programming model that differs from CUDA.&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon Trainium3: cloud-native scale with Neuron
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/ec2/instance-types/trn3/" rel="noopener noreferrer"&gt;Trainium3&lt;/a&gt; is the fourth-generation AWS AI chip. A Trainium3 chip provides 2.52 FP8 petaflops, 144 GB of HBM3e, and 4.9 TB/s of memory bandwidth. Trn3 UltraServers scale to 144 chips using NeuronSwitch-v1, and UltraCluster 3.0 connects much larger deployments through a non-blocking, petabit-scale network.&lt;/p&gt;

&lt;p&gt;Trainium3's architectural advantage is not only the chip. It is the combination of Trainium, the &lt;a href="https://aws.amazon.com/machine-learning/neuron/" rel="noopener noreferrer"&gt;AWS Neuron SDK&lt;/a&gt;, and cloud integration across services such as Amazon Bedrock, SageMaker, EKS, and Batch. Neuron supports PyTorch and JAX, while the Neuron Kernel Interface provides a lower-level path for custom kernels.&lt;/p&gt;

&lt;p&gt;Trainium3 is therefore a cloud-native alternative rather than a general market card. Its strength is cost and scale inside the AWS environment. Its trade is that a customer adopting it is also adopting the Neuron software path and the operating model of that cloud.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Primary advantage&lt;/th&gt;
&lt;th&gt;Main trade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA Vera Rubin NVL72&lt;/td&gt;
&lt;td&gt;Broadest accelerator, networking, and software platform&lt;/td&gt;
&lt;td&gt;Highest system complexity and dependence on NVIDIA's stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Ironwood TPU7x&lt;/td&gt;
&lt;td&gt;Tight hardware, compiler, and pod co-design&lt;/td&gt;
&lt;td&gt;Google Cloud and XLA-oriented programming model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Trainium3 / Trn3&lt;/td&gt;
&lt;td&gt;Cloud-native scale and Neuron economics&lt;/td&gt;
&lt;td&gt;AWS-specific hardware and software path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup accelerators&lt;/td&gt;
&lt;td&gt;Narrow optimization for latency, memory, power, or openness&lt;/td&gt;
&lt;td&gt;Smaller ecosystem and less proven deployment scale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  1. Cerebras: put the model on one enormous processor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.cerebras.ai/" rel="noopener noreferrer"&gt;Cerebras&lt;/a&gt; takes the most visible architectural departure from the GPU cluster. Its Wafer-Scale Engine uses an entire silicon wafer as a single processor, with a large on-chip memory system and a fabric connecting the compute elements.&lt;/p&gt;

&lt;p&gt;The bet is that moving data between many separate chips creates a large part of the latency and system complexity. A wafer-scale system keeps more of the working set close to the compute and reduces the need to coordinate a large collection of discrete accelerators.&lt;/p&gt;

&lt;p&gt;Cerebras is one of the strongest examples of a startup moving beyond a chip into a complete infrastructure product. Its &lt;a href="https://www.cerebras.ai/blog/openai-partners-with-cerebras-to-bring-high-speed-inference-to-the-mainstream" rel="noopener noreferrer"&gt;OpenAI agreement&lt;/a&gt; describes a planned 750 megawatts of wafer-scale systems for high-speed inference. The company also announced a &lt;a href="https://www.cerebras.ai/press-release/amd-and-cerebras-announce-industry-leading-ultra-low-latency-and-high-throughput-ai-inference" rel="noopener noreferrer"&gt;partnership with AMD&lt;/a&gt; that combines AMD rack-scale systems for throughput with Cerebras systems for token generation.&lt;/p&gt;

&lt;p&gt;Recent announcements make the scale-up challenge more concrete. Cerebras says it will add &lt;a href="https://www.cerebras.ai/company/press-release" rel="noopener noreferrer"&gt;200 megawatts of European AI compute capacity by the end of 2027&lt;/a&gt;, while third-party coverage places the OpenAI agreement above $20 billion over multiple years. The official announcement describes the deal as a multi-year 750-megawatt deployment; the larger figure is a reported commercial value, not a published contract document.&lt;/p&gt;

&lt;p&gt;The trade is extraordinary local memory and low latency in exchange for a less conventional manufacturing, programming, and deployment model. Cerebras is not a drop-in GPU. It is a different computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. SambaNova: sell the system, not only the silicon
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://sambanova.ai/" rel="noopener noreferrer"&gt;SambaNova&lt;/a&gt; packages custom processors, memory, networking, and software into enterprise AI systems. Its pitch is less about selling a component to an engineering team and more about providing a system that can be deployed for controlled inference workloads.&lt;/p&gt;

&lt;p&gt;The company raised &lt;a href="https://www.generalatlantic.com/media-article/sambanova-completes-first-close-of-1-billion-financing-at-11-billion-valuation/" rel="noopener noreferrer"&gt;$1 billion at an $11 billion valuation&lt;/a&gt; in July 2026. The same announcement describes expansion across enterprises, neoclouds, sovereign customers, and service providers. &lt;a href="https://www.sambanova.ai/press/sambanova-and-jpmorgan-chase-partner-to-advance-enterprise-ai-inference" rel="noopener noreferrer"&gt;JPMorgan Chase selected SambaNova as an inference infrastructure partner&lt;/a&gt;, according to the company.&lt;/p&gt;

&lt;p&gt;SambaNova's architecture is aimed at the part of inference where memory movement and serving cost dominate. Alternative accelerators often enter the market as part of a heterogeneous system rather than replacing every GPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. d-Matrix: move compute into memory
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.d-matrix.ai/" rel="noopener noreferrer"&gt;d-Matrix&lt;/a&gt; is attacking the memory wall directly. Its digital in-memory computing approach places more of the required computation near the data instead of repeatedly moving model weights between separate memory and compute units.&lt;/p&gt;

&lt;p&gt;The company raised &lt;a href="https://www.d-matrix.ai/announcements/d-matrix-raises-275-million-to-power-the-age-of-ai-inference/" rel="noopener noreferrer"&gt;$275 million in Series C funding at a $2 billion valuation&lt;/a&gt;. In June 2026, it announced that its &lt;a href="https://www.d-matrix.ai/announcements/d-matrix-corsair-ai-inference-platform-enters-full-production-to-meet-customer-demand/" rel="noopener noreferrer"&gt;Corsair platform entered full production&lt;/a&gt;, with volume shipments planned for selected hyperscale, neocloud, and frontier-lab customers.&lt;/p&gt;

&lt;p&gt;d-Matrix is also explicit about an architecture that works alongside GPUs. Its company-reported testing describes a heterogeneous configuration in which Corsair handles part of inference beside GPU infrastructure.&lt;/p&gt;

&lt;p&gt;That position became more concrete in 2026. d-Matrix &lt;a href="https://www.d-matrix.ai/announcements/acquisition-of-gigaio" rel="noopener noreferrer"&gt;acquired GigaIO's data-center business&lt;/a&gt; to add rack-scale systems and interconnect expertise, then announced a &lt;a href="https://www.d-matrix.ai/announcements/parasail-d-matrix-accelerators/" rel="noopener noreferrer"&gt;Parasail deployment&lt;/a&gt; pairing Corsair with NVIDIA Hopper and Blackwell systems. The company is no longer presenting only a chip; it is assembling the deployment layer around a heterogeneous rack.&lt;/p&gt;

&lt;p&gt;The product becomes useful when its compilers, runtimes, and fallback behavior cover the model graphs customers actually run.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Tenstorrent: make the stack more open
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tenstorrent.com/" rel="noopener noreferrer"&gt;Tenstorrent&lt;/a&gt; is taking a different route. Its Blackhole processors combine Tensix AI cores with RISC-V cores, and the company publishes an open software stack that gives developers access to lower layers of the system. Its &lt;a href="https://www.tenstorrent.com/hardware/blackhole" rel="noopener noreferrer"&gt;Blackhole cards&lt;/a&gt; are listed for purchase, including a model priced at $999 with 120 Tensix cores and up to 32 GB of GDDR6 memory.&lt;/p&gt;

&lt;p&gt;The architectural bet is not only about raw throughput. It is also about control: developers can inspect and tune more of the machine rather than treating the accelerator as a sealed appliance. That creates a software burden because NVIDIA's advantage includes the accumulated compatibility of &lt;a href="https://developer.nvidia.com/cuda-toolkit" rel="noopener noreferrer"&gt;CUDA&lt;/a&gt; libraries, frameworks, profilers, kernels, and developer habits.&lt;/p&gt;

&lt;p&gt;Tenstorrent therefore competes on a different axis: lower entry cost, RISC-V flexibility, and a more inspectable stack. The latest product update is larger than a card launch. Tenstorrent announced &lt;a href="https://tenstorrent.com/newsroom/tenstorrent-enables-ai-at-scale-with-industry-leading-performance" rel="noopener noreferrer"&gt;general availability of Galaxy Blackhole&lt;/a&gt;, a 32-chip air-cooled system starting at $110,000, with a four-system supercluster starting at $440,000. The company also says Galaxy is shipping in volume and has been deployed in multi-server configurations.&lt;/p&gt;

&lt;p&gt;Tenstorrent is moving from an openness thesis toward a systems thesis: standard Ethernet, RISC-V-based processors, public software, and rack-scale deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Etched: specialize for transformers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.etched.com/" rel="noopener noreferrer"&gt;Etched&lt;/a&gt; is making the narrowest bet in this group. The company is building an ASIC optimized for transformer models, the architecture behind many current large language models.&lt;/p&gt;

&lt;p&gt;The benefit of specialization is straightforward: remove general-purpose features and use the saved area and power budget for a targeted workload. The cost is equally straightforward: model architectures change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://techcrunch.com/2026/07/23/ai-chip-startup-etched-defies-skeptics-hits-10-3b-valuation-from-big-name-investors/" rel="noopener noreferrer"&gt;TechCrunch reported&lt;/a&gt; that Etched closed a $300 million Series C at a $10.3 billion valuation in July 2026. The same report says Etched has manufactured its chips, is testing full systems with clients, and has booked $1 billion in orders. Those are stronger maturity signals than a funding announcement, but they remain company-reported claims rather than independently audited revenue.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Fractile: treat memory as the compute surface
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://fractile.ai/" rel="noopener noreferrer"&gt;Fractile&lt;/a&gt; is another memory-centric architecture, but with a different implementation path. The London startup is building in-memory computing hardware intended to perform more of the inference arithmetic where the model weights are stored.&lt;/p&gt;

&lt;p&gt;The company raised &lt;a href="https://tech.eu/2026/05/13/uk-ai-chip-startup-fractile-raises-220m-to-tackle-the-growing-inference-bottleneck/" rel="noopener noreferrer"&gt;$220 million in Series B funding&lt;/a&gt; in May 2026. Recent trade coverage puts the first-chip target in the second half of 2026, earlier than the 2027 launch window cited in earlier coverage. That timeline needs confirmation from Fractile before it becomes a firm milestone.&lt;/p&gt;

&lt;p&gt;The architecture is attractive because inference repeatedly reads model weights. Its risk is software coverage across changing operators, quantization schemes, and model families.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Positron and FuriosaAI: win on efficiency and deployment
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.positron.ai/" rel="noopener noreferrer"&gt;Positron&lt;/a&gt; is building accelerator and memory products around high-throughput inference. &lt;a href="https://techcrunch.com/2026/02/04/exclusive-positron-raises-230m-series-b-to-take-on-nvidias-ai-chips/" rel="noopener noreferrer"&gt;TechCrunch reported&lt;/a&gt; a $230 million Series B and a plan to bring its Asimov chip into production in early 2027. The company's current &lt;a href="https://www.positron.ai/about" rel="noopener noreferrer"&gt;product and company pages&lt;/a&gt; distinguish the products clearly: Atlas is already shipping, while Asimov is the future custom-silicon product with more than 2 TB of memory per chip.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://furiosa.ai/" rel="noopener noreferrer"&gt;FuriosaAI&lt;/a&gt; is taking a similar efficiency-oriented position from South Korea. Its RNGD inference accelerator is aimed at reducing the power and system cost of serving models, and the company announced a &lt;a href="https://www.businesswire.com/news/home/20250730613509/en/" rel="noopener noreferrer"&gt;$125 million funding round&lt;/a&gt; to scale production. In May 2026, FuriosaAI announced a &lt;a href="https://furiosa.ai/blog/furiosaai-partners-with-broadcom-to-build-next-generation-inference-platform-for-the-agentic-era" rel="noopener noreferrer"&gt;partnership with Broadcom&lt;/a&gt; for a third-generation inference platform while stating that RNGD had entered mass production and had been validated by Samsung SDS and LG AI Research.&lt;/p&gt;

&lt;p&gt;The relevant comparison is whether a customer can meet its latency and quality target with fewer racks, lower power, lower cost, or a better deployment footprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Lightmatter: attack the network around the chip
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://lightmatter.co/about/" rel="noopener noreferrer"&gt;Lightmatter&lt;/a&gt; is building photonic computing and optical interconnect technology. Its core idea is that moving data between processors becomes a larger constraint as AI clusters grow. Photons can move signals through optical paths with less electrical loss and higher bandwidth density.&lt;/p&gt;

&lt;p&gt;This is not the same product category as Cerebras or d-Matrix. Lightmatter can become valuable even when the compute remains NVIDIA-based. The company has also joined &lt;a href="https://lightmatter.co/news/lightmatter-joins-nvidia-nvlink-fusion-and-powers-next-generation-ai-infrastructure/" rel="noopener noreferrer"&gt;NVIDIA's NVLink Fusion ecosystem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reuters.com/technology/photonic-startup-lightmatter-raises-400-million-amid-ai-datacenter-boom-eyes-ipo-2024-10-16/" rel="noopener noreferrer"&gt;Reuters reported&lt;/a&gt; that Lightmatter raised $400 million at a $4.4 billion valuation. Its position is closer to making every accelerator cluster scale better than replacing the incumbent accelerator.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Company&lt;/th&gt;
&lt;th&gt;Primary target&lt;/th&gt;
&lt;th&gt;Core architectural idea&lt;/th&gt;
&lt;th&gt;Relationship to GPUs&lt;/th&gt;
&lt;th&gt;Latest public funding or valuation signal&lt;/th&gt;
&lt;th&gt;Maturity signal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.cerebras.ai/" rel="noopener noreferrer"&gt;Cerebras&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Training and inference&lt;/td&gt;
&lt;td&gt;Wafer-scale processor and large local memory&lt;/td&gt;
&lt;td&gt;Alternative system; can be paired with other infrastructure&lt;/td&gt;
&lt;td&gt;750 MW OpenAI deployment agreement&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cerebras.ai/cbrs" rel="noopener noreferrer"&gt;Public listing&lt;/a&gt; and deployed systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://sambanova.ai/" rel="noopener noreferrer"&gt;SambaNova&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Enterprise inference&lt;/td&gt;
&lt;td&gt;Full-stack accelerator systems&lt;/td&gt;
&lt;td&gt;Alternative system&lt;/td&gt;
&lt;td&gt;$1B round at $11B valuation&lt;/td&gt;
&lt;td&gt;Enterprise and financial-services deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.d-matrix.ai/" rel="noopener noreferrer"&gt;d-Matrix&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Data-center inference&lt;/td&gt;
&lt;td&gt;Digital in-memory compute&lt;/td&gt;
&lt;td&gt;Works beside GPUs in heterogeneous systems&lt;/td&gt;
&lt;td&gt;$275M round at $2B valuation&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.d-matrix.ai/announcements/d-matrix-corsair-ai-inference-platform-enters-full-production-to-meet-customer-demand/" rel="noopener noreferrer"&gt;Corsair announced in full production&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://tenstorrent.com/" rel="noopener noreferrer"&gt;Tenstorrent&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Training and inference&lt;/td&gt;
&lt;td&gt;RISC-V plus Tensix AI cores&lt;/td&gt;
&lt;td&gt;Alternative and accelerator-card path&lt;/td&gt;
&lt;td&gt;Product pricing is public; valuation not used here&lt;/td&gt;
&lt;td&gt;&lt;a href="https://tenstorrent.com/newsroom/tenstorrent-enables-ai-at-scale-with-industry-leading-performance" rel="noopener noreferrer"&gt;Galaxy systems in general availability&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.etched.com/" rel="noopener noreferrer"&gt;Etched&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Transformer inference&lt;/td&gt;
&lt;td&gt;Transformer-specific ASIC&lt;/td&gt;
&lt;td&gt;Narrow replacement for selected workloads&lt;/td&gt;
&lt;td&gt;$300M round at $10.3B valuation&lt;/td&gt;
&lt;td&gt;First-silicon and contract claims require continued validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://fractile.ai/" rel="noopener noreferrer"&gt;Fractile&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Inference&lt;/td&gt;
&lt;td&gt;In-memory computing&lt;/td&gt;
&lt;td&gt;Alternative accelerator&lt;/td&gt;
&lt;td&gt;$220M Series B&lt;/td&gt;
&lt;td&gt;First chip target reported for late 2026; confirm with company&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.positron.ai/" rel="noopener noreferrer"&gt;Positron&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Inference&lt;/td&gt;
&lt;td&gt;Memory and accelerator system&lt;/td&gt;
&lt;td&gt;Alternative accelerator&lt;/td&gt;
&lt;td&gt;$230M Series B at $1B+ valuation&lt;/td&gt;
&lt;td&gt;Atlas shipping; Asimov production targeted for 2027&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://furiosa.ai/" rel="noopener noreferrer"&gt;FuriosaAI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Inference&lt;/td&gt;
&lt;td&gt;Power-efficient accelerator&lt;/td&gt;
&lt;td&gt;Alternative accelerator&lt;/td&gt;
&lt;td&gt;$125M funding round&lt;/td&gt;
&lt;td&gt;RNGD in mass production; Broadcom platform in development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://lightmatter.co/" rel="noopener noreferrer"&gt;Lightmatter&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Interconnect&lt;/td&gt;
&lt;td&gt;Photonic data movement&lt;/td&gt;
&lt;td&gt;Complements GPU clusters&lt;/td&gt;
&lt;td&gt;$400M round at $4.4B valuation&lt;/td&gt;
&lt;td&gt;Partner ecosystem and optical products&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no single “NVIDIA alternative” architecture. The specialized bets target the parts of the system where general-purpose GPUs carry too much cost or complexity.&lt;/p&gt;

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

&lt;p&gt;The market still lacks a universal comparison for production AI systems.&lt;/p&gt;

&lt;p&gt;Tokens per second is not enough. A system can produce tokens quickly while using a large amount of power, supporting a narrow model family, requiring a custom compiler, or failing under real concurrency. A low-latency demo can also hide the cost of loading weights, moving data between stages, and keeping the system utilized.&lt;/p&gt;

&lt;p&gt;The comparison needs six measurements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;time to first token&lt;/li&gt;
&lt;li&gt;sustained output tokens per second&lt;/li&gt;
&lt;li&gt;cost per million output tokens&lt;/li&gt;
&lt;li&gt;energy per million output tokens&lt;/li&gt;
&lt;li&gt;model and operator coverage&lt;/li&gt;
&lt;li&gt;software migration effort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those measurements need to be collected on the same model, prompt mix, quality target, concurrency level, and end-to-end system boundary. Until then, the market is full of company claims that answer different questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;The next AI hardware market will not be won by one chip that replaces every GPU.&lt;/p&gt;

&lt;p&gt;It will be won by a portfolio of architectures. General-purpose GPUs will remain the broad platform for workloads that change quickly. Specialized processors will take slices where latency, memory movement, power, or cost matter more than flexibility. Optical interconnects will make larger clusters possible. Open architectures will give some customers more control over the stack.&lt;/p&gt;

&lt;p&gt;That is the practical way to read valuations. A high valuation says that investors believe a bottleneck is valuable. It does not say the architecture has won.&lt;/p&gt;

&lt;p&gt;The better question for any AI chip startup is simple: what constraint does this company remove, and can it prove the result on a production workload without asking the customer to rebuild the entire software ecosystem?&lt;/p&gt;

&lt;p&gt;That is where the competition is.&lt;/p&gt;

</description>
      <category>aiinfrastructure</category>
      <category>semiconductors</category>
      <category>inference</category>
      <category>startup</category>
    </item>
    <item>
      <title>The Five-Layer AI Stack Is an Inverted Pyramid</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Wed, 05 Aug 2026 00:24:16 +0000</pubDate>
      <link>https://dev.to/amitrix/the-five-layer-ai-stack-is-an-inverted-pyramid-3ef0</link>
      <guid>https://dev.to/amitrix/the-five-layer-ai-stack-is-an-inverted-pyramid-3ef0</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Jensen Huang's five layers are energy, chips, infrastructure, models, and applications. The dependency chain is clear, but it is not a map of market power.&lt;/li&gt;
&lt;li&gt;Participation expands upward: a few physical platforms support many models and far more applications.&lt;/li&gt;
&lt;li&gt;Power concentrates at bottlenecks below and distribution gateways above. TSMC, ASML, three global clouds, and a short list of digital gatekeepers make that concentration visible.&lt;/li&gt;
&lt;li&gt;Applications create the customer value. That does not mean application vendors keep most of the profit.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;AI looks like software at the top and heavy industry at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogs.nvidia.com/blog/ai-5-layer-cake/" rel="noopener noreferrer"&gt;Jensen Huang describes AI&lt;/a&gt; as a five-layer cake: energy, chips, infrastructure, models, and applications. Each layer depends on the one below it. An application calls a model. The model runs on computing infrastructure. The infrastructure contains chips. The chips consume electricity.&lt;/p&gt;

&lt;p&gt;That is the right dependency map. It is the wrong shape.&lt;/p&gt;

&lt;p&gt;My read is that the stack behaves like an &lt;strong&gt;inverted production pyramid&lt;/strong&gt;. Participation expands as you move upward. A small number of physical platforms support more models, which support far more applications and industry workflows.&lt;/p&gt;

&lt;p&gt;Then the pyramid meets a second bottleneck. Thousands of applications still have to pass through a small number of distribution systems to reach customers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart BT
    E["Energy&amp;lt;br/&amp;gt;local power and grid access"] --&amp;gt; C["Chips&amp;lt;br/&amp;gt;qualified manufacturing"]
    C --&amp;gt; I["Infrastructure&amp;lt;br/&amp;gt;facilities, systems, and cloud"]
    I --&amp;gt; M["Models&amp;lt;br/&amp;gt;frontier, open, and specialized"]
    M --&amp;gt; A["Applications&amp;lt;br/&amp;gt;many products and workflows"]
    A --&amp;gt; D["Distribution gateways&amp;lt;br/&amp;gt;identity, discovery, billing"]
    D --&amp;gt; U["Customers"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stack widens in solution variety. It narrows around production capacity. It narrows again around customer access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Width Is Not Power
&lt;/h2&gt;

&lt;p&gt;An inverted pyramid only works after defining what its width represents.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;The question it answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Participation&lt;/td&gt;
&lt;td&gt;How many companies or products can enter this layer?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concentration&lt;/td&gt;
&lt;td&gt;How much supply or spending belongs to the largest providers?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Value creation&lt;/td&gt;
&lt;td&gt;Where does AI produce a useful customer outcome?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Value capture&lt;/td&gt;
&lt;td&gt;Who retains the revenue and profit?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distribution power&lt;/td&gt;
&lt;td&gt;Who controls customer access, identity, and billing?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These measures do not move together.&lt;/p&gt;

&lt;p&gt;A layer can contain thousands of products while a few suppliers control its inputs. An application can create the customer outcome while model, cloud, chip, data, and distribution providers collect part of the profit. More companies at the top does not automatically mean more competition or more economic power.&lt;/p&gt;

&lt;p&gt;This distinction is the key to reading the five layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Energy Is Broad Globally and Narrow Locally
&lt;/h2&gt;

&lt;p&gt;Energy looks like the broadest physical market. Countries have thousands of utilities, generators, fuel suppliers, and grid operators. It is not a global oligopoly.&lt;/p&gt;

&lt;p&gt;But AI infrastructure does not need electricity in the abstract. It needs deliverable power at a specific site, on a specific schedule, with transmission, transformers, cooling, permits, and financing already aligned.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.iea.org/reports/energy-and-ai/executive-summary" rel="noopener noreferrer"&gt;International Energy Agency estimates&lt;/a&gt; that data centers consumed about 415 terawatt-hours of electricity in 2024, or 1.5% of global consumption. Its base case reaches roughly 945 TWh in 2030. That global share can look manageable while individual data-center regions face severe local constraints.&lt;/p&gt;

&lt;p&gt;The hidden bottleneck can be an ordinary grid component. The &lt;a href="https://www.energy.gov/oe/supply-chain-and-market-analysis" rel="noopener noreferrer"&gt;US Department of Energy reports&lt;/a&gt; that distribution-transformer lead times expanded from three to six months in 2019 to 12 to 30 months in 2023.&lt;/p&gt;

&lt;p&gt;So the bottom of the pyramid is not "a few energy companies." The narrow point is the combination of powered land, grid access, equipment, and permission to build.&lt;/p&gt;

&lt;p&gt;Large companies such as &lt;a href="https://www.nexteraenergy.com/" rel="noopener noreferrer"&gt;NextEra Energy&lt;/a&gt;, &lt;a href="https://www.constellationenergy.com/" rel="noopener noreferrer"&gt;Constellation&lt;/a&gt;, and &lt;a href="https://www.gevernova.com/" rel="noopener noreferrer"&gt;GE Vernova&lt;/a&gt; supply generation and grid technology. Startups including &lt;a href="https://fervoenergy.com/" rel="noopener noreferrer"&gt;Fervo Energy&lt;/a&gt; and &lt;a href="https://oklo.com/" rel="noopener noreferrer"&gt;Oklo&lt;/a&gt; are pursuing new generation paths. But a power announcement is not operating capacity. Licensing, construction, fuel, transmission, and interconnection still determine when a project becomes real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chips Contain the Narrowest Global Chokepoints
&lt;/h2&gt;

&lt;p&gt;The chip layer contains many products but only a few qualified suppliers at critical stages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nvidia.com/en-us/data-center/" rel="noopener noreferrer"&gt;NVIDIA&lt;/a&gt; and &lt;a href="https://www.amd.com/en/products/accelerators/instinct.html" rel="noopener noreferrer"&gt;AMD&lt;/a&gt; sell merchant accelerators. &lt;a href="https://cloud.google.com/tpu" rel="noopener noreferrer"&gt;Google&lt;/a&gt;, &lt;a href="https://aws.amazon.com/machine-learning/trainium/" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;, and &lt;a href="https://azure.microsoft.com/en-us/blog/azure-maia-for-the-era-of-ai-from-silicon-to-software-to-systems/" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt; design custom chips for their own platforms. Startups such as &lt;a href="https://www.cerebras.ai/" rel="noopener noreferrer"&gt;Cerebras&lt;/a&gt;, &lt;a href="https://groq.com/" rel="noopener noreferrer"&gt;Groq&lt;/a&gt;, and &lt;a href="https://lightmatter.co/" rel="noopener noreferrer"&gt;Lightmatter&lt;/a&gt; attack different parts of compute and interconnect performance.&lt;/p&gt;

&lt;p&gt;That design activity still funnels into a concentrated manufacturing chain.&lt;/p&gt;

&lt;p&gt;The US Department of Commerce stated in April 2024 that&lt;br&gt;
&lt;a href="https://www.commerce.gov/news/press-releases/2024/04/biden-harris-administration-announces-preliminary-terms-tsmc-expanded" rel="noopener noreferrer"&gt;TSMC manufactures more than 90% of the world's leading-edge logic chips&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://www.asml.com/en/technology/lithography-principles/light-and-lasers" rel="noopener noreferrer"&gt;ASML describes extreme-ultraviolet lithography&lt;/a&gt; as technology unique to ASML. High-bandwidth memory comes from a small supplier group led by &lt;a href="https://news.skhynix.com/2026-market-outlook-focus-on-the-hbm-led-memory-supercycle" rel="noopener noreferrer"&gt;SK hynix&lt;/a&gt;, &lt;a href="https://semiconductor.samsung.com/dram/hbm/" rel="noopener noreferrer"&gt;Samsung&lt;/a&gt;, and &lt;a href="https://www.micron.com/products/memory/hbm" rel="noopener noreferrer"&gt;Micron&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the inverted pyramid at its clearest. A large application market can rest on one to three scaled suppliers at several manufacturing steps.&lt;/p&gt;

&lt;p&gt;Custom silicon can weaken one accelerator vendor's position. It does not remove the dependence on foundries, lithography, memory, packaging, and materials.&lt;/p&gt;
&lt;h2&gt;
  
  
  Infrastructure Is Several Markets Compressed Into One
&lt;/h2&gt;

&lt;p&gt;Huang's infrastructure layer includes land, power delivery, cooling, construction, networking, and orchestration. Economically, that combines at least three different markets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Physical facilities: powered land, buildings, substations, cooling, and colocation.&lt;/li&gt;
&lt;li&gt;Compute systems: servers, racks, storage, networking, schedulers, and inference software.&lt;/li&gt;
&lt;li&gt;Cloud services: capacity sold through APIs, managed platforms, and long-term contracts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first two contain many specialists. &lt;a href="https://www.vertiv.com/en-us/about/news-and-insights/articles/educational-articles/data-center-vision-how-data-center-infrastructure-is-evolving-to-support-ai/" rel="noopener noreferrer"&gt;Vertiv&lt;/a&gt; and &lt;a href="https://www.se.com/ww/en/work/solutions/data-centers-and-networks/" rel="noopener noreferrer"&gt;Schneider Electric&lt;/a&gt; connect power and cooling. &lt;a href="https://www.equinix.com/data-centers" rel="noopener noreferrer"&gt;Equinix&lt;/a&gt; and &lt;a href="https://www.digitalrealty.com/" rel="noopener noreferrer"&gt;Digital Realty&lt;/a&gt; operate data centers. &lt;a href="https://www.coreweave.com/" rel="noopener noreferrer"&gt;CoreWeave&lt;/a&gt;, &lt;a href="https://www.crusoe.ai/" rel="noopener noreferrer"&gt;Crusoe&lt;/a&gt;, and &lt;a href="https://nebius.com/" rel="noopener noreferrer"&gt;Nebius&lt;/a&gt; sell specialized AI capacity.&lt;/p&gt;

&lt;p&gt;Global cloud is much more concentrated. &lt;a href="https://www.srgresearch.com/articles/cloud-market-annual-revenue-run-rate-topped-half-a-trillion-dollars-in-q1-as-growth-surge-continues" rel="noopener noreferrer"&gt;Synergy Research Group reported&lt;/a&gt; that Amazon, Microsoft, and Google held 63% of worldwide cloud infrastructure spending in the first quarter of 2026.&lt;/p&gt;

&lt;p&gt;The competitive unit is no longer a GPU or a data-center building. It is the ability to assemble powered land, cooling, networking, accelerators, software, financing, and paying workloads into an operating system at high utilization.&lt;/p&gt;

&lt;p&gt;That favors companies able to coordinate several sublayers at once.&lt;/p&gt;
&lt;h2&gt;
  
  
  Models Form Their Own Hourglass
&lt;/h2&gt;

&lt;p&gt;The model layer looks wide when counting model artifacts. A&lt;br&gt;
&lt;a href="https://www.dataprovenance.org/economies-of-open-intelligence.pdf" rel="noopener noreferrer"&gt;Data Provenance Initiative study&lt;/a&gt; examined 851,000 models on the Hugging Face Model Hub, representing 97.6% of downloads in its dataset.&lt;/p&gt;

&lt;p&gt;Frontier model development is far narrower. &lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;, &lt;a href="https://www.anthropic.com/" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt;, &lt;a href="https://deepmind.google/" rel="noopener noreferrer"&gt;Google DeepMind&lt;/a&gt;, and a small set of other laboratories train leading general-purpose systems. Around them sits a much wider ecosystem of open-weight models, fine-tunes, quantizations, routers, and specialized models.&lt;/p&gt;

&lt;p&gt;That produces an hourglass inside the pyramid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Many research projects and model artifacts
          Few frontier laboratories
Many hosted, adapted, and specialized variants
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Model commoditization and model concentration can happen at the same time. Routine capabilities become cheaper and easier to substitute. Producing the strongest new general-purpose model can still require more capital, compute, data, and research talent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applications Expand, Then Distribution Narrows
&lt;/h2&gt;

&lt;p&gt;Applications create the widest solution surface because industries do not share one universal workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt; and &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt; target software development. &lt;a href="https://www.abridge.com/" rel="noopener noreferrer"&gt;Abridge&lt;/a&gt; works on clinical documentation. &lt;a href="https://www.harvey.ai/" rel="noopener noreferrer"&gt;Harvey&lt;/a&gt; focuses on professional services. &lt;a href="https://waymo.com/" rel="noopener noreferrer"&gt;Waymo&lt;/a&gt; applies AI to autonomous driving. Each category brings different data, regulation, trust, integrations, and measures of success.&lt;/p&gt;

&lt;p&gt;That diversity lowers the value of a generic market map. It also explains why application companies can keep entering even when the lower stack concentrates.&lt;/p&gt;

&lt;p&gt;But application creation and application distribution are different markets.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://digital-markets-act.ec.europa.eu/gatekeepers_en/" rel="noopener noreferrer"&gt;European Commission currently lists seven Digital Markets Act gatekeepers&lt;/a&gt;: Alphabet, Amazon, Apple, Booking, ByteDance, Meta, and Microsoft. The designation covers 23 core platform services, including app stores, search, operating systems, social networks, marketplaces, browsers, advertising, and messaging.&lt;/p&gt;

&lt;p&gt;The list is not a measure of AI application share. It shows that the routes through which digital products reach customers already concentrate around a short set of platforms.&lt;/p&gt;

&lt;p&gt;An application can call any model and still depend on one operating system, productivity suite, app store, cloud marketplace, identity provider, or social network for distribution. The top of the stack therefore has a gateway, not unlimited width.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Largest Companies Cross the Layers
&lt;/h2&gt;

&lt;p&gt;The major platforms do not stay inside one layer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Company&lt;/th&gt;
&lt;th&gt;Cross-layer position&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.nvidia.com/en-us/solutions/ai-factories/" rel="noopener noreferrer"&gt;NVIDIA&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Chips, networking, systems, infrastructure software, models, and industry platforms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/ai/" rel="noopener noreferrer"&gt;Amazon&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Power procurement, custom chips, cloud infrastructure, models, marketplaces, and customer distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.microsoft.com/en-us/ai" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Custom chips, Azure infrastructure, models, developer tools, productivity software, identity, and distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ai.google/" rel="noopener noreferrer"&gt;Google&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Custom chips, global infrastructure, models, Search, Workspace, Android, and YouTube&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ai.meta.com/" rel="noopener noreferrer"&gt;Meta&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Custom chips, internal infrastructure, open models, social applications, and advertising distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vertical integration can reduce coordination costs and improve complete-system performance. It also lets one company move value between layers. A platform can subsidize a model to sell cloud capacity, build a chip to lower inference cost, or bundle an application to protect distribution.&lt;/p&gt;

&lt;p&gt;The five-layer cake describes the production system. The integrated platforms compete across the whole meal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applications Create Value, but Who Captures It?
&lt;/h2&gt;

&lt;p&gt;Huang argues that applications are where the largest economic benefit appears. That claim holds: applications turn computed intelligence into completed code, clinical documentation, legal work, customer service, scientific discovery, or physical action.&lt;/p&gt;

&lt;p&gt;It does not follow that application vendors keep most of the profit.&lt;/p&gt;

&lt;p&gt;The application may create the customer outcome while cloud, model, data, chip, and distribution providers collect part of the revenue. Infrastructure suppliers can earn exceptional returns during scarcity. Distribution owners can bundle competing features. Model providers can move upward into applications, while application vendors can switch models or build their own.&lt;/p&gt;

&lt;p&gt;The durable position is not necessarily an entire layer. It is a control point that other companies cannot easily route around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a physical bottleneck that takes years to reproduce;&lt;/li&gt;
&lt;li&gt;a software ecosystem that raises switching costs;&lt;/li&gt;
&lt;li&gt;a workflow with proprietary context and customer trust;&lt;/li&gt;
&lt;li&gt;a distribution surface that controls access, identity, or billing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the Five-Layer Model Misses
&lt;/h2&gt;

&lt;p&gt;Jensen's model leaves two important forces implicit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data&lt;/strong&gt; moves through several layers. It trains models, grounds applications, creates regulatory obligations, and becomes proprietary context inside a workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribution&lt;/strong&gt; sits above applications. It determines whether a product can reach customers, earn attention, establish identity, and collect payment.&lt;/p&gt;

&lt;p&gt;Adding those forces does not invalidate the five-layer cake. It explains why the number of participants and the location of market power tell different stories.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;The inverted pyramid is a strong map of dependency and participation. It is a weak map of profit until the bottlenecks and gateways are drawn onto it.&lt;/p&gt;

&lt;p&gt;For builders and investors, the question is not only, "Which layer are you in?" The sharper question is, "What do you control that the layers above or below cannot easily replace?"&lt;/p&gt;

&lt;p&gt;The open question is whether applications eventually retain more of the value they create, or whether model, cloud, chip, energy, and distribution providers continue to collect most of it.&lt;/p&gt;

&lt;p&gt;The answer may differ by industry. Coding tools can reach users directly. Healthcare and legal products depend on regulated systems of record. Consumer applications can scale quickly while remaining exposed to mobile and web distribution gates. Physical AI adds manufacturing and safety constraints back into the top layer.&lt;/p&gt;

&lt;p&gt;One inverted pyramid may eventually become a different market map for every industry.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>infrastructure</category>
      <category>patterns</category>
    </item>
    <item>
      <title>MCP Became Stateless: Migrating a Real AgentCore Gateway</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Tue, 04 Aug 2026 05:21:24 +0000</pubDate>
      <link>https://dev.to/amitrix/mcp-became-stateless-migrating-a-real-agentcore-gateway-4f9l</link>
      <guid>https://dev.to/amitrix/mcp-became-stateless-migrating-a-real-agentcore-gateway-4f9l</guid>
      <description>&lt;p&gt;MCP no longer needs a protocol session for remote tool calls. The &lt;a href="https://modelcontextprotocol.io/specification/2026-07-28/changelog" rel="noopener noreferrer"&gt;2026-07-28 specification&lt;/a&gt; removes the initialization handshake and &lt;code&gt;Mcp-Session-Id&lt;/code&gt;, then makes every request carry enough information to stand alone.&lt;/p&gt;

&lt;p&gt;I migrated a working Amazon Bedrock AgentCore Gateway that exposes the managed WebSearch connector. The change was smaller than the specification makes it sound: one gateway configuration update and one client-side request change. The WebSearch target, IAM authorization, tool schema, and local Codex connection stayed intact.&lt;/p&gt;

&lt;p&gt;The result is the useful part. The gateway now serves old and new MCP clients at the same endpoint, and the new path reaches WebSearch without a handshake or protocol session.&lt;/p&gt;

&lt;h2&gt;
  
  
  The state before the migration
&lt;/h2&gt;

&lt;p&gt;My existing setup already used the pattern from &lt;a href="https://artificialcuriositylabs.ai/posts/agentcore-websearch-managed-connector/" rel="noopener noreferrer"&gt;Web Search as a Managed Connector&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Codex
  -&amp;gt; local stdio MCP shim
    -&amp;gt; SigV4-signed HTTPS request
      -&amp;gt; AgentCore Gateway
        -&amp;gt; managed WebSearch connector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The local shim presented one tool to Codex, signed the outbound request with an AWS identity, and called WebSearch through the gateway. It worked, but both the shim and gateway were pinned to MCP &lt;code&gt;2025-06-18&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The request carried &lt;code&gt;MCP-Protocol-Version: 2025-06-18&lt;/code&gt; in an HTTP header. Its JSON-RPC body contained the tool name and arguments, but no per-request client information or capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  What stateless MCP changes
&lt;/h2&gt;

&lt;p&gt;Earlier remote MCP versions established protocol context through &lt;code&gt;initialize&lt;/code&gt;, followed by &lt;code&gt;notifications/initialized&lt;/code&gt;. Streamable HTTP servers could then issue an &lt;code&gt;Mcp-Session-Id&lt;/code&gt; that clients returned on later requests. That couples subsequent traffic to state established earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://modelcontextprotocol.io/seps/2575-stateless-mcp" rel="noopener noreferrer"&gt;SEP-2575&lt;/a&gt; removes the initialization handshake, while &lt;a href="https://modelcontextprotocol.io/seps/2567-sessionless-mcp" rel="noopener noreferrer"&gt;SEP-2567&lt;/a&gt; removes protocol-level sessions from Streamable HTTP. Under &lt;code&gt;2026-07-28&lt;/code&gt;, each request declares its version, method, tool name, client identity, and capabilities.&lt;/p&gt;

&lt;p&gt;The new WebSearch call adds three HTTP headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: web-search-tool___WebSearch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also adds request metadata inside &lt;code&gt;params&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tools/call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web-search-tool___WebSearch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MCP 2026-07-28 specification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"_meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"io.modelcontextprotocol/protocolVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"io.modelcontextprotocol/clientInfo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"agentcore-websearch-shim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"io.modelcontextprotocol/clientCapabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The header and body versions must agree. &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-using-mcp-call.html" rel="noopener noreferrer"&gt;AgentCore Gateway rejects mismatches&lt;/a&gt;, which gives gateways and other HTTP infrastructure a trustworthy routing signal without parsing the entire body.&lt;/p&gt;

&lt;p&gt;Normal results also carry &lt;code&gt;resultType: "complete"&lt;/code&gt;. Interactive operations can instead return &lt;code&gt;resultType: "input_required"&lt;/code&gt; and continue through a later request using the specification's &lt;a href="https://modelcontextprotocol.io/seps/2322-MRTR" rel="noopener noreferrer"&gt;Multi Round-Trip Request model&lt;/a&gt;. State becomes explicit data, not hidden connection history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quantifying the change
&lt;/h2&gt;

&lt;p&gt;For a conventional session-aware client, the first tool call drops from an initialization exchange followed by the tool exchange to one self-contained tool exchange. That removes one network round trip from the cold path. The savings equal the client-to-server round-trip time, but only before the first call.&lt;/p&gt;

&lt;p&gt;AgentCore Gateway already accepted my shim's direct &lt;code&gt;tools/call&lt;/code&gt; without a preceding handshake, so its remote request count stayed &lt;code&gt;1 -&amp;gt; 1&lt;/code&gt;. I measured the compact JSON body for the same WebSearch call:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;MCP 2025-06-18&lt;/th&gt;
&lt;th&gt;MCP 2026-07-28&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remote requests per search&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compact JSON request body&lt;/td&gt;
&lt;td&gt;162 bytes&lt;/td&gt;
&lt;td&gt;372 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The new request adds 210 body bytes plus two routing headers. There is no credible latency win to claim for this client because WebSearch execution dominates the call and the old shim had already skipped the handshake. The immediate client benefit is conformance with the new protocol and access to its result, discovery, caching, tracing, and multi-round-trip contracts.&lt;/p&gt;

&lt;p&gt;The server-side arithmetic is stronger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol session state:&lt;/strong&gt; &lt;code&gt;N&lt;/code&gt; active clients previously meant up to &lt;code&gt;N&lt;/code&gt; protocol sessions or a shared session store. The new core holds zero protocol-session records. Application state remains separate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load balancing:&lt;/strong&gt; any request can reach any healthy instance. The &lt;a href="https://modelcontextprotocol.io/seps/2575-stateless-mcp" rel="noopener noreferrer"&gt;stateless MCP proposal&lt;/a&gt; describes the previous choice between connection affinity and shared state; the new protocol removes that requirement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold-call traffic:&lt;/strong&gt; a conforming client removes one response-bearing exchange before its first tool result, a 50% reduction from two exchanges to one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure recovery:&lt;/strong&gt; losing one server instance no longer invalidates protocol sessions pinned to it. In-flight work can still fail, but recovery becomes one ordinary request retry rather than session recovery plus retry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gain is not smaller JSON or faster search. It is removing coordination: fewer cold-start exchanges, no protocol session store, no sticky routing, and less custom recovery logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for builders
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Client and host builders&lt;/strong&gt; replace session management with request construction. They need a &lt;code&gt;2026-07-28&lt;/code&gt;-capable SDK or equivalent support for the new headers, &lt;code&gt;_meta&lt;/code&gt;, &lt;code&gt;resultType&lt;/code&gt;, discovery, HTTP errors, cache metadata, and multi-round-trip responses. Supporting both versions means selecting the protocol explicitly for each request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remote server builders&lt;/strong&gt; need handlers that understand each request in isolation. Application state still exists: a coding workspace, shopping basket, or long-running job needs an explicit handle passed as a tool argument and authorized on every call. Any healthy server instance can then process the next request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool builders behind a gateway&lt;/strong&gt; often change nothing. My WebSearch target, IAM policy, tool name, and arguments stayed the same because AgentCore Gateway owns the MCP boundary. The backend does not need to know which MCP version the caller selected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interactive-tool builders&lt;/strong&gt; have the largest conceptual change. Instead of relying on a persistent connection, the tool returns &lt;code&gt;input_required&lt;/code&gt;, the client gathers the missing input, and a later request resumes the work with explicit state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform operators&lt;/strong&gt; gain standard HTTP control points. &lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt; can drive routing, rate limits, metrics, and policy without opening the JSON body. Cache metadata and trace context bring catalog traffic and distributed tracing into the same request model.&lt;/p&gt;

&lt;p&gt;Local stdio MCP servers do not need an immediate rewrite. The migration boundary is remote Streamable HTTP; a shim or gateway can adopt the new contract while the local host keeps its existing protocol version.&lt;/p&gt;

&lt;h2&gt;
  
  
  The migration boundary matters
&lt;/h2&gt;

&lt;p&gt;The shim is the protocol boundary, so the change stayed narrow:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Change required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local Codex MCP configuration&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local stdio initialization&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shim's outbound Gateway request&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gateway &lt;code&gt;supportedVersions&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IAM/SigV4 authorization&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed WebSearch target&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSearch tool arguments&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Dual-version rollout is the safe path
&lt;/h2&gt;

&lt;p&gt;AgentCore Gateway makes the transition opt-in. Its &lt;a href="https://aws.amazon.com/blogs/machine-learning/how-agentcore-gateway-supports-the-mcp-2026-07-28-spec/" rel="noopener noreferrer"&gt;&lt;code&gt;supportedVersions&lt;/code&gt; configuration&lt;/a&gt; is a complete list, not an appended value. Replacing an older version with the new one would strand every client that has not migrated.&lt;/p&gt;

&lt;p&gt;I kept the old version while adding the new one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"2025-06-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both paths completed a WebSearch request, and the new path returned &lt;code&gt;resultType: "complete"&lt;/code&gt;. Six local tests also passed for argument validation, metadata, headers, SigV4 signing, and response parsing. Version selection at the request boundary lets clients migrate independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else arrived with this release
&lt;/h2&gt;

&lt;p&gt;Statelessness is the architectural center, but the revision goes further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP operations:&lt;/strong&gt; &lt;a href="https://modelcontextprotocol.io/seps/2243-http-standardization" rel="noopener noreferrer"&gt;&lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt;&lt;/a&gt; expose request intent to routing, metering, and policy layers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching and tracing:&lt;/strong&gt; &lt;a href="https://modelcontextprotocol.io/seps/2549-TTL-for-list-results" rel="noopener noreferrer"&gt;list responses can declare cache lifetime and scope&lt;/a&gt;, while &lt;a href="https://modelcontextprotocol.io/seps/414-request-meta" rel="noopener noreferrer"&gt;W3C trace context&lt;/a&gt; can cross client, gateway, and tool boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schemas and extensions:&lt;/strong&gt; tools support &lt;a href="https://modelcontextprotocol.io/seps/2106-json-schema-2020-12" rel="noopener noreferrer"&gt;JSON Schema 2020-12&lt;/a&gt;, and &lt;a href="https://modelcontextprotocol.io/seps/2133-extensions" rel="noopener noreferrer"&gt;extensions have a governed lifecycle&lt;/a&gt;. Tasks moved from core into an official extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization and lifecycle:&lt;/strong&gt; authorization aligns more closely with &lt;a href="https://aws.amazon.com/blogs/machine-learning/how-agentcore-gateway-supports-the-mcp-2026-07-28-spec/" rel="noopener noreferrer"&gt;OAuth 2.0 and OpenID Connect practice&lt;/a&gt;. Roots, Sampling, and Logging are &lt;a href="https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging" rel="noopener noreferrer"&gt;deprecated under a formal lifecycle policy&lt;/a&gt;, though they remain functional during the compatibility window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes move remote MCP closer to ordinary HTTP infrastructure: independently routable requests, explicit caching, standard tracing, and transport errors represented by real HTTP status codes.&lt;/p&gt;

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

&lt;p&gt;I have not removed &lt;code&gt;2025-06-18&lt;/code&gt; from the gateway. Both versions work, but successful tests do not prove that every occasional client has migrated. Removing the old version needs caller inventory and protocol-version telemetry, not confidence based on one active shim.&lt;/p&gt;

&lt;p&gt;The other open question is how quickly MCP hosts will expose the new protocol natively. A translation shim makes the migration manageable, but the cleaner end state is a host that can negotiate &lt;code&gt;2026-07-28&lt;/code&gt; directly and use &lt;code&gt;server/discover&lt;/code&gt;, cache metadata, trace context, and multi-round-trip interactions without custom code.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;Remote MCP is becoming normal web infrastructure. Gateways can route and meter calls from headers, servers can scale without sticky sessions, and clients can retry self-contained operations against any healthy instance. Application state still exists, but it has to be named and carried deliberately.&lt;/p&gt;

&lt;p&gt;For my client, the trade was 210 extra request bytes in exchange for removing an entire category of connection state. The migration follows the same logic: advertise both versions, update one client at a time, and retire the old path only when usage proves it is safe.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>mcp</category>
      <category>infrastructure</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Building an Autonomous AI News Agent on Step Functions and AgentCore</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 03 Aug 2026 07:57:53 +0000</pubDate>
      <link>https://dev.to/amitrix/building-an-autonomous-ai-news-agent-on-step-functions-and-agentcore-4njg</link>
      <guid>https://dev.to/amitrix/building-an-autonomous-ai-news-agent-on-step-functions-and-agentcore-4njg</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A daily pipeline fetches 24 curated RSS feeds, clusters items describing the same real-world story across sources, categorizes survivors into nine fixed buckets with one LLM call, and writes a ranked digest — no watchlist, no web search, no human review.&lt;/li&gt;
&lt;li&gt;The first design tracked 77 named companies and investors and searched the web for each one. Measurement killed it: only 8 of 77 ever had a working official RSS feed, and the curated feed list surfaced the same funding rounds and incidents anyway, with no targeting at all.&lt;/li&gt;
&lt;li&gt;One "synthesizer" invocation that deduped, categorized, extracted funding data, and wrote prose all in a single call hit AgentCore Runtime's real synchronous ceiling — not the 8-hour session limit the container's own error message implied. Splitting into analyze → write → digest fixed it.&lt;/li&gt;
&lt;li&gt;A Step Functions Map fanning out per-category writers hit a second real bug: &lt;code&gt;$$.Map.Item.Value&lt;/code&gt; only resolves inside the Map's own &lt;code&gt;ItemSelector&lt;/code&gt;, not inside a nested Task's &lt;code&gt;Payload&lt;/code&gt;. Neither bug showed up in 79 passing unit, contract, and integration tests — only a real deployed execution surfaced them.&lt;/li&gt;
&lt;li&gt;The whole system holds state in flat JSON and Markdown files in one S3 bucket. No database. A story-thread index is the only thing that persists across days, and it's checked and pruned on every run, not on a schedule.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The wrong unit of work
&lt;/h2&gt;

&lt;p&gt;The first version of this pipeline tracked entities. A watchlist of AI labs, chip makers, and investors — 77 of them — each with its own scan session, each hitting AgentCore Web Search to ask "what happened with this company today." The architecture made sense on paper: bounded, per-entity context; a clean map-reduce shape; isolation so one company's noisy news couldn't bleed into another's summary.&lt;/p&gt;

&lt;p&gt;Then the watchlist got measured. Of 77 tracked entities, 8 had a working official RSS feed. The other 69 depended entirely on web search returning something relevant on a given day, for a company that might not have shipped anything that week. Meanwhile, a small set of broad industry-news aggregators — the outlets that already do the work of deciding what's newsworthy — covered the same funding rounds and product launches, correctly attributed, with no targeting at all.&lt;/p&gt;

&lt;p&gt;The fix wasn't a better watchlist. It was dropping the watchlist entirely. Twenty-four curated feeds — eight official company blogs, sixteen aggregators, replace a per-entity scan with one fetch that reasons across everything at once. AgentCore Web Search came out with it; there was no longer an entity-scoped gap for it to fill. Coverage went up because attribution was already being done for me, by outlets whose job is to do it.&lt;/p&gt;

&lt;p&gt;This is the general shape of the mistake: modeling the problem after the tracked entity, when the actual unit of coverage was the story, and the story doesn't care which company you're watching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the pipeline does, once a day
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A[EventBridge Scheduler&amp;lt;br/&amp;gt;00:30 daily] --&amp;gt; B[Scanner&amp;lt;br/&amp;gt;fetch 24 RSS feeds]
    B --&amp;gt; C[Analyze&amp;lt;br/&amp;gt;dedup, categorize, rank]
    C --&amp;gt; D{Map over categories&amp;lt;br/&amp;gt;with surviving items}
    D --&amp;gt; E1[Writer: category 1]
    D --&amp;gt; E2[Writer: category 2]
    D --&amp;gt; E3[Writer: category N]
    E1 --&amp;gt; F[Digest&amp;lt;br/&amp;gt;top stories + assembly]
    E2 --&amp;gt; F
    E3 --&amp;gt; F
    F --&amp;gt; G[Publish&amp;lt;br/&amp;gt;kill-switch check]
    G --&amp;gt; H[(published/ in S3)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scanner fetches every feed unconditionally — no per-source filtering — normalizes each item's date into a comparable ISO-8601 UTC string, drops anything older than 30 days as a cheap staleness guard, and writes the raw batch to S3. No LLM call happens here at all.&lt;/p&gt;

&lt;p&gt;Analyze does the actual reasoning, in five steps, none of which write a sentence of prose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cross-feed dedup.&lt;/strong&gt; Canonicalize URLs, then cluster items across every feed describing the same real-world event — URL match first, embedding similarity as a fallback. The number of independent sources covering a story becomes a corroboration signal, carried forward rather than discarded once dedup is done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Funding extraction.&lt;/strong&gt; Clusters that look like funding rounds get a structured extraction call — company, investors, amount, stage — and get force-categorized into a Funding &amp;amp; Capital bucket regardless of what general categorization would pick.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Categorization.&lt;/strong&gt; One LLM call reads every surviving cluster and assigns it to exactly one of nine fixed categories. Closed vocabulary, not open-ended — a genuinely irrelevant cluster gets dropped, not stretched into a category it doesn't belong in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Story-thread classification.&lt;/strong&gt; Each item gets checked against a global, 14-day trailing index of everything already published. Below a similarity threshold, it's classified directly as new, duplicate, or update; the ambiguous middle band gets one LLM adjudication call. Duplicates are dropped; updates get a reference appended, not a rewritten paragraph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rank, cap, and select top stories.&lt;/strong&gt; Per category, take the top N ranked items into a primary section and the next few into an overflow section. Separately, one call reads across every surviving category and picks the handful of stories that matter regardless of which bucket they landed in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Writer and Digest are where prose gets written, and they're deliberately split from Analyze and from each other — the reason why is the whole second half of this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ceiling that wasn't the one I expected
&lt;/h2&gt;

&lt;p&gt;The first working version of this pipeline had one "synthesizer" stage: dedup, funding extraction, categorization, story-threading, ranking, and prose-writing for every category, all inside a single AgentCore Runtime invocation. It ran fine in testing. It failed on a real deployed run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BedrockAgentCore.RuntimeClientErrorException: Runtime initialization time
exceeded. Please make sure that initialization completes in 120s.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That error message is about cold starts. It was not a cold start. The actual cause: AgentCore Runtime runs a &lt;code&gt;/ping&lt;/code&gt; health-check thread alongside the entrypoint handler, and a long synchronous sequence of LLM calls — dedup, then five or six structured extractions, then a prose loop over every category — blocks that thread long enough for the platform to conclude the container is unhealthy and kill it.&lt;/p&gt;

&lt;p&gt;The number that actually matters isn't a session lifetime measured in hours. AgentCore Runtime's own service quotas list two separate limits: a 15-minute request timeout for synchronous requests, and an 8-hour maximum for asynchronous jobs — neither adjustable. A session can live for hours. One synchronous invocation inside it cannot run past 15 minutes and still return a response.&lt;/p&gt;

&lt;p&gt;The fix was architectural, not a bigger timeout: split the one long invocation into three chained stages, each well clear of the ceiling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A[Analyze&amp;lt;br/&amp;gt;dedup + categorize + rank&amp;lt;br/&amp;gt;no prose] --&amp;gt; B[Writer x N&amp;lt;br/&amp;gt;one category per call&amp;lt;br/&amp;gt;≤5 prose calls each]
    B --&amp;gt; C[Digest&amp;lt;br/&amp;gt;top stories + assemble&amp;lt;br/&amp;gt;reads back every draft]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analyze does everything that doesn't require writing sentences — the fast half of what used to be one call. Writer renders exactly one category's Markdown per invocation, fanned out by a small Step Functions Map over however many categories actually survived that day (at most nine, discovered at run time, not a static config list). Digest runs once after every writer invocation finishes, writes the cross-category "top stories" prose, and reassembles the full digest by reading back each category's already-written draft from S3 — because nothing survives in memory across separate invocations; if the next stage needs it, it has to be a file.&lt;/p&gt;

&lt;p&gt;The general pattern: a monolithic long-running call scales badly against a synchronous platform ceiling. Splitting into bounded, single-purpose stages that each stay comfortably under the ceiling — and pushing state through a shared object store instead of holding it in memory — is the same shape AWS's own reference samples use for multi-agent Step Functions pipelines. It's a more boring architecture. It's also the one that doesn't get killed mid-run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that 79 passing tests didn't catch
&lt;/h2&gt;

&lt;p&gt;Splitting the pipeline into three stages meant fanning out per-category writers with a Step Functions Map. The obvious way to pass the current category into each Map iteration's nested Task is to reference the Map's own context variable directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category.$"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$$.Map.Item.Value"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This synthesizes cleanly. It passes &lt;code&gt;cdk synth&lt;/code&gt;. It passes every unit test, because unit tests exercise the Python handler, not the state machine's actual JSON. It fails at runtime with &lt;code&gt;States.Runtime: The JSONPath '$$.Map.Item.Value' specified for the field 'category' could not be found in the input&lt;/code&gt; — because &lt;code&gt;$$.Map.Item.Value&lt;/code&gt; is only resolvable inside the enclosing Map state's own &lt;code&gt;ItemSelector&lt;/code&gt;, not inside a Task nested in &lt;code&gt;ItemProcessor&lt;/code&gt;. The fix is to resolve it one level up and forward it as a plain reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;In&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Map's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;own&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ItemSelector:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"category.$"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$$.Map.Item.Value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;In&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nested&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Task's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Payload,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;down:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"category.$"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$.category"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither this bug nor the timeout ceiling above showed up in 79 passing unit, contract, and integration tests before deployment. Both required a real Step Functions execution against a real AgentCore Runtime container to surface. Tests verify that code does what the code says. They don't verify that a platform's actual behavior matches its documentation, or that a JSONPath scoping rule holds the way the mental model assumes. For infrastructure this deep in a managed platform's own execution semantics, a green test suite is a necessary check, not a sufficient one — the deployed system still has to run for real, and the output still has to get read, not merely checked for non-emptiness.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually persists
&lt;/h2&gt;

&lt;p&gt;There's no database anywhere in this pipeline. Every handoff between stages is a flat file in one S3 bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    RSS["config/rss-feeds.yaml&amp;lt;br/&amp;gt;24 feeds"] --&amp;gt; Scanner
    Scanner --&amp;gt;|writes| Raw["signals/{date}/raw-items.json&amp;lt;br/&amp;gt;ephemeral, one run"]
    Raw --&amp;gt; Analyze
    Index[("state/stories-index.json&amp;lt;br/&amp;gt;global, 14-day lookback, forever")] &amp;lt;--&amp;gt;|read + write| Analyze
    Analyze --&amp;gt;|writes| Ranked["state/{date}/ranked-sections.json&amp;lt;br/&amp;gt;no prose, one run"]
    Ranked --&amp;gt; Writer
    Writer --&amp;gt;|writes, one file per category| Drafts["drafts/{category}/{date}.md"]
    Drafts --&amp;gt; Digest
    Digest --&amp;gt;|writes| DailyDigest["drafts/daily-digest/{date}.md"]
    DailyDigest --&amp;gt; Publish
    Publish --&amp;gt;|copies| Published[("published/&amp;lt;br/&amp;gt;terminal output, forever")]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one piece of state that outlives a single run is &lt;code&gt;state/stories-index.json&lt;/code&gt; — a global, append-only record of every story published in the last 14 days, checked on every run so the same event doesn't get written up twice as it develops across days. Everything else — raw feed items, the day's ranked sections, individual drafts — is scoped to one run and never read again once the digest is assembled.&lt;/p&gt;

&lt;p&gt;The reasoning for staying file-based instead of introducing a database: at this pipeline's actual volume — 150 to 300 raw items a day, collapsing to 40 to 80 clusters after dedup — full-file reads aren't a bottleneck, and flat files in S3 are free to version, cheap to store, and trivial to inspect with a plain &lt;code&gt;aws s3 cp&lt;/code&gt;. A database adds schemas, migrations, and connection handling to solve a query pattern that "read the whole file" already serves at this scale. The rule isn't "never use a database" — it's don't introduce one preemptively, and revisit only when a specific, measured limitation of the flat-file pattern actually gets hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model tiering, and the model that didn't get replaced
&lt;/h2&gt;

&lt;p&gt;Every LLM-calling stage uses one frontier-tier model for both structured extraction and prose — categorization, funding extraction, story-thread adjudication, and every "write this section" call. Nothing in this pipeline runs on a cheap tier today; the scan stage that would have used one makes no LLM call at all post-pivot, since fetching RSS feeds is pure mechanism, not judgment.&lt;/p&gt;

&lt;p&gt;The obvious move, once this was running inside AWS infrastructure, was assuming a Bedrock-native model would be cheaper. It wasn't. Checked directly against OpenRouter's own management API and AWS's Bedrock pricing API: the frontier model already in use runs at roughly $0.44 per million input tokens and $0.87 per million output, against $1.00 and $5.00 for Bedrock's equivalent-tier Claude model on the same account. Same story for embeddings — cost parity between the OpenAI embedding model in use and Bedrock's Titan embedding model, at a scale of dozens to low-hundreds of vectors per run with a brute-force linear scan and no vector database — meaning a swap wouldn't change anything measurable either way.&lt;/p&gt;

&lt;p&gt;The lesson isn't "OpenRouter beats Bedrock." It's that "we're already on AWS, so the AWS-native option must be cheaper" is a real assumption worth checking against actual current pricing before acting on it, not a fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;The design that survived contact with real deployment isn't the one that looked cleanest on a whiteboard. It's the one that got measured — a watchlist that turned out to be 8-of-77 useful, a synchronous ceiling that turned out to be 15 minutes rather than 8 hours, a JSONPath scoping rule that only a live execution would surface, a pricing assumption that didn't hold once checked. None of those were visible from the architecture diagram alone.&lt;/p&gt;

&lt;p&gt;The pattern underneath: build the pipeline to be cheap to run end-to-end for real, then let real executions — not test suites, not synthesized templates — tell you where the design's assumptions were wrong. A green build says the code does what it claims to do. Only a deployed run with real output, read and judged rather than merely checked for non-emptiness, tells you the architecture was actually right.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>agentcore</category>
      <category>stepfunctions</category>
    </item>
    <item>
      <title>Open Data Wasn't Missing. The Interface Was.</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 03 Aug 2026 06:28:24 +0000</pubDate>
      <link>https://dev.to/amitrix/open-data-wasnt-missing-the-interface-was-1hb5</link>
      <guid>https://dev.to/amitrix/open-data-wasnt-missing-the-interface-was-1hb5</guid>
      <description>&lt;p&gt;Open data has an interface problem.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://registry.opendata.aws/" rel="noopener noreferrer"&gt;Registry of Open Data on AWS&lt;/a&gt; already&lt;br&gt;
contained 1,153 active datasets when I tested it. The catalog spans satellite&lt;br&gt;
imagery, weather, life sciences, genomics, LiDAR, census data, and web archives.&lt;br&gt;
The hard part was not finding a file with public access. It was turning a&lt;br&gt;
research question into the right collection, license, access path, and first&lt;br&gt;
executable query.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/awslabs/mcp/tree/main/src/roda-mcp-server" rel="noopener noreferrer"&gt;Registry of Open Data MCP server&lt;/a&gt;&lt;br&gt;
puts those qualification steps inside an agent conversation. The&lt;br&gt;
&lt;a href="https://aws.amazon.com/blogs/opensource/introducing-mcp-server-for-registry-of-open-data-on-aws/" rel="noopener noreferrer"&gt;launch post&lt;/a&gt;&lt;br&gt;
describes discovery as the entry point. My test found a more precise boundary:&lt;br&gt;
the server is a strong qualification interface behind a weak natural-language&lt;br&gt;
search interface.&lt;/p&gt;
&lt;h2&gt;
  
  
  What the server can do
&lt;/h2&gt;

&lt;p&gt;Version &lt;code&gt;3.4.5&lt;/code&gt; exposed 10 tools in my live session. They cover discovery,&lt;br&gt;
qualification, bounded inspection, and handoff:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;What they return&lt;/th&gt;
&lt;th&gt;Boundary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Search and browse&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;search_datasets&lt;/code&gt;, &lt;code&gt;list_datasets&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Keyword results plus tag, organization, and license filters&lt;/td&gt;
&lt;td&gt;Search uses lexical matching, not semantic ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Focus discovery&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;discover_by_organization&lt;/code&gt;, &lt;code&gt;discover_by_license&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Datasets scoped to a provider or supported license family&lt;/td&gt;
&lt;td&gt;Results depend on Registry metadata consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect one dataset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;get_dataset_details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Description, license, documentation, update frequency, and resources&lt;/td&gt;
&lt;td&gt;Metadata describes access; it does not perform analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow catalog relationships&lt;/td&gt;
&lt;td&gt;&lt;code&gt;find_related_datasets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Other datasets with shared tags&lt;/td&gt;
&lt;td&gt;Shared tags do not prove scientific relevance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect the catalog&lt;/td&gt;
&lt;td&gt;&lt;code&gt;get_knowledge_base_stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dataset, tag, organization, resource, and license counts&lt;/td&gt;
&lt;td&gt;Counts are a live catalog snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect public storage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;preview_dataset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Up to 10 S3 object keys without downloading their contents&lt;/td&gt;
&lt;td&gt;Multiple buckets require selection; private objects need credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read a bounded sample&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sample_dataset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Up to 100 KB from a selected public object; text display is capped at 2,000 characters&lt;/td&gt;
&lt;td&gt;Sampling is inspection, not bulk data processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find domain handoffs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;search_stac_endpoints&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;STAC APIs and catalogs referenced by Registry entries&lt;/td&gt;
&lt;td&gt;The returned STAC service remains a separate interface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The server runs locally over standard input and output. This is the MCP client&lt;br&gt;
configuration shape I tested:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"roda"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"awslabs.roda-mcp-server@latest"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FASTMCP_LOG_LEVEL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ERROR"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The equivalent direct launch command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvx awslabs.roda-mcp-server@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Catalog search and metadata inspection did not require AWS credentials. Live&lt;br&gt;
storage access still reflected each dataset's actual permissions.&lt;/p&gt;
&lt;h2&gt;
  
  
  The 12-question test
&lt;/h2&gt;

&lt;p&gt;I ran 12 target-retrieval tasks across wildfire, oceans, weather, agriculture,&lt;br&gt;
genomics, single-cell biology, autonomous driving, terrain, web history,&lt;br&gt;
biodiversity, flooding, and population data. Each task had a known-fit Registry&lt;br&gt;
entry selected before the search.&lt;/p&gt;

&lt;p&gt;Every task used the same sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search with the plain-language research question.&lt;/li&gt;
&lt;li&gt;Search again with distinctive terms and a tag or organization filter.&lt;/li&gt;
&lt;li&gt;Retrieve the target's metadata.&lt;/li&gt;
&lt;li&gt;Check its license, documentation, and resources.&lt;/li&gt;
&lt;li&gt;Run a live access preview.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This measured target retrieval, not universal relevance. Another result could&lt;br&gt;
be useful and still count as a miss if the preselected target did not appear.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;Plain question&lt;/th&gt;
&lt;th&gt;Constrained query&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Known-fit target in top 3&lt;/td&gt;
&lt;td&gt;2/12&lt;/td&gt;
&lt;td&gt;11/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known-fit target in top 20&lt;/td&gt;
&lt;td&gt;3/12&lt;/td&gt;
&lt;td&gt;12/12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All 12 targets returned license, resource, and documentation metadata. Ten&lt;br&gt;
returned a live anonymous bucket preview. One required a bucket selection.&lt;br&gt;
Common Crawl returned an access-denied result with credential instructions.&lt;/p&gt;


Complete benchmark results

| Domain | Plain rank | Constrained rank | Access result |
|---|---:|---:|---|
| Wildfire | Miss | 11 | Public preview |
| Oceans | Miss | 2 | Public preview |
| Weather | 11 | 1 | Public preview |
| Agriculture | 2 | 1 | Bucket selection required |
| Genomics | 1 | 1 | Public preview |
| Single-cell biology | Miss | 1 | Public preview |
| Autonomous driving | Miss | 1 | Public preview |
| Terrain | Miss | 2 | Public preview |
| Web history | Miss | 1 | Credentials required |
| Biodiversity | Miss | 2 | Public preview |
| Flooding | Miss | 2 | Public preview |
| Population | Miss | 1 | Public preview |



&lt;p&gt;Across 48 per-case MCP calls, median latency was 50.2 milliseconds, average&lt;br&gt;
latency was 99.5 milliseconds, and the slowest call took 854.0 milliseconds.&lt;br&gt;
This was one run on July 29, 2026, not a reliability study.&lt;/p&gt;

&lt;p&gt;The retrieval gap was not subtle. Plain questions matched between 421 and 1,153&lt;br&gt;
datasets, and nine known-fit targets disappeared beyond the first 20 results.&lt;br&gt;
The server removes only a few generic terms, accepts a record when any remaining&lt;br&gt;
term appears as a substring, and then diversifies the result set by provider. It&lt;br&gt;
does not calculate a relevance score.&lt;/p&gt;

&lt;p&gt;Constrained queries changed the result. Distinctive dataset terms plus a tag or&lt;br&gt;
organization filter recovered all 12 targets. The agent host currently has to&lt;br&gt;
do the query planning that natural-language search implies.&lt;/p&gt;
&lt;h2&gt;
  
  
  The handoff test
&lt;/h2&gt;

&lt;p&gt;Finding metadata is not the same as using data. I ran a second experiment to&lt;br&gt;
test the handoff from MCP qualification to an actual analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;research question
  -&amp;gt; RODA MCP discovery and access qualification
  -&amp;gt; Earth Search STAC scene selection
  -&amp;gt; bounded Cloud-Optimized GeoTIFF reads
  -&amp;gt; NDVI change
  -&amp;gt; numerical and visual evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The target was &lt;a href="https://registry.opendata.aws/sentinel-2-l2a-cogs/" rel="noopener noreferrer"&gt;Sentinel-2 Cloud-Optimized GeoTIFFs&lt;/a&gt;.&lt;br&gt;
A broad MCP query for that name matched 304 datasets and missed the target in&lt;br&gt;
the first 20. The constrained query &lt;code&gt;sentinel s2 l2a cogs&lt;/code&gt;, filtered to&lt;br&gt;
&lt;code&gt;Element 84&lt;/code&gt;, returned three records and ranked the target second.&lt;/p&gt;

&lt;p&gt;The detail call then supplied the &lt;a href="https://github.com/Element84/earth-search" rel="noopener noreferrer"&gt;Earth Search documentation&lt;/a&gt;,&lt;br&gt;
Sentinel access terms, public S3 and notification resource types, and the STAC&lt;br&gt;
collection links. The preview correctly stopped at another boundary: the entry&lt;br&gt;
has four public buckets, so the server asked for a bucket selection rather than&lt;br&gt;
guessing.&lt;/p&gt;

&lt;p&gt;That metadata was enough to leave MCP and use the domain interface.&lt;/p&gt;
&lt;h2&gt;
  
  
  A bounded wildfire screen
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.fire.ca.gov/incidents/2021/6/24/lava-fire" rel="noopener noreferrer"&gt;CAL FIRE incident record&lt;/a&gt;&lt;br&gt;
places the 2021 Lava Fire near Mount Shasta at &lt;code&gt;41.459, -122.329&lt;/code&gt;, reports a&lt;br&gt;
June 24 start, and records 26,409 acres burned. I defined a fixed rectangle&lt;br&gt;
around that published location. It is an area of interest, not a reconstructed&lt;br&gt;
fire perimeter.&lt;/p&gt;

&lt;p&gt;The script queried the current Earth Search &lt;code&gt;sentinel-2-c1-l2a&lt;/code&gt; collection for&lt;br&gt;
two windows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre-fire: June 1 through June 23, 2021&lt;/li&gt;
&lt;li&gt;Post-fire: July 15 through August 15, 2021&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each window, it selected the lowest-cloud scene that fully covered the same&lt;br&gt;
area. It read red, near-infrared, scene-classification, and true-color assets&lt;br&gt;
directly from their Cloud-Optimized GeoTIFFs. The scene-classification layer&lt;br&gt;
removed cloud, shadow, snow, water, and invalid pixels. No complete source scene&lt;br&gt;
was written to disk.&lt;/p&gt;

&lt;p&gt;Each 10-meter source raster was 10,980 by 10,980 pixels. The geographic window&lt;br&gt;
was 2,125 by 1,938 source pixels, or 3.42% of the tile's pixel footprint. The&lt;br&gt;
analysis resampled that window to 20 meters and computed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NDVI = (near infrared - red) / (near infrared + red)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The selected dates were June 18 and July 18. Across 948,704 valid overlapping&lt;br&gt;
pixels, mean NDVI moved from &lt;code&gt;0.4266&lt;/code&gt; to &lt;code&gt;0.3549&lt;/code&gt;. Mean change was &lt;code&gt;-0.0716&lt;/code&gt;;&lt;br&gt;
median change was &lt;code&gt;-0.0107&lt;/code&gt;. The lower tenth percentile reached &lt;code&gt;-0.3377&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The screening threshold matters more than the average. Pixels with a drop of at&lt;br&gt;
least &lt;code&gt;0.2&lt;/code&gt; covered 17.74% of the valid area, or 67.3152 square kilometers at&lt;br&gt;
the analysis resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/roda-mcp/lava-fire-ndvi-change.png" class="article-body-image-wrapper"&gt;&lt;img src="/assets/roda-mcp/lava-fire-ndvi-change.png" alt="Pre-fire and post-fire Sentinel-2 imagery with NDVI change near the Lava Fire incident location"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the change panel, red marks lower post-fire NDVI and blue marks higher&lt;br&gt;
post-fire NDVI. The strongest red region aligns visually with the scar in the&lt;br&gt;
post-fire image. That is evidence that the handoff works. It is not a&lt;br&gt;
burn-severity result. The rectangle includes land outside the final fire&lt;br&gt;
boundary, and NDVI also responds to seasonality, smoke, terrain shadows, and&lt;br&gt;
land management.&lt;/p&gt;

&lt;p&gt;The experiment is reproducible from the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run scripts/roda-sentinel-ndvi-experiment.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script reruns MCP discovery, queries live STAC metadata, selects scenes,&lt;br&gt;
performs bounded raster reads, and regenerates the JSON and image artifacts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the server unlocks
&lt;/h2&gt;

&lt;p&gt;The server does not make open data public. It turns catalog work into agent&lt;br&gt;
actions: search, filter, inspect a license, enumerate resources, and test an&lt;br&gt;
access boundary. That removes the manual transition between a research question&lt;br&gt;
and a known technical entry point.&lt;/p&gt;

&lt;p&gt;The Sentinel experiment shows why that matters. MCP did not calculate NDVI.&lt;br&gt;
It identified the collection, exposed its terms and resources, and pointed to&lt;br&gt;
the interface that could. Earth Search selected scenes. Rasterio read bounded&lt;br&gt;
COG windows. NumPy performed the calculation. Each layer stayed inside its&lt;br&gt;
actual capability.&lt;/p&gt;

&lt;p&gt;This pattern generalizes beyond satellite data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Registry discovery can hand ocean observations to a NetCDF or Zarr workflow.&lt;/li&gt;
&lt;li&gt;It can hand web archives to Common Crawl's index.&lt;/li&gt;
&lt;li&gt;It can hand single-cell data to a domain API.&lt;/li&gt;
&lt;li&gt;It can hand point clouds to a LiDAR processing engine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The unlock is not one universal data tool. It is a reliable routing layer from&lt;br&gt;
intent to the correct specialized tool.&lt;/p&gt;

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

&lt;p&gt;Search ranking is the immediate gap. Broad natural-language prompts can match&lt;br&gt;
nearly the whole catalog because common words survive tokenization and any-term&lt;br&gt;
substring matching. Structured filters repair retrieval, but only after the&lt;br&gt;
host agent extracts the right terms.&lt;/p&gt;

&lt;p&gt;Access preview also stops at storage. It can show that a bucket is public,&lt;br&gt;
requires credentials, or needs a selection. It does not inspect scientific&lt;br&gt;
fitness, choose an analysis method, or validate a result.&lt;/p&gt;

&lt;p&gt;The open question is where semantic selection belongs. It could move into the&lt;br&gt;
MCP server, remain in the host agent over a larger candidate set, or become a&lt;br&gt;
separate domain-specific discovery layer. The current server proves the value&lt;br&gt;
of the qualification boundary. The benchmark also shows that the host still&lt;br&gt;
does the most important retrieval work.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>agents</category>
      <category>infrastructure</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Every Way to Attribute Cost on Amazon Bedrock, Live-Tested</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Thu, 30 Jul 2026 03:31:56 +0000</pubDate>
      <link>https://dev.to/amitrix/every-way-to-attribute-cost-on-amazon-bedrock-live-tested-4ee4</link>
      <guid>https://dev.to/amitrix/every-way-to-attribute-cost-on-amazon-bedrock-live-tested-4ee4</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Bedrock has five distinct mechanisms for attributing inference cost, and I tested all five live in an account: application inference profiles, Projects, Workspaces, IAM identity tags, and request metadata joined to invocation logs.&lt;/li&gt;
&lt;li&gt;Four of the five reach real AWS billing data (Cost Explorer / Cost and Usage Report). All four are bound to a resource or an identity you provision ahead of time — none vary per individual API call.&lt;/li&gt;
&lt;li&gt;The fifth, request metadata, is the only one that's per-call, but it lands in logs, not the bill. You compute the dollar figure yourself, from token counts — a real number, but not necessarily the invoiced one, since it can't see discounts or commitments applied at the account level.&lt;/li&gt;
&lt;li&gt;For a multi-tenant SaaS product, per-customer billing isn't a cloud-tagging problem at all — it's an application-layer metering problem, and AWS's own Well-Architected guidance says so directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The five mechanisms
&lt;/h2&gt;

&lt;p&gt;Every one of these was tested with real API calls against a live Bedrock account, not read off a docs page. Each does something genuinely different, and picking the wrong one for your use case is where most cost-attribution confusion starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Application inference profiles — tag a model, not a call
&lt;/h3&gt;

&lt;p&gt;An inference profile is a named resource that wraps a specific model. Tag the profile, route calls through it, and the tag shows up on the resulting billing line items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws bedrock create-inference-profile &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--inference-profile-name&lt;/span&gt; &lt;span class="s2"&gt;"team-search-claude"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model-source&lt;/span&gt; &lt;span class="nv"&gt;copyFrom&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-haiku-4-5"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt; &lt;span class="nv"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;team,Value&lt;span class="o"&gt;=&lt;/span&gt;search &lt;span class="nv"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cost-center,Value&lt;span class="o"&gt;=&lt;/span&gt;eng-42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every call that specifies this profile's ARN as the model ID gets billed under it, and the &lt;code&gt;team&lt;/code&gt; / &lt;code&gt;cost-center&lt;/code&gt; tags become groupable dimensions in Cost Explorer once activated. The catch: one profile per model per cost dimension. Ten teams sharing five models means fifty profiles to create and keep in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Projects and Workspaces — one resource, two entry points
&lt;/h3&gt;

&lt;p&gt;A Project is a billing-scoped container that can span multiple models, which fixes the per-model constraint of inference profiles. Workspaces are the same underlying resource, referenced from a different API surface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://bedrock-mantle.us-east-1.api.aws/v1/organization/projects &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "search-team-project", "tags": {"team": "search", "cost-center": "eng-42"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scope a call to it via a header — &lt;code&gt;OpenAI-Project: proj_xxxx&lt;/code&gt; on the Chat Completions surface, or &lt;code&gt;anthropic-workspace: proj_xxxx&lt;/code&gt; on the Anthropic Messages surface. I created one Project, then called both surfaces against the same project ID and confirmed both routed to the identical billing bucket. One resource, callable from either API shape.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. IAM identity tags — tag the caller, not the call
&lt;/h3&gt;

&lt;p&gt;Tag the IAM role or user making the calls, and the tag rides along on every request that role makes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam tag-role &lt;span class="nt"&gt;--role-name&lt;/span&gt; bedrock-search-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt; &lt;span class="nv"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;team,Value&lt;span class="o"&gt;=&lt;/span&gt;search &lt;span class="nv"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cost-center,Value&lt;span class="o"&gt;=&lt;/span&gt;eng-42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the tag key is activated as a cost allocation tag, it shows up prefixed &lt;code&gt;iamPrincipal/team&lt;/code&gt; in the billing export's tag column, alongside the caller's ARN in a dedicated &lt;code&gt;line_item_iam_principal&lt;/code&gt; field. This is the mechanism that scales best across many models without creating a resource per dimension — one tagged role covers every model that role touches.&lt;/p&gt;

&lt;p&gt;The limit is architectural, not a missing feature: the tag lives on the &lt;em&gt;identity&lt;/em&gt;, not the request. If one shared service role serves ten thousand different end-customers, the bill sees one tagged identity, not ten thousand.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Session tags — a different tag per login, not per role
&lt;/h3&gt;

&lt;p&gt;STS lets you attach tags at the moment a role is assumed, distinct from the role's own static tags. This is the mechanism that gets you &lt;em&gt;closer&lt;/em&gt; to per-tenant, because a federated identity provider can mint a differently-tagged session for every login.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
    participant User as Tenant User
    participant IdP as Identity Provider
    participant STS as AWS STS
    participant Bedrock

    User-&amp;gt;&amp;gt;IdP: Login
    IdP-&amp;gt;&amp;gt;IdP: Read tenant_id attribute
    IdP-&amp;gt;&amp;gt;STS: AssumeRoleWithWebIdentity (principalTags: tenant_id)
    STS-&amp;gt;&amp;gt;STS: Attach session tag to temporary credentials
    STS--&amp;gt;&amp;gt;User: Temporary credentials (1hr TTL)
    User-&amp;gt;&amp;gt;Bedrock: Converse(...) using tagged session
    Bedrock--&amp;gt;&amp;gt;User: Response
    Note over STS,Bedrock: Session tag rides on every call&amp;lt;br/&amp;gt;until credentials expire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wiring this up: a Cognito Identity Pool (or any OIDC/SAML identity provider — Okta, Auth0, Entra ID all support the identical pattern) maps a custom user attribute to a principal tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cognito-identity set-principal-tag-attribute-map &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--identity-pool-id&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1:xxxx"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--identity-provider-name&lt;/span&gt; &lt;span class="s2"&gt;"cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxx"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--principal-tags&lt;/span&gt; &lt;span class="nv"&gt;tenant_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;custom:tenant_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The IAM role being assumed has to explicitly trust &lt;code&gt;sts:TagSession&lt;/code&gt;, not only &lt;code&gt;sts:AssumeRoleWithWebIdentity&lt;/code&gt; — leaving it off doesn't produce an obvious tagging error, it produces an unrelated-looking &lt;code&gt;InvalidIdentityPoolConfigurationException&lt;/code&gt;. I hit this omission once and it cost me twenty minutes tracing it back to the trust policy.&lt;/p&gt;

&lt;p&gt;Getting the tag to actually show up in the billing export requires two separate switches, both easy to miss: &lt;code&gt;INCLUDE_IAM_PRINCIPAL_DATA&lt;/code&gt; has to be turned on in the export's table configuration, and the export's own query has to explicitly select the &lt;code&gt;tags&lt;/code&gt; column — a separate column from &lt;code&gt;resource_tags&lt;/code&gt;, which is where I looked first and found nothing. Missing either switch produces a report with no error and no tenant breakdown, which reads exactly like the tag isn't working when it actually is.&lt;/p&gt;

&lt;p&gt;This mechanism scales to per-tenant, but the cost is real: minting a session per tenant means caching credentials properly. A naive implementation that re-authenticates on every inbound request will hit identity-provider rate limits well before it hits any meaningful production traffic — Cognito's &lt;code&gt;GetCredentialsForIdentity&lt;/code&gt;, for instance, defaults to 200 requests per second, account-wide. The fix is the same one every AWS SDK's credential provider already implements: cache the session for its lifetime, refresh a few minutes before expiry, never mint one per request.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Request metadata — the only per-call mechanism, and it skips the bill
&lt;/h3&gt;

&lt;p&gt;Every other mechanism attributes cost by &lt;em&gt;who's calling&lt;/em&gt;. This one attributes by &lt;em&gt;what's in the call&lt;/em&gt;, and it's the only one that's genuinely per-request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws bedrock-runtime converse &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model-id&lt;/span&gt; us.anthropic.claude-haiku-4-5-20251001-v1:0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--messages&lt;/span&gt; &lt;span class="s1"&gt;'[{"role":"user","content":[{"text":"hi"}]}]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--request-metadata&lt;/span&gt; &lt;span class="s1"&gt;'{"customer_id":"cust-042","feature":"chat-widget"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That metadata lands in CloudWatch invocation logs — automatically, alongside input and output token counts — the moment you turn on model invocation logging. It does not appear anywhere in Cost Explorer or the Cost and Usage Report. To get a dollar figure, you query the logs and multiply.&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="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;ispresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="n"&gt;requestMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="k"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputTokenCount&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;inputTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="k"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputTokenCount&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;outputTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputTokenCount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;000001&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputTokenCount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;000005&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;estCostUSD&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;stats&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputTokens&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputTokens&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;estCostUSD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran this against two simulated customers and got a clean per-customer split — real token counts, real cost math, computed in one CloudWatch Logs Insights query. I haven't compared this number against an actual invoice line item, but &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/cost-mgmt-faq.html" rel="noopener noreferrer"&gt;AWS's own cost-management guidance is explicit&lt;/a&gt; that a token-times-published-rate estimate doesn't account for volume discounts, committed spend, or whatever pricing tier the account is on — it's a real, defensible number for a dashboard, and it's built from a different formula than whatever your invoice actually applies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The map, end to end
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A[API call to Bedrock] --&amp;gt; B{What are you tagging?}
    B --&amp;gt;|A model resource| C[Inference Profile]
    B --&amp;gt;|A billing container| D[Project / Workspace]
    B --&amp;gt;|The calling role| E[IAM identity tag]
    B --&amp;gt;|The calling session| F[STS session tag]
    B --&amp;gt;|The request itself| G[Request metadata]

    C --&amp;gt; H[Cost Explorer / CUR]
    D --&amp;gt; H
    E --&amp;gt; H
    F --&amp;gt; H
    G --&amp;gt; I[CloudWatch Logs]
    I --&amp;gt; J[Self-computed estimate]

    H --&amp;gt; K[Real invoice dollars,&amp;lt;br/&amp;gt;bound to a resource or identity]
    J --&amp;gt; L[Real per-request granularity,&amp;lt;br/&amp;gt;estimated dollars]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four paths converge on the same billing platform and inherit the same shape: attribution follows a resource or an identity, aggregated by day and usage type, never by individual request. One path breaks out to the request layer and trades the aggregation ceiling for an estimate. There's no version of this that gives you both a per-request breakdown and an invoice-accurate number, on Bedrock, today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this stops being an AWS problem
&lt;/h2&gt;

&lt;p&gt;If you're running a multi-tenant SaaS product on Bedrock, the natural next question is whether any of the five mechanisms above solve per-customer cost — team A pays for tenant X's usage, and you need to know the exact number.&lt;/p&gt;

&lt;p&gt;They don't, and the reason isn't a gap in Bedrock specifically. &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/saas-lens/expenditure-awareness.html" rel="noopener noreferrer"&gt;AWS's own Well-Architected SaaS Lens&lt;/a&gt; states the design point directly: measuring per-tenant consumption in a shared-resource architecture requires the application itself to instrument tenant activity and correlate it with billing data afterward — the billing report alone was never going to enumerate an unbounded, growing customer base. The reference pattern in the same guidance is: capture tenant activity at the request layer (request counts, token counts, whatever correlates with cost in your architecture), store it, then apply that consumption ratio against the aggregate AWS bill for the period. That's mechanism five above, generalized — the SaaS billing layer sits &lt;em&gt;next to&lt;/em&gt; CUR, reading from it, not inside it.&lt;/p&gt;

&lt;p&gt;I went and checked whether another provider had actually solved this differently rather than only packaged it better. &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/add-labels-to-api-calls" rel="noopener noreferrer"&gt;Google's Vertex AI lets a single service account attach a label to every individual request and have that label reach the actual Cloud Billing export&lt;/a&gt; — no per-tenant credential required, which is a real architectural difference from minting a tagged STS session per tenant. But the mechanism has a limit stated plainly in Google's own documentation: each label key holds &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/add-labels-to-api-calls" rel="noopener noreferrer"&gt;at most 1,000 unique values, for the lifetime of the billing account&lt;/a&gt;, silently dropping anything past that with no error surfaced anywhere. A product with a few hundred tenants gets real per-tenant billing visibility with none of the identity plumbing Bedrock's session-tag pattern needs. A product that expects to grow past a thousand tenants hits the same wall — later, and more quietly than a missing feature would announce itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;Pick the mechanism by what you're actually trying to attribute, not by which one sounds most granular. Team, department, cost center — tag the role or the resource, and it's done; that's what all four billing-linked mechanisms are actually built for. Per-customer, in a product with a growing and unbounded tenant base — nothing in Bedrock's billing layer, or in Vertex's once you check the fine print, gives you that natively past a bounded scale. Build it where AWS's own architecture guidance says to build it: instrument the request layer, correlate against the bill yourself, and treat the result as a well-reasoned estimate rather than a substitute for the invoice.&lt;/p&gt;

&lt;p&gt;I haven't found a platform that closes this gap natively — a request-level tag that lands in real, invoice-accurate billing data with no cardinality ceiling. I don't know if that's a hard problem or an unbuilt one.&lt;/p&gt;

</description>
      <category>patterns</category>
      <category>infrastructure</category>
      <category>ainative</category>
      <category>aws</category>
    </item>
    <item>
      <title>Web Search as a Managed Connector: Wiring Amazon Bedrock AgentCore WebSearch Into Any Agent</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sat, 25 Jul 2026 06:17:21 +0000</pubDate>
      <link>https://dev.to/amitrix/web-search-as-a-managed-connector-wiring-amazon-bedrock-agentcore-websearch-into-any-agent-2cmk</link>
      <guid>https://dev.to/amitrix/web-search-as-a-managed-connector-wiring-amazon-bedrock-agentcore-websearch-into-any-agent-2cmk</guid>
      <description>&lt;p&gt;Most "add web search to your agent" integrations are a wrapper around someone else's search API: an API key in an env var, a rate limiter, a result parser, and a bill from a third party. Amazon Bedrock AgentCore WebSearch removes all four. It ships as a managed MCP connector you attach to a Gateway — the search index, auth, and result shaping happen inside AWS, and your agent discovers the tool with a standard &lt;code&gt;tools/list&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;I wired it into my local agents and have run 331 real searches through it. This post covers what makes it worth choosing over a search-API wrapper, how the wiring actually goes together (including the auth), and what the numbers look like after about 10 days of real use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the managed connector actually is
&lt;/h2&gt;

&lt;p&gt;WebSearch on AgentCore &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-bedrock-agentcore-web-search/" rel="noopener noreferrer"&gt;went GA on June 16, 2026&lt;/a&gt;, currently in &lt;code&gt;us-east-1&lt;/code&gt; only. It is a &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-connector-web-search-tool.html" rel="noopener noreferrer"&gt;built-in connector target&lt;/a&gt; on an AgentCore Gateway, spoken over MCP. You attach it with &lt;code&gt;connectorId: "web-search"&lt;/code&gt; and the Gateway handles schema management, endpoint resolution, and service authentication.&lt;/p&gt;

&lt;p&gt;Two things make it more than a search proxy. First, it is &lt;a href="https://aws.amazon.com/blogs/machine-learning/introducing-web-search-on-amazon-bedrock-agentcore/" rel="noopener noreferrer"&gt;backed by a web index Amazon operates directly&lt;/a&gt;, spanning tens of billions of documents, rather than reselling a third-party engine. Second, it returns semantic snippets tuned for a model's context window — ranked excerpts with source URLs, titles, and publication dates — not raw HTML you then have to strip. The design goal is intelligence per token, and it combines the web index with knowledge-graph facts so entities resolve to verified data rather than inferred page text.&lt;/p&gt;

&lt;p&gt;The practical consequence: queries never leave your AWS environment. There is no outbound call to an external search vendor, so there is no data egress and no third-party credential to rotate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why choose it over a search-API wrapper
&lt;/h2&gt;

&lt;p&gt;The reason an agent needs web search at all is grounding. A model's knowledge is frozen at training time, so anything current — a release from last week, a price that changed yesterday, a filing from this morning — is either unknown or hallucinated. WebSearch closes that gap by &lt;a href="https://aws.amazon.com/blogs/aws/announcing-web-search-on-amazon-bedrock-agentcore-ground-your-ai-agents-in-current-accurate-web-knowledge/" rel="noopener noreferrer"&gt;grounding responses in current, cited web knowledge&lt;/a&gt;, which is the difference between an agent that guesses and one that answers.&lt;/p&gt;

&lt;p&gt;The rest of the case is what you &lt;em&gt;don't&lt;/em&gt; build. Rolling your own web search for an agent is &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-connector-web-search-tool.html" rel="noopener noreferrer"&gt;several projects stacked together&lt;/a&gt;: procure a third-party search API, manage keys and quotas and rate limits, parse inconsistent result formats, write snippet-extraction logic so the model gets passages instead of raw HTML, reason about where queries travel and how they're retained, and keep coverage fresh over time. The managed connector collapses all of it into one &lt;code&gt;connectorId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Concretely, the benefits that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Grounding over guessing&lt;/strong&gt; — real-time facts and cited sources instead of stale training data, which directly cuts hallucination on timely questions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero infrastructure&lt;/strong&gt; — no search API to provision, no quotas to tune, no result parser to maintain. The Gateway exposes it as a standard MCP tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework-agnostic&lt;/strong&gt; — any MCP-compatible client works: Strands, LangChain, LangGraph, CrewAI, or a hand-rolled shim. Nothing is tied to one agent framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A purpose-built index, not a reseller&lt;/strong&gt; — backed by an index &lt;a href="https://aws.amazon.com/blogs/machine-learning/introducing-web-search-on-amazon-bedrock-agentcore/" rel="noopener noreferrer"&gt;Amazon operates directly&lt;/a&gt; (tens of billions of documents, refreshed within minutes), the same search infrastructure behind Alexa+, Amazon Q Business, and Kiro. Broad coverage answers long-tail questions a popularity-ranked engine misses, and a knowledge graph resolves entities to verified facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero data egress&lt;/strong&gt; — queries stay inside AWS, which removes an entire category of security and compliance review for teams that care where data travels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage-based pricing&lt;/strong&gt; — &lt;a href="https://aws.amazon.com/blogs/aws/announcing-web-search-on-amazon-bedrock-agentcore-ground-your-ai-agents-in-current-accurate-web-knowledge/" rel="noopener noreferrer"&gt;$7 per 1,000 queries&lt;/a&gt; with no upfront commitment, plus Free Tier credits for new accounts. You pay per search, not for standing infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The through-line: improvements to freshness, coverage, and relevance flow to your agent automatically through the same connector, with no version upgrade or migration on your side.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the wiring
&lt;/h2&gt;

&lt;p&gt;The connector lives in AWS. The caller can be a local agent on your laptop speaking MCP over stdio, or — more commonly — an autonomous agent deployed on AgentCore Runtime or your own compute, calling the Gateway directly. Either way the caller discovers the tool with &lt;code&gt;tools/list&lt;/code&gt; and invokes it with &lt;code&gt;tools/call&lt;/code&gt;; the only difference is how it signs. A deployed agent signs with its execution role; a local agent uses a small shim. The path is the same shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Caller
  · deployed agent on AgentCore Runtime / Lambda / ECS  → execution role signs (SigV4)
  · local agent on your laptop (Codex / Cursor / Zed / Claude Code / Kiro / GitHub Copilot) → MCP shim signs (SigV4)
      → POST https://&amp;lt;gateway-id&amp;gt;.gateway.bedrock-agentcore.&amp;lt;region&amp;gt;.amazonaws.com/mcp
        → target (connectorId: web-search)
          → Amazon web index + knowledge graph
            → ranked snippets + source URLs + titles + dates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You create the Gateway once with &lt;code&gt;authorizerType: AWS_IAM&lt;/code&gt; and &lt;code&gt;protocolType: MCP&lt;/code&gt;, then add a connector target pointing at &lt;code&gt;web-search&lt;/code&gt;. The Gateway assumes an execution role to reach the backend; that role needs no special search permissions because AWS operates the search stack.&lt;/p&gt;

&lt;p&gt;If you want to bound what the tool can reach, the connector supports a &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-connector-web-search-tool.html" rel="noopener noreferrer"&gt;domain denylist&lt;/a&gt; — a list of domains the Web Search Tool is not allowed to query, configured on the target at creation time through the SDK or CLI (&lt;code&gt;create-gateway-target&lt;/code&gt;, the same call that sets &lt;code&gt;connectorId: web-search&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;One thing worth calling out, because it trips people up: &lt;em&gt;configuring&lt;/em&gt; the connector needs current AWS tooling (or the console), but &lt;em&gt;calling&lt;/em&gt; it does not. The invocation path is just a SigV4-signed JSON-RPC POST to the gateway URL, so an agent or shim runs on whatever SDK version it already has.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring in the auth
&lt;/h2&gt;

&lt;p&gt;The Gateway is IAM-authorized, so the caller has to present a SigV4-signed request from an AWS principal. That is the entire auth model: does the caller hold valid AWS credentials for the account that owns the gateway? There is no token endpoint, no client secret, no refresh loop.&lt;/p&gt;

&lt;p&gt;The signing is identical whether the caller is a deployed agent or a local one — it resolves credentials from the standard AWS chain (environment variables, then a named profile, then an instance or container role) and signs each MCP request before sending it. A deployed agent on Runtime or Lambda gets its execution role from that chain; my local shim gets a profile from the same chain. Same code, different credential source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;botocore.session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;botocore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;botocore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;awsrequest&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;botocore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get_credentials&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get_frozen_credentials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;botocore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;awsrequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AWSRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json, text/event-stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MCP-Protocol-Version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2025-06-18&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;botocore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SigV4Auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bedrock-agentcore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;add_auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what &lt;code&gt;get_credentials()&lt;/code&gt; does not take: no API key, no secret, no token. A deployed agent presents its execution role automatically; on my laptop the tool config sets a profile name and a region and botocore does the rest. In neither case is there a search credential in the config to leak, rotate, or expire — the AWS identity the caller already has &lt;em&gt;is&lt;/em&gt; the credential.&lt;/p&gt;

&lt;p&gt;Because resolution is per-process, the same signed path works unchanged across every local agent harness that speaks stdio MCP. Point Codex, Cursor, Zed, Claude Code, Kiro, or GitHub Copilot at the same shim and they all inherit web search, each using whatever profile its environment provides — while a fleet of deployed agents inherits it through their execution roles with no shim at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 331 real searches look like
&lt;/h2&gt;

&lt;p&gt;Numbers from my own gateway over about 10 active days since I started using it — not a benchmark, just the real traffic from running agents.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WebSearch invocations&lt;/td&gt;
&lt;td&gt;331 across 10 active days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Busiest day&lt;/td&gt;
&lt;td&gt;91 calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-to-end latency p50&lt;/td&gt;
&lt;td&gt;635 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-to-end latency p90&lt;/td&gt;
&lt;td&gt;784 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-to-end latency p99&lt;/td&gt;
&lt;td&gt;1,013 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connector backend time (p50)&lt;/td&gt;
&lt;td&gt;547 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SystemErrors&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throttles&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UserErrors&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things stand out. Sub-second p50 end to end, with zero system errors and zero throttles across every call — the managed path held up under bursty agent traffic without any tuning on my side. And the latency is dominated by the search itself: ~547 ms of the ~635 ms p50 is connector backend time, meaning the Gateway and signing overhead adds well under 100 ms. You are paying for the index doing real work, not for glue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where these numbers come from
&lt;/h3&gt;

&lt;p&gt;Every figure above is emitted automatically — there is nothing to instrument. The Gateway publishes to the CloudWatch namespace &lt;code&gt;AWS/Bedrock-AgentCore&lt;/code&gt;, dimensioned per tool, so you can slice latency and error rate for the WebSearch target specifically. &lt;code&gt;TargetExecutionTime&lt;/code&gt; is the connector's own backend time, which is what let me separate search time from gateway overhead above.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it costs, from the actual bill
&lt;/h3&gt;

&lt;p&gt;The pricing claim is easy to verify because it shows up as its own line. In Cost Explorer and the Cost and Usage Report, WebSearch appears under the service &lt;code&gt;Amazon Bedrock AgentCore&lt;/code&gt; with the usage type &lt;code&gt;USE1-WebSearchTool:Consumption-based:Queries&lt;/code&gt;. On my bill, 144 queries in one month cost $1.008 and 152 the next cost $1.064 — exactly $0.007 per query, or the advertised $7 per 1,000, with no rounding surprises. The Gateway itself bills separately and trivially, as &lt;code&gt;USE1-Gateway:Consumption-based:API-Invocations&lt;/code&gt; (fractions of a cent for the same traffic) plus an even smaller &lt;code&gt;Gateway:Consumption-based:Tool-Indexing&lt;/code&gt; line — a fraction of a tenth of a cent, and it scales with the number of tools registered on the gateway rather than with search volume, which fits a per-schema indexing cost for the Gateway's semantic tool discovery. So the cost model is legible: one metered line for searches, one negligible line for gateway invocations, and nothing for standing infrastructure.&lt;/p&gt;

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

&lt;p&gt;Three honest constraints. It is &lt;code&gt;us-east-1&lt;/code&gt; only right now, so if your agents or data residency live elsewhere you are making a cross-region hop or waiting for the &lt;a href="https://aws.amazon.com/blogs/aws/announcing-web-search-on-amazon-bedrock-agentcore-ground-your-ai-agents-in-current-accurate-web-knowledge/" rel="noopener noreferrer"&gt;regional rollout&lt;/a&gt;. The query is capped at &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-connector-web-search-tool.html" rel="noopener noreferrer"&gt;200 characters&lt;/a&gt;, which is fine for natural-language questions but forces you to decompose anything long. And the connector is semantic web search for grounding, not a data feed: the &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-connector-web-search-tool.html" rel="noopener noreferrer"&gt;acceptable-use terms&lt;/a&gt; require you to retain and display source citations on any result you surface, and prohibit bulk-extracting results or using them to build a competing index.&lt;/p&gt;

&lt;p&gt;The open thread I have not closed is per-user authorization. The external path itself is not in doubt: alongside my own IAM-authorized agents, I run a separate JWT-authorized gateway that fronts several tools, where callers present an OAuth token and carry no AWS credentials at all. That proves an external caller can reach a connector without a shared secret. But my gateway authorizes at the coarsest grain it can — it validates that the token comes from my issuer and carries my audience, and nothing more. Every caller behind that token is identical to the gateway.&lt;/p&gt;

&lt;p&gt;The capability to go finer is already there; I just have not wired it. A JWT-authorized Gateway &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy-authorization-flow.html" rel="noopener noreferrer"&gt;evaluates Cedar policies on every call&lt;/a&gt;, constructing an authorization request whose principal is the token's &lt;code&gt;sub&lt;/code&gt; claim, whose action is the tool name, and whose resource is the gateway — so you can write a rule that says &lt;em&gt;this user may call this tool&lt;/em&gt; and have it enforced before the connector ever runs, with conditions that read claims like &lt;code&gt;scope&lt;/code&gt; or &lt;code&gt;role&lt;/code&gt; or even the tool's own arguments. Per-user scoping is a policy I have not authored, not a feature the platform is missing. And because a Gateway's authorizer is IAM &lt;em&gt;or&lt;/em&gt; JWT, fixed at creation, mixing my own agents and external users still means two gateways in front of the same connector — which is exactly why I run them separately today. Authenticated external access works; per-user authorization behind it is the Cedar layer I would wire before I called the multi-user story done.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;If you are giving an agent web search, the question is not which search API to wrap. It is whether the search itself is good enough to ground the agent, and whether the data path is one you can defend. WebSearch answers both: an Amazon-operated index of tens of billions of documents, refreshed within minutes and paired with a knowledge graph, so the agent reasons over current, cited facts instead of stale training data — and every query stays inside your AWS boundary, with no egress to a third-party engine and nothing retained outside AWS. That last part is what turns it from a convenience into something you can put in front of a security review.&lt;/p&gt;

&lt;p&gt;The auth model is the tax you &lt;em&gt;don't&lt;/em&gt; pay on top of that. Because the connector is IAM-authorized, the AWS credential you already manage becomes the credential for search — no new secret, no new parser, no new vendor bill, nothing to rotate. Good search results, a data path that stays where it belongs, and an integration with nothing left to leak: that is the combination worth choosing, and it is why running web search on AWS makes sense rather than bolting a search API wrapper onto the side of your agent.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>mcp</category>
      <category>infrastructure</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Does Graphify Actually Help an AI Coding Agent?</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sat, 25 Jul 2026 05:55:55 +0000</pubDate>
      <link>https://dev.to/amitrix/does-graphify-actually-help-an-ai-coding-agent-4bpi</link>
      <guid>https://dev.to/amitrix/does-graphify-actually-help-an-ai-coding-agent-4bpi</guid>
      <description>&lt;p&gt;The thesis: a codebase map earns its place only when it helps an agent reach a correct answer with lower measured cost.&lt;/p&gt;

&lt;p&gt;Graphify promises a local knowledge graph for code, configuration, and documentation. It turns files into nodes and relationships, then lets an agent query the graph instead of rediscovering the repository through search. That is a plausible mechanism. It is not evidence of a productivity gain.&lt;/p&gt;

&lt;p&gt;The first result is a measurement rule: do not accept the token-reduction claim, the graph visualization, or the feeling that exploration was easier as proof. Test the tool on the work it is meant to improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result So Far
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Against opening four relevant files in full, Graphify reduced retrieval context
from 15,186 to 1,618 tokens: an 83% reduction.&lt;/li&gt;
&lt;li&gt;Against disciplined search plus narrow source snippets, it used 1,618 versus
1,488 tokens: 9% more.&lt;/li&gt;
&lt;li&gt;In a three-question freshness-aware run, the wrapper arm had a 20-second
median versus 17.4 seconds for disciplined search. It fully covered two of
three answer keys; the baseline covered all three.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The wrapper removes command-syntax errors and can narrow exploration. It has&lt;br&gt;
not yet shown a speed, token, or correctness advantage over careful search and&lt;br&gt;
source verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Test Has to Be Local
&lt;/h2&gt;

&lt;p&gt;The published evidence on AI coding productivity points in opposite directions. In a randomized trial, &lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;METR&lt;/a&gt; found that experienced open-source contributors using early-2025 AI tools took 19% longer on their own tasks, even though they believed the tools made them faster. METR now labels that result historical and says it no longer reflects current tools.&lt;/p&gt;

&lt;p&gt;The durable lesson is not that AI slows people down. The durable lesson is that reported confidence and measured completion are different things.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.databricks.com/blog/benchmarking-coding-agents-databricks-multi-million-line-codebase" rel="noopener noreferrer"&gt;Databricks reached the same practical conclusion from the other direction&lt;/a&gt;: evaluate against real tasks from the codebase, review the task and its answer by hand, and use held-out tests rather than an LLM judge that rewards an answer for sounding correct.&lt;/p&gt;

&lt;p&gt;Graphify's own &lt;a href="https://github.com/Graphify-Labs/graphify/blob/v8/README.md" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; makes a narrower claim. Its local parser extracts structure and relationships; its graph can answer scoped queries without reopening every source file. The right experiment tests that exact claim: repository understanding, impact analysis, and architectural navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pilot
&lt;/h2&gt;

&lt;p&gt;Use twelve read-only tasks drawn from one unfamiliar but representative repository. Six run without the graph. Six run with a fresh code-only graph. A second set of matched tasks reverses the order. This counterbalanced design prevents the first condition from winning because the operator learned the repository during the trial.&lt;/p&gt;

&lt;p&gt;The task set needs four categories:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Example question&lt;/th&gt;
&lt;th&gt;Required evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ownership&lt;/td&gt;
&lt;td&gt;Which service enforces a budget or access rule?&lt;/td&gt;
&lt;td&gt;Handler, shared policy code, and test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change impact&lt;/td&gt;
&lt;td&gt;What changes when a new endpoint or tool backend is added?&lt;/td&gt;
&lt;td&gt;Application code, configuration, infrastructure, and docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture&lt;/td&gt;
&lt;td&gt;Why are two components separate instead of merged?&lt;/td&gt;
&lt;td&gt;Current code plus the decision record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operations&lt;/td&gt;
&lt;td&gt;What is the approved deployment or recovery path?&lt;/td&gt;
&lt;td&gt;CLI contract, infrastructure definition, and operator guide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Before the first run, a reviewer writes an answer key for every task. The key names the facts that must appear and the files that establish them. It also lists dependencies that are easy to miss. No tool sees the answer key.&lt;/p&gt;

&lt;p&gt;Each task has a fixed stopping rule: the participant submits a short answer with citations to local files, then states the change or decision they would make. The reviewer scores the answer before seeing whether Graphify was available.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Measure
&lt;/h2&gt;

&lt;p&gt;Time matters, but it is not enough. A fast answer that misses the infrastructure change is worse than a slow answer that finds it.&lt;/p&gt;

&lt;p&gt;Record five fields for every task:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Correctness:&lt;/strong&gt; Did the answer match the answer key?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence coverage:&lt;/strong&gt; Did it cite the source files and decision records that establish the answer?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency coverage:&lt;/strong&gt; Did it identify every required cross-layer effect?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elapsed time:&lt;/strong&gt; From task start to submitted answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exploration cost:&lt;/strong&gt; Raw files opened, search calls, and model usage when the harness exposes it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reviewer also records unsupported assertions. This is the failure mode a map can create: a clean-looking path through the graph can make an inferred connection feel established. Graphify distinguishes extracted and inferred edges. The evaluation must preserve that distinction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Decision Rule
&lt;/h2&gt;

&lt;p&gt;This is a pilot, not a claim about the category. Twelve tasks establish whether the next test is worth running.&lt;/p&gt;

&lt;p&gt;Keep Graphify optional for unfamiliar, cross-layer questions. Admit it to the&lt;br&gt;
default workflow only when it is at least as correct and has either a 20% lower&lt;br&gt;
median completion time or a 20% lower measured retrieval-token cost. If it&lt;br&gt;
saves tokens but produces more unsupported claims, it failed.&lt;/p&gt;

&lt;p&gt;Keep it out of the default workflow when the task already identifies the files to change. A graph has its highest chance of helping during onboarding, architecture review, incident investigation, and change-impact analysis. It has little reason to sit between a builder and a two-file fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Safety Boundary
&lt;/h2&gt;

&lt;p&gt;The first run is code-only and local. Exclude secrets, state, local environment files, generated bundles, dependency directories, and deployment output. Do not enable document or media enrichment, strict hooks, shared graph hosting, or a project-scoped agent instruction during the pilot.&lt;/p&gt;

&lt;p&gt;That leaves one variable under test: whether a local structural map improves the agent's understanding of the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;The first run is complete. It is an exploratory four-task slice, not the&lt;br&gt;
twelve-task counterbalanced study described above.&lt;/p&gt;

&lt;p&gt;Two fresh agents each completed one baseline task and one Graphify-assisted&lt;br&gt;
task. The Graphify condition required graph-first discovery, then limited raw&lt;br&gt;
source verification. The baseline condition used normal repository search and&lt;br&gt;
raw source reads. No task changed code, contacted AWS, or enabled a persistent&lt;br&gt;
agent hook.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Tasks&lt;/th&gt;
&lt;th&gt;Median time&lt;/th&gt;
&lt;th&gt;Raw source files opened&lt;/th&gt;
&lt;th&gt;Answer quality&lt;/th&gt;
&lt;th&gt;Unsupported assertions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline&lt;/td&gt;
&lt;td&gt;Budget enforcement; conditional routing&lt;/td&gt;
&lt;td&gt;17.5s&lt;/td&gt;
&lt;td&gt;6.5 average&lt;/td&gt;
&lt;td&gt;Correct, source-cited, and bounded&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graphify&lt;/td&gt;
&lt;td&gt;Cost attribution; load-balanced routing&lt;/td&gt;
&lt;td&gt;16.5s&lt;/td&gt;
&lt;td&gt;4 average&lt;/td&gt;
&lt;td&gt;Correct after raw-source verification&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The graph itself took 7.1 seconds to build from 299 code files. It produced&lt;br&gt;
4,005 nodes and 10,229 edges in a 12 MB local artifact. Focused &lt;code&gt;explain&lt;/code&gt;&lt;br&gt;
lookups took 0.32 to 0.36 seconds and returned source locations plus&lt;br&gt;
extracted-versus-inferred relationship labels.&lt;/p&gt;

&lt;p&gt;The read: the graph condition opened fewer raw source files. It did not clear&lt;br&gt;
the adoption threshold. The observed one-second median difference is too&lt;br&gt;
small, and the tasks were not identical in difficulty. This unpaired slice&lt;br&gt;
cannot establish a speed or token benefit. The tool is an optional discovery&lt;br&gt;
layer for unfamiliar code paths, not a replacement for source verification.&lt;/p&gt;

&lt;p&gt;Two implementation limits surfaced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Broad natural-language graph queries returned hundreds of nodes and were
truncated. The useful pattern was a narrow query followed by &lt;code&gt;explain&lt;/code&gt; on a
discovered symbol.&lt;/li&gt;
&lt;li&gt;The code-only safety mode omitted Markdown decision records and documentation.
That makes it useful for code and infrastructure tracing, but insufficient
for an architecture question whose authoritative answer lives in a decision
record.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Token Result
&lt;/h2&gt;

&lt;p&gt;The graph also needs a token test. Its value proposition is not that source&lt;br&gt;
code disappears. The value proposition is that an agent reads a structural map&lt;br&gt;
first, then opens only the evidence required to verify the answer.&lt;/p&gt;

&lt;p&gt;The same load-balancing question was measured three ways. The count uses the&lt;br&gt;
&lt;a href="https://github.com/openai/tiktoken" rel="noopener noreferrer"&gt;cl100k_base tokenizer&lt;/a&gt; over the captured&lt;br&gt;
tool output and source text. It excludes the agent's system prompt, tool-call&lt;br&gt;
envelope, and generated answer, so it measures retrieval context rather than&lt;br&gt;
total model cost.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Retrieval pattern&lt;/th&gt;
&lt;th&gt;Input tokens&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Open four relevant files in full&lt;/td&gt;
&lt;td&gt;15,186&lt;/td&gt;
&lt;td&gt;High context cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search, then read narrow source snippets&lt;/td&gt;
&lt;td&gt;1,488&lt;/td&gt;
&lt;td&gt;Lowest cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broad graph query, graph explanation, then source verification&lt;/td&gt;
&lt;td&gt;2,515&lt;/td&gt;
&lt;td&gt;69% more than disciplined search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph explanation, then minimal source verification&lt;/td&gt;
&lt;td&gt;1,618&lt;/td&gt;
&lt;td&gt;9% more than disciplined search&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The result is clear. Graphify reduced context by 83% against opening all four&lt;br&gt;
files in full. It did not save tokens against a careful search-and-snippet&lt;br&gt;
workflow on this focused question.&lt;/p&gt;

&lt;p&gt;That is not a failure of the graph. It defines the right use case. Use it when&lt;br&gt;
the agent does not know where a cross-layer path begins, when the repository is&lt;br&gt;
unfamiliar, or when the alternative is broad file reading. Do not force it&lt;br&gt;
into a two-file question where search already identifies the exact symbols.&lt;/p&gt;

&lt;p&gt;The expanded study needs to record retrieval tokens for every task, with the&lt;br&gt;
same boundary: graph output, raw verification text, and the final generated&lt;br&gt;
answer counted separately. A graph-first workflow earns a default only if it&lt;br&gt;
reduces total context without reducing evidence quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Release Context
&lt;/h2&gt;

&lt;p&gt;Graphify is getting attention because it is new, visible, and moving quickly.&lt;br&gt;
The &lt;a href="https://api.github.com/repos/Graphify-Labs/graphify" rel="noopener noreferrer"&gt;public repository&lt;/a&gt;&lt;br&gt;
was created on April 3, 2026, and the&lt;br&gt;
&lt;a href="https://pypi.org/pypi/graphifyy/json" rel="noopener noreferrer"&gt;PyPI package&lt;/a&gt; first shipped the next&lt;br&gt;
day. By July 24, &lt;a href="https://github.com/Graphify-Labs/graphify/releases" rel="noopener noreferrer"&gt;GitHub release history&lt;/a&gt;&lt;br&gt;
recorded 172 public releases, including 27 releases in the 27 days from June&lt;br&gt;
28 through July 24.&lt;/p&gt;

&lt;p&gt;The adoption signals are real but need interpretation. &lt;a href="https://pypistats.org/api/packages/graphifyy/overall?mirrors=false" rel="noopener noreferrer"&gt;PyPI Stats&lt;/a&gt;&lt;br&gt;
recorded 3.60 million package-download events through July 24, while the&lt;br&gt;
&lt;a href="https://graphify.com/" rel="noopener noreferrer"&gt;project site&lt;/a&gt; reported 93,125 GitHub stars on July 20.&lt;br&gt;
Package downloads are not active users, and star counts do not establish&lt;br&gt;
production use. They establish attention.&lt;/p&gt;

&lt;p&gt;Independent technical guides appeared across April through July, including&lt;br&gt;
&lt;a href="https://www.analyticsvidhya.com/blog/2026/04/graphify-guide/" rel="noopener noreferrer"&gt;Analytics Vidhya&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://fossengineer.com/graphify-code-knowledge-graph/" rel="noopener noreferrer"&gt;Foss Engineer&lt;/a&gt;, and&lt;br&gt;
&lt;a href="https://betterstack.com/community/guides/ai/ai-development/graphify-codebase/" rel="noopener noreferrer"&gt;Better Stack&lt;/a&gt;.&lt;br&gt;
The Hacker News response was smaller: the July Show HN post had two points and&lt;br&gt;
no comments, according to the &lt;a href="https://hn.algolia.com/api/v1/search?query=Graphify-Labs%2Fgraphify&amp;amp;tags=story" rel="noopener noreferrer"&gt;public HN search record&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The read: there is genuine launch momentum around a project that is less than&lt;br&gt;
four months old. The release rate is also a maturity signal. Treat the current&lt;br&gt;
CLI as fast-moving developer tooling, not stable shared infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freshness And Safety Test
&lt;/h2&gt;

&lt;p&gt;An isolated temporary corpus tested local extraction, ignored-file handling,&lt;br&gt;
and incremental rebuilds without a model backend.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Python and Terraform/HCL extraction&lt;/td&gt;
&lt;td&gt;Passed: expected symbols and resources appeared&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ignored secret-like file&lt;/td&gt;
&lt;td&gt;Passed: it did not appear in the graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unchanged re-extraction&lt;/td&gt;
&lt;td&gt;Passed: zero files changed and the graph hash stayed identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add and delete source files&lt;/td&gt;
&lt;td&gt;Passed: the new symbol appeared and deleted-file nodes disappeared&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code-only follow-up update&lt;/td&gt;
&lt;td&gt;Mixed: &lt;code&gt;update --force&lt;/code&gt; added Markdown nodes after the initial code-only extraction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row matters. A code-only initial extraction is the correct safety&lt;br&gt;
boundary. Do not assume every follow-up command preserves that boundary without&lt;br&gt;
an explicit test on the exact version in use. Keep graph output outside the&lt;br&gt;
repository and retain &lt;code&gt;GRAPHIFY_QUERY_LOG_DISABLE=1&lt;/code&gt; until query logging is&lt;br&gt;
independently verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanded Agent Run
&lt;/h2&gt;

&lt;p&gt;A second agent run was intended to broaden the task sample across identity and&lt;br&gt;
routing questions. It did not produce a publishable performance score.&lt;/p&gt;

&lt;p&gt;The experimental instruction described the graph command too loosely. Multiple&lt;br&gt;
agents first invoked an invalid command before reaching the correct&lt;br&gt;
&lt;code&gt;graphify query "&amp;lt;question&amp;gt;" --graph &amp;lt;path&amp;gt;&lt;/code&gt; form. That invalidates elapsed&lt;br&gt;
time as a comparison. The answers still required raw source verification, and&lt;br&gt;
the graph output remained broad enough to need narrowing.&lt;/p&gt;

&lt;p&gt;This is useful operational evidence. Graphify needs a precise local skill or&lt;br&gt;
wrapper that supplies valid query syntax and a narrow-query pattern. Without&lt;br&gt;
that layer, agent setup errors erase any small retrieval-time benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freshness-Aware Wrapper Run
&lt;/h2&gt;

&lt;p&gt;The wrapper was then tested on the same repository revision with a fresh&lt;br&gt;
code-only graph, three matched questions, and an explicit first command:&lt;br&gt;
&lt;code&gt;graph-discover query "&amp;lt;question&amp;gt;" --repo &amp;lt;repository&amp;gt; --budget 800&lt;/code&gt;. It passed&lt;br&gt;
the integration test: all three graph-first runs used valid syntax, checked the&lt;br&gt;
freshness record, and verified their conclusions in raw source. The wrapper&lt;br&gt;
also kept graph artifacts outside the repository.&lt;/p&gt;

&lt;p&gt;The result does not show a speed win. The baseline used disciplined search and&lt;br&gt;
narrow source reads; the wrapper run used graph discovery followed by source&lt;br&gt;
verification. The timing below is agent-reported and one run per condition.&lt;br&gt;
Five runs only had whole-second resolution because the local &lt;code&gt;date&lt;/code&gt; command&lt;br&gt;
did not support millisecond output.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Baseline time&lt;/th&gt;
&lt;th&gt;Wrapper time&lt;/th&gt;
&lt;th&gt;Baseline files read&lt;/th&gt;
&lt;th&gt;Wrapper files read&lt;/th&gt;
&lt;th&gt;Answer coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Team-budget enforcement&lt;/td&gt;
&lt;td&gt;17.4s&lt;/td&gt;
&lt;td&gt;34s&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Full in both arms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth login and credential storage&lt;/td&gt;
&lt;td&gt;18s&lt;/td&gt;
&lt;td&gt;18s&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Full in both arms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic-routing rendering&lt;/td&gt;
&lt;td&gt;14s&lt;/td&gt;
&lt;td&gt;20s&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Full baseline; wrapper missed one deployment-boundary fact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median&lt;/td&gt;
&lt;td&gt;17.4s&lt;/td&gt;
&lt;td&gt;20s&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Baseline 3/3 full; wrapper 2/3 full&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The read: the wrapper fixes the invalid-command problem and can reduce source&lt;br&gt;
exploration. It did not beat disciplined search on elapsed time in this sample,&lt;br&gt;
and the routing answer shows why correctness remains the first gate. The&lt;br&gt;
wrapper found the routing renderer but missed that the active data-plane&lt;br&gt;
configuration is separately rendered and a per-team dynamic reload is still a&lt;br&gt;
follow-up.&lt;/p&gt;

&lt;p&gt;No retrieval-token trace was captured for this run. Fewer files opened is not&lt;br&gt;
a token-savings result. The earlier focused token test still stands: Graphify&lt;br&gt;
beat opening four full files, but it did not beat careful search plus narrow&lt;br&gt;
snippets. The next study needs captured graph output and source excerpts under&lt;br&gt;
the same tokenizer, then a blinded answer-key score before comparing medians.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adoption Decision
&lt;/h2&gt;

&lt;p&gt;Keep Graphify available only behind an explicit, freshness-aware wrapper for&lt;br&gt;
unfamiliar, cross-layer questions. Do not commit graph artifacts, enable a&lt;br&gt;
repository hook, or use semantic document extraction yet.&lt;/p&gt;

&lt;p&gt;The next run needs the full twelve-task counterbalanced design, matched task&lt;br&gt;
difficulty, and an independent reviewer who does not know the condition. Until&lt;br&gt;
then, the result is directional evidence about navigation cost, not a published&lt;br&gt;
productivity claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Open Question
&lt;/h2&gt;

&lt;p&gt;A codebase graph can reduce rediscovery. It can also become stale, omit an indirect dependency, or encourage an agent to trust a summary over the code. The pilot measures the first benefit. It does not settle the freshness problem.&lt;/p&gt;

&lt;p&gt;The question is not whether an agent can draw a map. It is whether the map improves a correct decision before the code changes underneath it.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>contextengineering</category>
      <category>patterns</category>
      <category>buildlog</category>
    </item>
    <item>
      <title>Prompt Caching Is a Harness Design Problem, Not an API Toggle</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sat, 25 Jul 2026 04:13:34 +0000</pubDate>
      <link>https://dev.to/amitrix/prompt-caching-is-a-harness-design-problem-not-an-api-toggle-2c2b</link>
      <guid>https://dev.to/amitrix/prompt-caching-is-a-harness-design-problem-not-an-api-toggle-2c2b</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A 186-request matrix produced 84.4% normalized input savings with one write and 20 reads, but changing the cache key every call cost 25% more than uncached input.&lt;/li&gt;
&lt;li&gt;Reordering tools or changing a description or schema forced a full rewrite; changing tool results after a stable breakpoint preserved the cached prefix.&lt;/li&gt;
&lt;li&gt;TTL controls how long reusable work survives. The harness controls whether two requests contain reusable work at all.&lt;/li&gt;
&lt;li&gt;Treat rendered-prefix stability, cache reads, cache writes, and post-compaction recovery as production metrics, not provider defaults.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;A cache flag can be enabled while an agent pays to rebuild the cache on every call.&lt;/p&gt;

&lt;p&gt;That is the central mistake in how prompt caching gets discussed. The API exposes the capability. The harness determines whether the capability produces a hit, a miss, or a stream of expensive writes.&lt;/p&gt;

&lt;p&gt;I tested that distinction across 186 successful requests in 40 staged agent sessions, then ran a separate 30-track retention suite across OpenAI and Claude models on &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html" rel="noopener noreferrer"&gt;Amazon Bedrock&lt;/a&gt;. The result was consistent: prompt caching is not primarily a TTL decision. It is a request-construction discipline.&lt;/p&gt;

&lt;p&gt;The provider owns the cache. The harness owns the prefix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same API produced opposite economics
&lt;/h2&gt;

&lt;p&gt;The test matrix covered implicit and explicit caching, append-only conversations, prompt sizes from below the cache threshold to 240,000 tokens, tool mutations, cache-key changes, concurrent calls, and delayed retention probes.&lt;/p&gt;

&lt;p&gt;The strongest cost result came from the simplest pattern: write one stable prefix, then reuse it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Request pattern&lt;/th&gt;
&lt;th&gt;Normalized input savings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One cache write, one cache read&lt;/td&gt;
&lt;td&gt;32.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One cache write, three cache reads&lt;/td&gt;
&lt;td&gt;61.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One cache write, five concurrent reads&lt;/td&gt;
&lt;td&gt;70.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One cache write, twenty concurrent reads&lt;/td&gt;
&lt;td&gt;84.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New cache key on every request&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;25% more expensive&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The calculation uses the current GPT-5.6 pricing shape documented by &lt;a href="https://developers.openai.com/api/docs/guides/prompt-caching" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html" rel="noopener noreferrer"&gt;Amazon Bedrock&lt;/a&gt;: writes cost 1.25 times normal input, while reads receive a 90% discount.&lt;/p&gt;

&lt;p&gt;The feature did not create the savings. Reuse did. With no reuse, the write premium made caching worse than ordinary input.&lt;/p&gt;

&lt;p&gt;That distinction becomes more important inside an agent loop. A coding harness rebuilds a request from system instructions, repository guidance, tool definitions, conversation history, tool calls, tool results, environment state, and the newest user turn. Every one of those components can preserve or destroy the common prefix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool catalogs are part of the cache key
&lt;/h2&gt;

&lt;p&gt;The tool tests made the harness boundary visible.&lt;/p&gt;

&lt;p&gt;An unchanged tool catalog produced an 8,556-token cache read. Reordering the same tools caused a new write. Changing one tool description caused a new write. Changing one JSON schema caused a new write.&lt;/p&gt;

&lt;p&gt;The tools remained semantically similar. The rendered prefix did not.&lt;/p&gt;

&lt;p&gt;This matches the provider contracts. &lt;a href="https://developers.openai.com/api/docs/guides/prompt-caching" rel="noopener noreferrer"&gt;OpenAI requires tools and images to remain identical&lt;/a&gt; for an exact prefix match. &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html" rel="noopener noreferrer"&gt;Amazon Bedrock processes cacheable content in tools → system → messages order&lt;/a&gt;; changing tools invalidates the system and message caches that follow. &lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;Anthropic documents the same hierarchy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The practical consequence is larger than “sort your JSON.” The tool registry is now part of the cost architecture.&lt;/p&gt;

&lt;p&gt;A harness that discovers tools dynamically, changes descriptions at runtime, emits schemas in nondeterministic order, or injects session-specific metadata before its stable instructions can have caching enabled and still miss continuously. Tool discovery, serialization, and prompt construction are no longer separate implementation details. They meet in the rendered prefix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic work belongs after the boundary
&lt;/h2&gt;

&lt;p&gt;Dynamic tool results behaved differently in the same matrix.&lt;/p&gt;

&lt;p&gt;I kept the instructions and tool catalog fixed, placed an explicit breakpoint after them, and changed only the tool result that followed. Both requests retained the same 8,556-token cache hit with no new write.&lt;/p&gt;

&lt;p&gt;That is the architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[stable tools]
[stable system instructions]
[stable repository or task context]
[cache breakpoint]
[conversation turns]
[tool calls and results]
[latest user input]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact fields differ by provider. The invariant does not: stable content first, volatile content later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cookbook.openai.com/examples/prompt_caching_201" rel="noopener noreferrer"&gt;OpenAI's Prompt Caching 201 guide&lt;/a&gt; describes the same pattern in Codex: system instructions, tool definitions, sandbox configuration, and environment context stay consistently ordered, while new messages append to the conversation. The guide also reports one coding workload improving its hit rate from 60% to 87% after adding a stable &lt;code&gt;prompt_cache_key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The cache key matters because reuse has two conditions: the prefix must match, and requests must reach compatible cache capacity. A key that changes every call fragments reuse. A key shared across too much traffic can overflow one routing bucket. The harness owns that partitioning decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  TTL is retention, not reuse
&lt;/h2&gt;

&lt;p&gt;The original version of my prompt-caching explainer overemphasized the five-minute TTL. The live tests showed why that is the wrong organizing principle.&lt;/p&gt;

&lt;p&gt;Provider and model contracts differ:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tested model family&lt;/th&gt;
&lt;th&gt;Requested retention&lt;/th&gt;
&lt;th&gt;Observed result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna and Terra&lt;/td&gt;
&lt;td&gt;30-minute minimum&lt;/td&gt;
&lt;td&gt;Hit at 10 minutes; rewrite at 31 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5 and Opus 4.8&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;td&gt;Rewrite at 6 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5 and Opus 4.8&lt;/td&gt;
&lt;td&gt;1 hour&lt;/td&gt;
&lt;td&gt;Hit at 31 minutes; rewrite at 61 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each delayed probe used an independent cache entry, so an earlier hit could not refresh the entry tested later. For GPT-5.6, &lt;code&gt;30m&lt;/code&gt; is the only supported value and &lt;a href="https://developers.openai.com/api/docs/guides/prompt-caching" rel="noopener noreferrer"&gt;sets a minimum lifetime, not an exact expiration&lt;/a&gt;. OpenAI may retain an entry longer. These observations establish the cache state at each probe time, not the exact millisecond of eviction.&lt;/p&gt;

&lt;p&gt;TTL answers, “How long can matching work remain reusable?” Prefix identity answers, “Is this still the same work?” The second question belongs to the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six harness responsibilities
&lt;/h2&gt;

&lt;p&gt;Prompt-cache performance emerges from six parts of the agent harness.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Harness component&lt;/th&gt;
&lt;th&gt;Cache responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Instruction manager&lt;/td&gt;
&lt;td&gt;Keep durable instructions byte-stable; move timestamps and request IDs out of the prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool registry&lt;/td&gt;
&lt;td&gt;Use deterministic tool order, descriptions, and schemas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context builder&lt;/td&gt;
&lt;td&gt;Put shared repository context before session-specific state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversation manager&lt;/td&gt;
&lt;td&gt;Append turns instead of rewriting earlier history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compactor&lt;/td&gt;
&lt;td&gt;Treat compaction as a planned cache reset, then stabilize the new summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router and telemetry&lt;/td&gt;
&lt;td&gt;Use stable cache keys and measure reads, writes, misses, cost, and time to first token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Compaction exposes the hardest tradeoff. Removing or summarizing old turns reduces context size, but rewriting history also breaks the existing prefix. OpenAI's caching guide calls this tension out directly: context engineering rewards selective change, while prompt caching rewards stability.&lt;/p&gt;

&lt;p&gt;The right response is not to avoid compaction. It is to make the reset observable. Record the prompt and tool bundle fingerprint, expect one cold write after compaction, then verify that later turns read the new prefix. A cache miss caused by an intentional state transition is healthy. A cache miss caused by randomized tool order is a regression.&lt;/p&gt;

&lt;h2&gt;
  
  
  The research reaches the same conclusion
&lt;/h2&gt;

&lt;p&gt;The strongest external confirmation comes from a &lt;a href="https://arxiv.org/html/2601.06007v1" rel="noopener noreferrer"&gt;study of more than 500 long-horizon agent sessions&lt;/a&gt; across OpenAI, Anthropic, and Google models.&lt;/p&gt;

&lt;p&gt;The study measured 45–80% API cost reductions and 13–31% time-to-first-token improvements. Its more important result was architectural: system-prompt-only caching and strategies that excluded dynamic tool results produced more consistent benefits than naive full-context caching. In one condition, full-context caching made latency worse because the system paid write overhead for dynamic content that was not reused.&lt;/p&gt;

&lt;p&gt;That is the same failure mode the cost table exposes. A cache write is an investment. The harness needs to decide whether the content before a breakpoint has a realistic path to later reads.&lt;/p&gt;

&lt;p&gt;Anthropic describes the production consequence even more directly in its &lt;a href="https://claude.com/blog/lessons-from-building-claude-code-prompt-caching-is-everything" rel="noopener noreferrer"&gt;Claude Code prompt-caching engineering notes&lt;/a&gt;: the team builds the harness around prompt caching, alerts on hit-rate regressions, preserves the main conversation prefix during compaction, and avoids changing tool definitions mid-session. That is not an API configuration checklist. It is an agent architecture.&lt;/p&gt;

&lt;p&gt;Latency also needs separate treatment. In my matrix, cache behavior was functionally reliable, but short-prompt latency did not improve consistently. One 128,000-token Terra request improved from 3.935 seconds cold to 1.868 seconds warm; the comparable Luna calls were effectively unchanged. Cost and token accounting were stronger signals than a handful of end-to-end timing samples.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's missing: cache observability at the harness layer
&lt;/h2&gt;

&lt;p&gt;Provider metrics report cached tokens and cache writes. They do not explain which harness change fragmented the prefix.&lt;/p&gt;

&lt;p&gt;A production harness needs four additional signals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A fingerprint for the rendered stable prefix.&lt;/li&gt;
&lt;li&gt;A separate fingerprint for the ordered tool bundle.&lt;/li&gt;
&lt;li&gt;Cache-read and cache-write tokens by prompt version.&lt;/li&gt;
&lt;li&gt;An event marking intentional resets such as compaction, tool-version changes, or model switches.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without those signals, a declining hit rate appears as a larger bill. With them, it becomes a deploy regression tied to a specific prompt or tool bundle.&lt;/p&gt;

&lt;p&gt;Anthropic has started exposing &lt;a href="https://docs.anthropic.com/en/build-with-claude/cache-diagnostics" rel="noopener noreferrer"&gt;cache diagnostics&lt;/a&gt; that identify whether two requests diverged in tools, system instructions, or message history. The broader opportunity is provider-neutral diagnostics inside the harness, before requests leave the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;Enabling prompt caching is the first line of implementation, not the end of the work.&lt;/p&gt;

&lt;p&gt;The durable pattern is simple: serialize stable instructions and tools deterministically, place dynamic state after a deliberate boundary, append conversation turns, partition cache keys around real reuse, and make writes as visible as reads.&lt;/p&gt;

&lt;p&gt;The unresolved part is dynamic tool discovery. Loading every tool preserves one stable catalog but spends context and can reduce tool-selection quality. Loading tools on demand improves relevance but changes the prefix. Deferred tool search and request-level tool restrictions offer a middle path, but the right balance still needs workload-level measurement.&lt;/p&gt;

&lt;p&gt;That is the next cache problem for coding agents: not whether the API supports caching, but whether a changing tool surface can remain both selective and reusable.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>contextengineering</category>
      <category>patterns</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Flux LoRA fine-tuning on fal.ai is shockingly simple</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Tue, 21 Jul 2026 02:44:45 +0000</pubDate>
      <link>https://dev.to/amitrix/flux-lora-fine-tuning-on-falai-is-shockingly-simple-2jb7</link>
      <guid>https://dev.to/amitrix/flux-lora-fine-tuning-on-falai-is-shockingly-simple-2jb7</guid>
      <description>&lt;p&gt;I needed consistent visual style across 50+ blog post images. Traditional fine-tuning pipelines felt heavy. fal.ai changed that.&lt;/p&gt;

&lt;p&gt;This isn't a toy example, either — the header image on this very post was generated by the LoRA trained through this exact pipeline. Same base model, same platform, no separate demo needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two-call pattern
&lt;/h2&gt;

&lt;p&gt;Inference is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@fal-ai/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fal-ai/flux/dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fallingwater in the style of aclvisual, architectural photography&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;portrait_4_3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;num_inference_steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;guidance_scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;num_images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine-tuning a LoRA is two calls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload your reference images to fal storage.&lt;/li&gt;
&lt;li&gt;Start the training job.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Upload images&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zipBlob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refs.zip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Train&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;training&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fal-ai/flux-lora-fast-training&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;images_data_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;trigger_word&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aclvisual&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;create_masks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;onQueueUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IN_PROGRESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;LoRA ready:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;training&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lora_url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use the trained LoRA in inference exactly like any other model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fal-ai/flux-lora&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lora_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;training&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lora_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;trigger_word&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aclvisual&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What actually surprised me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No custom training scripts. No GPU management. No dataset formatting hell.&lt;/li&gt;
&lt;li&gt;Training jobs are async and resumable. Close your terminal; the job keeps running.&lt;/li&gt;
&lt;li&gt;The resulting LoRA is a single &lt;code&gt;.safetensors&lt;/code&gt; file hosted by fal. You can use it immediately or download it.&lt;/li&gt;
&lt;li&gt;Cost is predictable: ~$2–5 to train on 8–12 images, then pennies per generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used this exact flow to train the house style LoRA that produces every post header image on this site, then regenerated the entire catalog against it. The whole process (upload → train → dozens of images) took under 30 minutes of wall time and cost less than a coffee.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it still falls short
&lt;/h2&gt;

&lt;p&gt;fal's strength is speed and simplicity. What it doesn't give you is deep control over the training process itself. If you need custom schedulers, very specific captioning strategies, or multi-concept training with heavy regularization, you will eventually outgrow the hosted endpoints and move to something like Diffusers on your own hardware or a more configurable platform.&lt;/p&gt;

&lt;p&gt;For most practitioner use cases—style LoRAs, character consistency, product shots—the hosted path is not just "good enough." It is dramatically better than the alternatives I tried.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;If your mental model of fine-tuning still includes "spin up a GPU, clone repo, fight with dependencies," update it. fal has collapsed the distance between "I have some images" and "I have a working LoRA I can call from code" to roughly the same effort as calling an inference endpoint.&lt;/p&gt;

&lt;p&gt;The open thread: how long until every major model host offers this same two-call training experience as a table-stakes feature? And what does that do to the current "fine-tuning as a service" market?&lt;/p&gt;

</description>
      <category>flux</category>
      <category>finetuning</category>
      <category>fal</category>
      <category>imagegeneration</category>
    </item>
    <item>
      <title>Building AI Voice Agents with Amazon Nova Sonic and LiveKit: Patterns, Architecture, and a RAG Latency Surprise</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Tue, 21 Jul 2026 01:22:15 +0000</pubDate>
      <link>https://dev.to/amitrix/building-ai-voice-agents-with-amazon-nova-sonic-and-livekit-patterns-architecture-and-a-rag-4np8</link>
      <guid>https://dev.to/amitrix/building-ai-voice-agents-with-amazon-nova-sonic-and-livekit-patterns-architecture-and-a-rag-4np8</guid>
      <description>&lt;p&gt;I spent a few hours building a series of voice AI agents on Amazon Nova 2 Sonic and LiveKit's Agents framework — starting from a basic voice round-trip and working up to a phone-answering restaurant concierge with real persistence, and a separate agent grounded in a real knowledge base. This is what actually held up: the patterns worth reusing, the architecture that survived a real phone call, and one latency finding that contradicts the standard assumption about voice RAG.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/aws/introducing-amazon-nova-2-sonic-next-generation-speech-to-speech-model-for-conversational-ai/" rel="noopener noreferrer"&gt;Amazon Nova 2 Sonic&lt;/a&gt; is a speech-to-speech model — it runs speech understanding, reasoning, tool use, and speech generation as one bidirectional stream, not a chained ASR → LLM → TTS pipeline. That matters for more than latency: acoustic context — tone, pace, hesitation — never gets flattened into a text transcript in between, so the model can respond to &lt;em&gt;how&lt;/em&gt; something was said, not just what was said.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/machine-learning/build-real-time-conversational-ai-experiences-using-amazon-nova-sonic-and-livekit/" rel="noopener noreferrer"&gt;LiveKit's Agents framework&lt;/a&gt; handles the part that has nothing to do with conversational AI and everything to do with real-time media: audio capture and streaming, voice activity detection, turn-taking, WebRTC transport, session lifecycle. LiveKit's own plugin for Nova Sonic means you write an &lt;code&gt;AgentSession&lt;/code&gt; and a handful of tools; you don't write a media pipeline.&lt;/p&gt;

&lt;p&gt;Together, that's a small, honest surface area: the model owns the conversation, LiveKit owns the wire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patterns that held up
&lt;/h2&gt;

&lt;p&gt;A few things worked consistently well enough, across enough different agents, that I'd call them defaults rather than one-off wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interruption and multi-turn memory work out of the box.&lt;/strong&gt; Barge-in — talking over the agent mid-response — and remembering earlier turns in the same conversation both worked cleanly on the first real test, with no special handling required on my end. This is the thing a cascaded STT/LLM/TTS pipeline has to engineer explicitly; a native speech-to-speech model gets it from the architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool calls stay responsive during slow operations, if you let them.&lt;/strong&gt; A simple tool call (a time lookup) completed in about a second. A deliberately slow tool (a 5-second simulated lookup) didn't block the conversation — the model replied to a second, unrelated request while the slow tool was still in flight, then picked back up within roughly 0.01 seconds of the tool actually completing. It's watching for completion, not blocking on it. That's a real design affordance: you can let a slow backend call run without the caller sitting in dead air the whole time, as long as your prompt gives the model permission to keep talking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small toolsets, with a confirmation gate before every write.&lt;/strong&gt; The restaurant concierge agent runs on 9 tools — inside &lt;a href="https://docs.livekit.io/agents/logic/tools/design/" rel="noopener noreferrer"&gt;LiveKit's own guidance of 5 to 10 tools per agent&lt;/a&gt;, since tool-selection accuracy degrades past that. Every write (booking a reservation, confirming an order) takes a &lt;code&gt;read_back&lt;/code&gt; parameter the model can only set to &lt;code&gt;true&lt;/code&gt; after it has actually spoken the details back to the caller and gotten confirmation — call it with &lt;code&gt;read_back=false&lt;/code&gt; and the tool hands back the exact wording the model should use to read the details back first. Writes also run with interruptions disabled, so a caller talking over the agent mid-confirmation can't leave a booking half-committed. That's the difference between a demo and something you'd trust with a real reservation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multilingual support is broad, and the one documented limitation is narrower than it reads.&lt;/strong&gt; Nova 2 Sonic supports 16 voices across 8 languages, including mid-conversation language switching. AWS's own &lt;a href="https://docs.aws.amazon.com/ai/responsible-ai/nova-sonic/overview.html" rel="noopener noreferrer"&gt;AI Service Card states plainly&lt;/a&gt; that the model "does not support real-time speech-to-speech translation," and that's true if you ask it to act as a continuous interpreter — across repeated testing, it occasionally self-limited on that framing, in-language, and then still attempted a partial translation anyway. For straightforward one-off sentence translation, though, it was accurate and consistent across dozens of test runs in two languages. Worth knowing the difference before you rule the capability out entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telephony deployment looks nothing like a call center you'd provision yourself.&lt;/strong&gt; A phone number tied to a LiveKit SIP dispatch rule routes inbound calls to an explicitly named agent — different from the automatic dispatch used for browser/local testing, and &lt;a href="https://docs.livekit.io/agents/" rel="noopener noreferrer"&gt;LiveKit's documented recommendation for telephony specifically&lt;/a&gt;. The worker that actually answers calls runs as a container on LiveKit Cloud's managed compute, deployed the same way you'd deploy any containerized service — and it scales to zero replicas when nobody's calling, spinning one up per inbound call. There's no EC2 instance sitting idle, no process to keep running by hand. The AWS side of the bill is similarly usage-shaped: DynamoDB on on-demand billing, Bedrock metered per invocation. This is a serverless cost model end to end, not a traditional always-on stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference architecture: telephony + persistence
&lt;/h2&gt;

&lt;p&gt;This is the shape that actually took a real inbound phone call, in production:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Caller (PSTN)"] --&amp;gt; B["LiveKit SIP number&amp;lt;br/&amp;gt;dispatch rule routes by agent_name"]
    B --&amp;gt; C["LiveKit Cloud managed agent&amp;lt;br/&amp;gt;scales to zero when idle,&amp;lt;br/&amp;gt;one replica per inbound call"]
    C --&amp;gt; D["Nova 2 Sonic — bidirectional stream&amp;lt;br/&amp;gt;speech understanding + reasoning +&amp;lt;br/&amp;gt;tool selection + speech generation&amp;lt;br/&amp;gt;(one model, one connection)"]
    D --&amp;gt; E["Read-only lookups&amp;lt;br/&amp;gt;menu, hours, availability&amp;lt;br/&amp;gt;served from a static fixture"]
    D --&amp;gt; F["Write attempt&amp;lt;br/&amp;gt;book reservation / confirm order"]
    F --&amp;gt; G{"read_back confirmed&amp;lt;br/&amp;gt;by caller?"}
    G --&amp;gt;|no| D
    G --&amp;gt;|yes| H["Commit write"]
    H --&amp;gt; I["Persistence — DynamoDB&amp;lt;br/&amp;gt;on-demand billing&amp;lt;br/&amp;gt;keyed by confirmation code"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No knowledge base in this path — the menu and hours are a static fixture, deliberately kept simple. That's a separate pattern, tested as its own agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grounding a voice agent in a knowledge base — and a real latency surprise
&lt;/h2&gt;

&lt;p&gt;Adding Retrieval-Augmented Generation to a voice agent is straightforward: register a tool backed by &lt;a href="https://docs.aws.amazon.com/nova/latest/userguide/speech-rag.html" rel="noopener noreferrer"&gt;Amazon Bedrock Knowledge Bases&lt;/a&gt;, let the model call it, let it speak the retrieved content back. I tested this as its own standalone agent, against a real technical knowledge base — not a toy dataset — and it worked correctly: asked about a specific technical topic, the reply cited real, specific details that were actually present in the source content, not fabricated.&lt;/p&gt;

&lt;p&gt;But the response took noticeably longer than every other tool I'd tested — 46 to 100-plus seconds end to end, against roughly a second for a simple lookup. The instinct, and the standard advice, is to blame the vector database. A &lt;a href="https://arxiv.org/html/2603.02206v1" rel="noopener noreferrer"&gt;Salesforce AI Research paper on voice RAG&lt;/a&gt; frames the problem exactly that way: &lt;em&gt;"A typical vector database query adds 50–300ms to the response pipeline, which... pushes total latency well beyond the 200ms budget required for natural conversational flow."&lt;/em&gt; That's a reasonable place to start, and for a lot of RAG pipelines it's exactly right.&lt;/p&gt;

&lt;p&gt;I wanted real numbers instead of a guess, so I isolated each leg of the pipeline and timed it separately, across three identical runs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Leg&lt;/th&gt;
&lt;th&gt;Run 1&lt;/th&gt;
&lt;th&gt;Run 2&lt;/th&gt;
&lt;th&gt;Run 3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Direct retrieval, isolated (no model)&lt;/td&gt;
&lt;td&gt;0.46s&lt;/td&gt;
&lt;td&gt;0.40s&lt;/td&gt;
&lt;td&gt;0.41s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to tool invocation (model decides to call it)&lt;/td&gt;
&lt;td&gt;1.24s&lt;/td&gt;
&lt;td&gt;1.08s&lt;/td&gt;
&lt;td&gt;1.21s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval call itself, inside the pipeline&lt;/td&gt;
&lt;td&gt;0.55s&lt;/td&gt;
&lt;td&gt;0.48s&lt;/td&gt;
&lt;td&gt;0.53s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tool completion → final spoken reply&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;89.67s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;55.39s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;68.53s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total, request to reply&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;91.47s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;56.95s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70.28s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Retrieval and tool-decision latency were both fast and consistent — under 1.3 seconds combined, matching an isolated direct-call benchmark almost exactly. The summarization step — Nova Sonic turning roughly 1,500 characters of dense retrieved content into a spoken answer — accounted for over 99% of total latency, every single time, ranging 55 to 90 seconds by itself. It wasn't a bug or a fluke: I initially suspected a known class of Nova Sonic tool-calling issue where the model appears to hang after a tool response when multiple tools are registered, but isolated single-tool testing with a longer timeout ruled that out cleanly. The model wasn't hanging — it was genuinely taking that long to compose a spoken answer from that much dense source material.&lt;/p&gt;

&lt;p&gt;That's the opposite of where the conventional wisdom points. If you're building a voice agent grounded in a knowledge base and you're worried about latency, a faster vector database or a semantic cache in front of it is an answer to a question you probably don't have. The lever that actually moves is what you hand the model to summarize: fewer chunks, shorter chunks, or a retrieval step that returns something closer to a direct answer than a stack of dense paragraphs for the model to condense on the fly.&lt;/p&gt;

&lt;p&gt;It also changes what you tell the caller. A 60-to-90 second silence on a phone call reads as broken, even when it's working correctly. The fix that mattered most wasn't architectural — it was conversational: have the agent say "let me check that" before it goes quiet, the same thing a real support rep says when they're actually looking something up. That one line of UX design did more for the felt experience than any latency optimization would have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits in the industry
&lt;/h2&gt;

&lt;p&gt;Voice AI has moved past proof-of-concept into a real, fast-growing category — one market estimate puts &lt;a href="https://market.us/press-release/voice-ai-agents-market/" rel="noopener noreferrer"&gt;voice AI agents at $2.4B in 2024, growing to $47.5B by 2034&lt;/a&gt; at a 34.8% CAGR, with BFSI and large enterprises as the earliest heavy adopters. In the restaurant vertical specifically — the use case I built the telephony pattern around — the pattern is consistent across every case study I found: &lt;a href="https://www.slang.ai/customers" rel="noopener noreferrer"&gt;Slang.ai&lt;/a&gt; reports 10x ROI and 200+ reservations booked monthly per location on average across its customer base, with &lt;a href="https://www.implicator.ai/slang-ai-proved-restaurants-need-voice-ai-now-it-needs-to-prove-they-need-slang/" rel="noopener noreferrer"&gt;25M+ calls processed across 2,000+ locations&lt;/a&gt;. The category is crowded now — Loman, Hostie, Revmo, and others are all building variations of the same core loop: answer the phone, understand intent, take the action.&lt;/p&gt;

&lt;p&gt;What's notable is that the &lt;em&gt;reference pattern&lt;/em&gt; for this use case is converging across vendors, independent of which model or framework you use. &lt;a href="https://docs.livekit.io/reference/recipes/restaurant-agent/" rel="noopener noreferrer"&gt;LiveKit's own official example for its Agents framework&lt;/a&gt; is, not coincidentally, a restaurant reservation and ordering system with a small set of well-scoped tools — the same shape I converged on independently.&lt;/p&gt;

&lt;p&gt;The other clear industry signal: real telephony integration is now a first-class feature, not a bolt-on. &lt;a href="https://aws.amazon.com/blogs/aws/introducing-amazon-nova-2-sonic-next-generation-speech-to-speech-model-for-conversational-ai/" rel="noopener noreferrer"&gt;Nova 2 Sonic launched with direct integration into Amazon Connect, Vonage, Twilio, Audiocodes, and media platforms like LiveKit and Pipecat&lt;/a&gt; — the industry has moved past "can this work on a phone call" to "which integration path fits your existing infrastructure."&lt;/p&gt;

&lt;h2&gt;
  
  
  What's still open
&lt;/h2&gt;

&lt;p&gt;I haven't yet combined the two patterns — a phone agent that both takes orders &lt;em&gt;and&lt;/em&gt; answers open-ended knowledge questions in the same session. If I did, I'd keep the grounded-lookup tool on its own latency budget and give the model explicit permission to acknowledge the wait for that specific tool, rather than treating every tool call as equally fast. I also don't yet know where the summarization-latency curve bends — at what chunk size does 60-second summarization become 15 seconds, and is that relationship linear or does it fall off a cliff past some token threshold? That's the next thing I want real numbers on, not a guess.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>voiceai</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Which Tier Does Your Vector Workload Live On?</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Thu, 09 Jul 2026 22:33:51 +0000</pubDate>
      <link>https://dev.to/amitrix/which-tier-does-your-vector-workload-live-on-5f2a</link>
      <guid>https://dev.to/amitrix/which-tier-does-your-vector-workload-live-on-5f2a</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Since Bedrock Knowledge Bases launched in late 2023, the default vector store was OpenSearch Serverless with a ~$700/month floor you paid whether you queried it or not. Amazon S3 Vectors added a true pay-per-use tier, and the question changed to which tier of the cost/latency curve your workload belongs on.&lt;/li&gt;
&lt;li&gt;The tiers sort cleanly: hot (OpenSearch, sub-50ms, always-on), warm (Aurora + pgvector, beside relational data), cold (S3 Vectors, ~100ms, pay-per-use). Picking a store is picking a tier, not picking a winner.&lt;/li&gt;
&lt;li&gt;The cold tier is a category the market already validated. Turbopuffer built a ~$100M business storing vectors on object storage for Cursor, Notion, and Anthropic; Cursor cut its vector-database cost 95% moving to it. S3 Vectors is AWS making that same architecture a managed primitive.&lt;/li&gt;
&lt;li&gt;Agent workloads belong on the cold tier, and the reason is structural: an agent's retrieval is one step inside a multi-second reasoning loop, so 100ms versus 10ms is noise. The latency that disqualifies a customer-facing search box is invisible to an agent.&lt;/li&gt;
&lt;li&gt;S3 Vectors is not a database replacement. It is semantic-only, has no hybrid search, and trades single-digit-ms latency for cost. Know the three limits before you build on it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;When Amazon Bedrock Knowledge Bases launched at the end of 2023, the default vector store was OpenSearch Serverless, and it came with a bill before you stored anything. The floor was roughly $700 a month — four OpenSearch Compute Units (two for indexing, two for search with standby) at about $0.24 per unit-hour, running whether you queried once a day or a thousand times a second. For a production search system, that floor is rounding error. For a personal knowledge base or an internal document search, it is the reason the project never ships.&lt;/p&gt;

&lt;p&gt;Amazon S3 Vectors, &lt;a href="https://aws.amazon.com/s3/features/vectors/" rel="noopener noreferrer"&gt;generally available since December 2025&lt;/a&gt;, prices the way the rest of S3 does: no minimum charge, pay for what you store and what you query, nothing while idle. One &lt;a href="https://kane.mx/posts/2026/s3-vectors-vs-opensearch/" rel="noopener noreferrer"&gt;30-project analysis&lt;/a&gt; puts the entry point at roughly $0.60 for a first month against OpenSearch Serverless's hundreds, and finds S3 Vectors 15 to 66 times cheaper across small and medium workloads. OpenSearch has since narrowed its own gap — fractional compute units and a scale-to-zero tier cut the idle cost — but the arrival of a true pay-per-use tier is what reset the default. The question stopped being "which vector database wins" and became "which tier of the cost and latency curve does this workload belong on."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tiers
&lt;/h2&gt;

&lt;p&gt;Every AWS-native vector option now sorts onto one curve that trades latency for cost. Picking a store is picking a point on that curve.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;Fits&lt;/th&gt;
&lt;th&gt;AWS option&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hot&lt;/td&gt;
&lt;td&gt;Sub-50ms, always-on&lt;/td&gt;
&lt;td&gt;High QPS, customer-facing search&lt;/td&gt;
&lt;td&gt;OpenSearch Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm&lt;/td&gt;
&lt;td&gt;50–200ms&lt;/td&gt;
&lt;td&gt;Vectors beside relational data, ACID&lt;/td&gt;
&lt;td&gt;Aurora PostgreSQL + pgvector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold&lt;/td&gt;
&lt;td&gt;~100ms warm, sub-second cold&lt;/td&gt;
&lt;td&gt;Large or long-lived, infrequent or bursty&lt;/td&gt;
&lt;td&gt;S3 Vectors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Amazon Bedrock Knowledge Bases sits across the whole curve as the managed RAG layer, and it supports every store as a backend — OpenSearch Serverless and Managed Cluster, Aurora, Neptune Analytics, Pinecone, MongoDB Atlas, Redis, and S3 Vectors. You choose the tier; Bedrock runs the ingestion, chunking, embedding, and retrieval on top of it. The store is a decision about cost and latency, not a decision about capability.&lt;/p&gt;

&lt;p&gt;The shift since S3 Vectors arrived is that the top and bottom of the curve now combine instead of compete. You keep hot vectors in OpenSearch for the queries that need speed and spill the long tail into S3 Vectors for cost, and AWS supports importing directly from one to the other. "Pick one database" was the wrong frame; "which tier for which slice of the data" is the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cold Tier Is Already a Business
&lt;/h2&gt;

&lt;p&gt;S3 Vectors can read like an AWS experiment if you have not been watching the vector-database market. It is AWS's managed entry into a pattern that a startup has already turned into a company.&lt;/p&gt;

&lt;p&gt;The storage math behind the cold tier is not subtle. When you embed text, the vectors are much larger than the source — &lt;a href="https://jxnl.co/writing/2025/09/11/turbopuffer-object-storage-first-vector-database-architecture/" rel="noopener noreferrer"&gt;Turbopuffer measures 1KB of text expanding to roughly 16KB of vector data&lt;/a&gt; after chunking and embedding. Keeping all of that in memory or on SSD is where the bill comes from. Object storage runs about &lt;a href="https://www.morphllm.com/comparisons/turbopuffer-vs-pinecone/" rel="noopener noreferrer"&gt;$0.02 per GB against roughly 16 times that for SSD&lt;/a&gt;, and most vectors in a real corpus are read rarely. Storing the cold majority on object storage and caching only the hot slice is the whole idea.&lt;/p&gt;

&lt;p&gt;Turbopuffer built its company on exactly that idea. It stores vectors on S3, GCS, or Azure Blob and caches hot data on SSD and RAM by access pattern. &lt;a href="https://sacra.com/research/100m-yr-posthog-of-vector-databases/" rel="noopener noreferrer"&gt;Sacra estimates it reached about $100M in annualized revenue by March 2026, up 2,400% year over year&lt;/a&gt;, serving Cursor, Notion, Anthropic, Linear, and Superhuman. When Cursor moved its codebase index to this architecture, &lt;a href="https://turbopuffer.com/blog/turbopuffer" rel="noopener noreferrer"&gt;it reported cutting vector-database cost by 95%&lt;/a&gt; — because most codebases are queried infrequently, and paying in-memory rates to keep them all live was the expensive mistake.&lt;/p&gt;

&lt;p&gt;Turbopuffer is one vendor of several. &lt;a href="https://docs.lancedb.com/storage/" rel="noopener noreferrer"&gt;LanceDB&lt;/a&gt; is an open-source, file-based vector store that runs directly on any S3-compatible backend, and AWS itself published an architecture for &lt;a href="https://aws.amazon.com/blogs/architecture/a-scalable-elastic-database-and-search-solution-for-1b-vectors-built-on-lancedb-and-amazon-s3/" rel="noopener noreferrer"&gt;1B+ vectors on LanceDB, S3, and Lambda&lt;/a&gt; where the only fixed cost is the S3 storage footprint and each query costs fractions of a cent. Spice.ai integrated S3 Vectors into its open-source engine. The industry even converged on shared vocabulary for it — hot, warm, and cold vector tiers — because enough teams are building this way that the pattern needed names.&lt;/p&gt;

&lt;p&gt;S3 Vectors is AWS making that architecture a managed primitive: the cold tier without running the caching layer yourself. The reason to trust the tier is that a $100M business, a marquee set of AI customers, and AWS's own reference architecture all point at the same economics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Agents Belong on the Cold Tier
&lt;/h2&gt;

&lt;p&gt;Here is the insight that makes S3 Vectors the default for agent work, and it is easy to miss if you only look at the latency number.&lt;/p&gt;

&lt;p&gt;A customer-facing search box lives or dies on latency. A user typed, a box must fill, and 100 milliseconds versus 10 is the difference between snappy and sluggish. That workload belongs on the hot tier, and the OpenSearch bill is the cost of the experience.&lt;/p&gt;

&lt;p&gt;An agent is a different shape of workload. When an agent retrieves, the retrieval is one step inside a reasoning loop that already takes seconds — the model is thinking, calling tools, reading results, thinking again. &lt;a href="https://bigdataboutique.com/blog/opensearch-with-s3-vectors-cost-efficient-hybrid-search" rel="noopener noreferrer"&gt;As one analysis puts it&lt;/a&gt;, adding a vector lookup that takes 100ms instead of 10ms is rarely the bottleneck when the model-side latency of a single tool call is already 500ms to several seconds. The 90 milliseconds you save on the hot tier vanish inside a loop that was never going to be fast. You paid the always-on floor to optimize a step that is not on the critical path.&lt;/p&gt;

&lt;p&gt;This is why AWS positions S3 Vectors as &lt;a href="https://aws.amazon.com/jp/blogs/storage/building-persistent-memory-for-multi-agent-ai-systems-with-amazon-s3-vectors/" rel="noopener noreferrer"&gt;purpose-built for agent memory&lt;/a&gt;: agent memory grows continuously, is queried in bursts, and tolerates hundreds of milliseconds because it lives inside a slow loop. The cold tier fits the shape of the work. The hot tier would be paying a premium for speed the agent cannot use.&lt;/p&gt;

&lt;p&gt;The access pattern is the same one that made the cold tier a business. Cursor's codebases sit dormant most of the time and get queried in bursts; agent memory has the identical profile — mostly idle, occasionally read, never on a human's critical path. The workload that justified an object-storage-native database for code search is the workload most agents already have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where S3 Vectors Fits
&lt;/h2&gt;

&lt;p&gt;The official use cases share one profile: large or growing corpora, moderate or bursty query rates, latency budgets measured in hundreds of milliseconds, and a preference for zero infrastructure. That profile shows up in five recurring patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic search over large collections&lt;/strong&gt; — documents, media, medical images, video archives where cost per vector dominates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG long tail&lt;/strong&gt; — the bulk of a knowledge base that is queried occasionally, with a hot tier in front only if some subset gets constant traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent memory&lt;/strong&gt; — persistent, growing, bursty, latency-tolerant. The canonical fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch evaluation corpora&lt;/strong&gt; — embeddings you query in batches, not in real time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold tier of a tiered design&lt;/strong&gt; — the durable, cheap floor under an OpenSearch hot tier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My own case is the RAG long tail. I put my blog — 70-plus posts — into a Bedrock Knowledge Base on S3 Vectors. Small corpus, queried when I am writing and want to know what I already said, entirely latency-tolerant. A retrieval returns the relevant posts with strong semantic scores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query: "do agent memories fade while skills persist"
  0.825  memories-fade-skills-persist.md
  0.753  skills-are-git-native-distribution.md
  0.725  agent-sprawl-is-a-skills-problem.md
  0.714  what-is-a-skill.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I reach that knowledge base from my agents through one tool on a gateway — a pattern worth its own post, &lt;a href="https://artificialcuriositylabs.ai/posts/any-api-becomes-an-agent-tool/" rel="noopener noreferrer"&gt;How AgentCore Gateway Turns Any API Into an Agent Tool&lt;/a&gt;. The point here is the storage decision underneath it: this workload is cold-tier, and the cold tier no longer costs $700 to enter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Limits
&lt;/h2&gt;

&lt;p&gt;S3 Vectors buys its cost advantage with tradeoffs, and a design that ignores them will disappoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic-only, no hybrid search.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-bedrock-kb.html" rel="noopener noreferrer"&gt;AWS documents&lt;/a&gt; that S3 Vectors does not support hybrid search — the combination of vector similarity with keyword matching. For content full of exact tokens like part numbers or version strings, pure semantic recall scores poorly, and OpenSearch with lexical scoring remains the right tier. My prose has no such tokens, so the limit does not bite, but a corpus of technical specs would feel it on the first query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency is a floor, not a target.&lt;/strong&gt; Warm queries land around 100 milliseconds, cold ones sub-second — fine inside an agent loop, disqualifying for an interactive search box. When part of the workload needs speed, the answer is not to abandon S3 Vectors but to tier: keep the bulk cold, promote the hot subset to OpenSearch, which AWS supports importing into directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metadata is capped.&lt;/strong&gt; S3 Vectors limits custom metadata per vector, which constrains how much filtering you can push into the store. For rich per-document filtering at scale, that cap is a real design input, not a footnote. I take apart exactly what that cap does to ingestion and filtering in &lt;a href="https://artificialcuriositylabs.ai/posts/what-gets-stored-in-s3-vectors/" rel="noopener noreferrer"&gt;What Actually Gets Stored When You Put a Vector in S3 Vectors&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;Stop asking which vector database is best. Start asking which tier your workload sits on, because the answer is usually obvious once you look at the shape of the queries. Customer-facing and latency-critical goes hot. Sitting next to relational data goes warm. Large, growing, bursty, and patient — which describes most internal RAG and nearly all agent memory — goes cold.&lt;/p&gt;

&lt;p&gt;The reason this matters now is that the cold tier stopped being expensive. The $700 floor was quietly deciding architectures — pushing people toward one always-on database because standing up anything felt like the same fixed cost. Remove the floor and the honest answer for most agent and internal workloads is the cheap tier, running at pennies, tolerating a latency the agent never notices. The premium tier is still there when you need speed. Most of the time, you do not.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>rag</category>
      <category>bedrock</category>
    </item>
  </channel>
</rss>
