<?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: Arindam Majumder </title>
    <description>The latest articles on DEV Community by Arindam Majumder  (@arindam_1729).</description>
    <link>https://dev.to/arindam_1729</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%2F965723%2F8c3a1bb4-eb47-4302-a280-09eedb8bc785.png</url>
      <title>DEV Community: Arindam Majumder </title>
      <link>https://dev.to/arindam_1729</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arindam_1729"/>
    <language>en</language>
    <item>
      <title>A Beginner's Guide to GitHub Stacked PRs</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Fri, 07 Aug 2026 18:21:14 +0000</pubDate>
      <link>https://dev.to/arindam_1729/github-stacked-prs-a-practical-guide-to-smaller-faster-code-reviews-4md2</link>
      <guid>https://dev.to/arindam_1729/github-stacked-prs-a-practical-guide-to-smaller-faster-code-reviews-4md2</guid>
      <description>&lt;p&gt;Large pull requests are difficult to review well. &lt;/p&gt;

&lt;p&gt;They combine too many concerns, make feedback harder to act on, and often leave reviewers deciding where to start. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/pull-requests/how-tos/stacked-pull-requests" rel="noopener noreferrer"&gt;GitHub Stacked PRs&lt;/a&gt; offers a more deliberate workflow: split one large change into a sequence of small, dependent pull requests (PRs) that can be reviewed independently.&lt;/p&gt;

&lt;p&gt;In this tutorial, you will learn what stacked PRs are, when to use them, and how to manage a complete stack using GitHub CLI. We will use a small authentication feature as an example, breaking it into database, API, and interface layers.&lt;/p&gt;

&lt;p&gt;If you need a visual demonstration, I have also made a video walkthrough of this workflow.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/HDZApVSL0go"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are GitHub Stacked PRs?
&lt;/h2&gt;

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

&lt;p&gt;A stacked pull request is a chain of two or more PRs in the same repository. The bottom PR targets your trunk branch, usually &lt;code&gt;main&lt;/code&gt;, and every PR above it targets the branch directly below it.&lt;/p&gt;

&lt;p&gt;For example, an authentication feature might be organized like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat/login-ui        → PR #3 (base: feat/auth-api)
feat/auth-api        → PR #2 (base: feat/user-model)
feat/user-model      → PR #1 (base: main)
main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer contains one discrete, reviewable change. A reviewer opening &lt;code&gt;feat/auth-api&lt;/code&gt; sees the API work introduced by that layer, not the database work already included in &lt;code&gt;feat/user-model&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;GitHub also displays the stack relationship in the pull request interface, so the full context remains available.&lt;/p&gt;

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

&lt;p&gt;This differs from simply splitting a feature into arbitrary branches. The order matters: a layer can depend on code in the same branch or a lower branch, but not on code higher in the stack. Put foundational work, such as schema changes and shared types, near the bottom; put code that consumes those foundations, such as endpoints and UI components, above it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Stacked PRs?
&lt;/h2&gt;

&lt;p&gt;Stacked PRs are useful when a change is too large for one focused review but its pieces must be developed in order. They let you open the first layer for review and immediately continue building the next layer instead of waiting for a merge.&lt;/p&gt;

&lt;p&gt;The main benefits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smaller, more focused diffs:&lt;/strong&gt; Reviewers can concentrate on one concern at a time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Earlier feedback:&lt;/strong&gt; You can request feedback on a data model or API contract before the rest of the feature is complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clearer dependencies:&lt;/strong&gt; The branch structure documents which work builds on which foundation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safer high-volume development:&lt;/strong&gt; This is especially helpful when coding agents generate a larger feature in several logical steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less manual Git work:&lt;/strong&gt; GitHub can cascade rebases through a stack when lower layers change or merge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stacks are not the right answer for every change. Use a normal PR for a small, self-contained fix. A stack adds coordination overhead, so its layers should be meaningful on their own, not tiny fragments created only to increase the number of PRs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A GitHub repository with a default branch such as &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.github.com/" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt; version 2.0 or later installed and authenticated. If needed, run &lt;code&gt;gh auth login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The GitHub Stacked PRs extension installed:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh extension &lt;span class="nb"&gt;install &lt;/span&gt;github/gh-stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Stacked PRs is currently in public preview, so the interface and commands may evolve. All branches in a stack must also live in the same repository; cross-fork stacks are not supported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Your First Stack
&lt;/h2&gt;

&lt;p&gt;We will create a three-layer stack for an authentication feature:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user model.&lt;/li&gt;
&lt;li&gt;Authentication API routes.&lt;/li&gt;
&lt;li&gt;A login interface.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start from an up-to-date local copy of your default branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
git pull &lt;span class="nt"&gt;--ff-only&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Initialize the bottom layer
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;gh stack init&lt;/code&gt; with a branch name to create the first branch and register a stack locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack init feat/user-model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bottom branch is based on the repository's default branch unless you explicitly choose another base with &lt;code&gt;--base&lt;/code&gt;. Make the database or domain-model changes on this branch, then commit them as you normally would:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/models/user.ts migrations/
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add user model"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run &lt;code&gt;gh stack init&lt;/code&gt; without a branch name and select the first layer interactively.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Add a dependent API layer
&lt;/h3&gt;

&lt;p&gt;Once the user-model work is committed, create a branch above it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack add feat/auth-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates and checks out &lt;code&gt;feat/auth-api&lt;/code&gt; at the current &lt;code&gt;HEAD&lt;/code&gt;. Implement the login and session routes, then commit the work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/routes/auth.ts src/services/session.ts
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add authentication API"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API branch now contains the commits from the user-model layer plus its own commits. However, its eventual PR diff will show only the API-specific changes because its base branch is &lt;code&gt;feat/user-model&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Add the UI layer
&lt;/h3&gt;

&lt;p&gt;Create the third layer while you are on the current top branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack add feat/login-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the form and client-side integration, then commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/components/LoginForm.tsx src/pages/login.tsx
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add login interface"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;gh stack view&lt;/code&gt; at any point to inspect the local order, branch names, associated PR links, and recent commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Add a new branch when the concern changes or the current layer has grown large enough to make review difficult. A database migration, an API contract, and a UI implementation are usually better review units than three random groups of files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Submit the Stack to GitHub
&lt;/h2&gt;

&lt;p&gt;When the layers are ready, submit them together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command pushes every branch, creates or updates a PR for each branch, and links the PRs as one stack on GitHub. In an interactive terminal, it opens an editor where you can review each PR title and description and choose whether it is ready for review or a draft.&lt;/p&gt;

&lt;p&gt;For automation or a quick initial submission, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack submit &lt;span class="nt"&gt;--auto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the non-interactive form creates new PRs as drafts. Add &lt;code&gt;--open&lt;/code&gt; if the new PRs should be ready for review immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack submit &lt;span class="nt"&gt;--auto&lt;/span&gt; &lt;span class="nt"&gt;--open&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After submission, the stack looks like this on GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PR #1: Add user model          → main
PR #2: Add authentication API  → feat/user-model
PR #3: Add login interface     → feat/auth-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PR page includes a stack map that shows the layers and their status. Reviewers can jump between the PRs without returning to the pull request list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review Stacked Pull Requests
&lt;/h2&gt;

&lt;p&gt;The best way to review a complete stack is from bottom to top. Start with the foundational model, then review the API that depends on it, then the interface that uses that API. This mirrors the dependency order and provides the full story.&lt;/p&gt;

&lt;p&gt;Each PR should also make sense as a focused review on its own. If reviewing one layer requires holding too much unrelated information in mind, consider restructuring the stack so that the layer becomes more atomic.&lt;/p&gt;

&lt;p&gt;GitHub evaluates each stacked PR against the requirements of the bottom PR's base branch. In practice, this means branch protection rules and pull-request CI checks associated with &lt;code&gt;main&lt;/code&gt; apply throughout the stack, including layers that directly target another feature branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update a Stack After Feedback
&lt;/h2&gt;

&lt;p&gt;Feedback often arrives on the lower layers first. For example, a reviewer might ask you to rename a field in &lt;code&gt;feat/user-model&lt;/code&gt; after you have already built the API and UI on top of it.&lt;/p&gt;

&lt;p&gt;Check out the layer you need to change, make the correction, and commit it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack checkout feat/user-model
&lt;span class="c"&gt;# Edit the model files&lt;/span&gt;
git add src/models/user.ts
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Rename user identifier field"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then rebase the dependent branches in order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack rebase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;gh stack rebase&lt;/code&gt; fetches from the remote and runs a cascading rebase from the trunk upward. If Git reports a conflict, resolve it, stage the resolved files, and continue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &amp;lt;resolved-files&amp;gt;
gh stack rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, push the updated branches and refresh their PRs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For routine maintenance, &lt;code&gt;gh stack sync&lt;/code&gt; is often the simplest option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It fetches updates, reconciles the local and remote stack, fast-forwards the trunk when possible, cascades rebases when needed, pushes branches, and synchronizes PR state. If a rebase rewrites branch history, the extension uses &lt;code&gt;--force-with-lease&lt;/code&gt; when pushing, which protects against overwriting a remote update you do not have locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge a Stack
&lt;/h2&gt;

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

&lt;p&gt;Stacked PRs merge from the bottom upward. You can merge one layer, a contiguous portion of the stack, or the whole stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Merge the bottom PR to land only that PR.&lt;/li&gt;
&lt;li&gt;Merge a middle PR to land it and every unmerged PR below it.&lt;/li&gt;
&lt;li&gt;Merge the top PR to land the entire stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You cannot merge a middle layer while leaving an unmerged dependency below it. After a partial merge, GitHub automatically rebases and retargets the remaining upper layers so that the next unmerged PR is ready to continue through review.&lt;/p&gt;

&lt;p&gt;GitHub supports merge commits, squash merges, and rebase merges for stacks, and the final history matches the result of merging the PRs individually from bottom to top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for GitHub Stacked PRs
&lt;/h2&gt;

&lt;p&gt;Use these guidelines to keep stacks readable and easy to maintain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Make each layer independently reviewable.&lt;/strong&gt; A layer can depend on lower layers, but its purpose should be clear in its own title, description, and diff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the stack shallow when possible.&lt;/strong&gt; Two to five thoughtful layers are easier to reason about than a long chain of micro-PRs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order layers by dependency.&lt;/strong&gt; Put shared types, migrations, and core logic below their consumers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use descriptive branch and PR names.&lt;/strong&gt; Names such as &lt;code&gt;feat/user-model&lt;/code&gt; and &lt;code&gt;feat/auth-api&lt;/code&gt; make the stack map immediately understandable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit early as drafts.&lt;/strong&gt; This gives teammates visibility and lets you ask for architecture feedback before implementation is complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync before continuing work after lower layers merge.&lt;/strong&gt; This keeps local branches aligned with GitHub's updated stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain the stack in the PR descriptions.&lt;/strong&gt; A short sentence such as “Part 2 of 3: adds the API on top of the user model” helps reviewers understand the intended sequence.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;GitHub Stacked PRs turn a large, difficult-to-review change into a series of focused, connected reviews. The workflow is straightforward: initialize a bottom branch, add layers as the work gains dependencies, submit the stack, and keep it synchronized as reviews and merges happen.&lt;/p&gt;

&lt;p&gt;Start with a feature that naturally separates into two or three layers. Once your team is comfortable reviewing one focused change at a time, stacked PRs can make large changes feel much more manageable.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Use Kimi K3 with Claude Code</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Fri, 07 Aug 2026 12:47:34 +0000</pubDate>
      <link>https://dev.to/arindam_1729/how-to-use-kimi-k3-with-claude-code-6oo</link>
      <guid>https://dev.to/arindam_1729/how-to-use-kimi-k3-with-claude-code-6oo</guid>
      <description>&lt;p&gt;Frontier coding models are becoming more capable, but using them for every task can become expensive quickly. &lt;/p&gt;

&lt;p&gt;That matters when an AI agent is part of your daily development workflow.&lt;/p&gt;

&lt;p&gt;The answer is not to use a cheaper model blindly. It is to match the model to the task. A strong open-weight model can handle repository exploration, test writing, documentation, contained refactors, and many routine implementation tasks. Save premium models and extra review for the work where the stakes or ambiguity truly justify them.&lt;/p&gt;

&lt;p&gt;In this tutorial, you will use &lt;strong&gt;Kimi K3&lt;/strong&gt; with &lt;strong&gt;Claude Code&lt;/strong&gt; through &lt;strong&gt;Nebius Token Factory Relay&lt;/strong&gt;. The relay lets Claude Code communicate with Nebius-hosted open models without changing the workflow you use in the terminal.&lt;/p&gt;

&lt;p&gt;For a visual walkthrough, watch the accompanying video: &lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/9_eZOLkGg-w"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Will Learn
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial, you will be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explain what Kimi K3 is and when it makes sense to use it.&lt;/li&gt;
&lt;li&gt;Create a Nebius Token Factory API key.&lt;/li&gt;
&lt;li&gt;Install and configure Nebius TF Relay.&lt;/li&gt;
&lt;li&gt;Launch Claude Code with Kimi K3.&lt;/li&gt;
&lt;li&gt;Confirm that the model is working before you give it a real coding task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Is Kimi K3?
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://github.com/MoonshotAI/Kimi-K3" rel="noopener noreferrer"&gt;Kimi K3&lt;/a&gt; is Moonshot AI’s flagship open-weight model. It is built for coding, agentic workflows, long-context tasks, and knowledge work. The model uses a Mixture-of-Experts architecture with 2.8 trillion total parameters and 104 billion active parameters per token. Moonshot reports a one-million-token context window and native vision capabilities in its &lt;a href="https://arxiv.org/abs/2607.24653" rel="noopener noreferrer"&gt;technical report&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The model has attracted attention because it performs competitively on coding and agentic benchmarks while being available as open weights. Independent testing from &lt;a href="https://artificialanalysis.ai/articles/kimi-k3-agentic-knowledge-benchmark" rel="noopener noreferrer"&gt;Artificial Analysis&lt;/a&gt; places it close to leading proprietary models on agentic knowledge work. Moonshot’s own &lt;a href="https://github.com/MoonshotAI/Kimi-K3" rel="noopener noreferrer"&gt;evaluation suite&lt;/a&gt; reports strong results across coding, agentic, long-context, and multimodal evaluations.&lt;/p&gt;

&lt;p&gt;Benchmarks are useful context, but they are not a guarantee for your project. They use fixed prompts, tools, and scoring systems. The practical question is whether the model gives you reliable output on your codebase at an acceptable cost and speed.&lt;/p&gt;

&lt;p&gt;Kimi K3 is a good model to try for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding an unfamiliar codebase&lt;/li&gt;
&lt;li&gt;Writing or improving tests&lt;/li&gt;
&lt;li&gt;Refactoring a well-defined area of a project&lt;/li&gt;
&lt;li&gt;Drafting documentation and technical notes&lt;/li&gt;
&lt;li&gt;Investigating an error before making a change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For sensitive security work, complex migrations, high-impact architecture decisions, or production changes, use the model and review process that give you the highest confidence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Kimi K3’s published model context window is one million tokens. Nebius TF Relay currently lists a 262K context window for its Kimi K3 route. The provider you use determines the limits, pricing, availability, and performance you actually receive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Nebius TF Relay Works
&lt;/h2&gt;

&lt;p&gt;Claude Code is designed to communicate with Anthropic’s Messages API. Nebius Token Factory provides hosted open models through an OpenAI-compatible API. Those two APIs do not speak the same format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/shivaylamba/nebius-tf-relay" rel="noopener noreferrer"&gt;Nebius TF Relay&lt;/a&gt; runs locally and translates between them. Claude Code sends requests to the relay, the relay converts them for Nebius, and the response is converted back for Claude Code. This means you can keep using the terminal interface, repository tools, and approval flow you already know.&lt;/p&gt;

&lt;p&gt;The setup looks like this:&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;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;Your coding-agent interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nebius TF Relay&lt;/td&gt;
&lt;td&gt;Local protocol bridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nebius Token Factory&lt;/td&gt;
&lt;td&gt;Hosted inference provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kimi K3&lt;/td&gt;
&lt;td&gt;The model that generates responses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you begin, make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code installed locally. Use the &lt;a href="https://docs.anthropic.com/en/docs/claude-code/getting-started" rel="noopener noreferrer"&gt;official installation guide&lt;/a&gt; if needed.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://dub.sh/nebius" rel="noopener noreferrer"&gt;Nebius Token Factory&lt;/a&gt; account.&lt;/li&gt;
&lt;li&gt;A terminal on macOS, Linux, or WSL.&lt;/li&gt;
&lt;li&gt;An optional &lt;a href="https://app.tavily.com/" rel="noopener noreferrer"&gt;Tavily API key&lt;/a&gt; if you want web search inside the relay.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will also need a Nebius Token Factory API key. Create one from the &lt;a href="https://tokenfactory.nebius.com/?modals=create-api-key" rel="noopener noreferrer"&gt;Nebius API-key page&lt;/a&gt;. Copy it to a secure location when it is created.&lt;/p&gt;

&lt;p&gt;Do not commit the key to Git, paste it into an AI prompt, or show it in a video recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install Nebius TF Relay
&lt;/h2&gt;

&lt;p&gt;Install the relay with the project’s installer:&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;-fsSL&lt;/span&gt; https://nebius-tf-relay.vercel.app/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This installs the &lt;code&gt;nebiusrelay&lt;/code&gt; command and shortcuts such as &lt;code&gt;nclaude&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you work in a company or security-sensitive environment, inspect the &lt;a href="https://github.com/shivaylamba/nebius-tf-relay" rel="noopener noreferrer"&gt;project source&lt;/a&gt; before running a shell installer from the internet. That is good practice for any third-party developer tool.&lt;/p&gt;

&lt;p&gt;After installation, check that the command is available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nebiusrelay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the relay’s interactive menu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Configure Your Nebius API Key
&lt;/h2&gt;

&lt;p&gt;Run the configuration command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nebiusrelay configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;When prompted, paste your Nebius Token Factory API key. The setup will also ask for a Tavily API key. You can skip this if you do not need web search.&lt;/p&gt;

&lt;p&gt;The relay stores its configuration locally. You can also supply the key through an environment variable instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NEBIUS_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_nebius_api_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using an environment variable is useful for temporary sessions and automated environments. On a shared machine, use a secret manager or another protected credential workflow so that the key is not exposed in shell history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Launch Claude Code Through the Relay
&lt;/h2&gt;

&lt;p&gt;Move into the repository where you want to work, then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nebiusrelay claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;You can use the shorter alias as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nclaude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relay starts Claude Code with the Nebius endpoint and credentials configured for that session. It does not require you to permanently replace your existing Claude Code settings.&lt;/p&gt;

&lt;p&gt;If Claude Code is not installed, the relay will tell you and point you to the official installation path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Select Kimi K3
&lt;/h2&gt;

&lt;p&gt;Once Claude Code opens, use the model selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Select &lt;strong&gt;Kimi K3&lt;/strong&gt; from the list.&lt;/p&gt;

&lt;p&gt;Nebius TF Relay fetches the available model catalog when it starts, so the exact choices can change over time. Kimi K3 is documented as the relay’s default coding model, but it is worth checking the selected model before you begin a session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Verify the Setup With a Safe Prompt
&lt;/h2&gt;

&lt;p&gt;Before asking the agent to change code, start with a read-only task. This confirms that the relay, credentials, model selection, and repository access are all working.&lt;/p&gt;

&lt;p&gt;Use this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read this repository without changing files. Identify the application entry point,
the test command, and the three highest-risk areas to modify. Cite the files you used.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a better first test than a vague request such as “build a feature.” It gives you evidence that the model can inspect the repository and follow constraints without making changes.&lt;/p&gt;

&lt;p&gt;After that succeeds, try a small, bounded task. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspect the failing test. Do not edit files yet. Explain the likely root cause,
the minimum fix, and the tests you would run after the change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review the proposal before you approve edits. Then inspect the diff and run the relevant tests yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kimi K3 is a capable open-weight model for coding, agentic work, and long-context tasks.&lt;/li&gt;
&lt;li&gt;Nebius TF Relay lets you access it inside Claude Code without changing your normal terminal workflow.&lt;/li&gt;
&lt;li&gt;You need a Nebius Token Factory API key, the relay, and the &lt;code&gt;nclaude&lt;/code&gt; command to get started.&lt;/li&gt;
&lt;li&gt;Start with a read-only prompt, then validate every code change with a diff review and tests.&lt;/li&gt;
&lt;li&gt;Use the model that best matches the risk and complexity of the task—not necessarily the most expensive one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kimi K3 with Claude Code is not a replacement for engineering judgment. It is a practical way to add another strong model to your workflow and reserve expensive frontier-model usage for the situations where it has the most value.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>agents</category>
      <category>ai</category>
      <category>coding</category>
    </item>
    <item>
      <title>I Ran the Same Login Through BrowserAct and Playwright. One Got Flagged as a Bot</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Tue, 04 Aug 2026 13:01:01 +0000</pubDate>
      <link>https://dev.to/arindam_1729/i-ran-the-same-login-through-browseract-and-playwright-one-got-flagged-as-a-bot-35ll</link>
      <guid>https://dev.to/arindam_1729/i-ran-the-same-login-through-browseract-and-playwright-one-got-flagged-as-a-bot-35ll</guid>
      <description>&lt;p&gt;Agent browser automation works beautifully until it meets a real website.&lt;/p&gt;

&lt;p&gt;The agent clicks through a demo page and looks unstoppable. Then you point it at a logged-in dashboard, or a form whose selectors moved after last week's redeploy, or a login that wants an SMS code. The reasoning model is fine. The layer underneath it was never built for this.&lt;/p&gt;

&lt;p&gt;I spent a few days running &lt;a href="https://www.browseract.ai/Arindam" rel="noopener noreferrer"&gt;BrowserAct&lt;/a&gt; through a JS-rendered page and a full login flow, then wrote the same login as a Playwright script to find where the two approaches diverge. Everything below is output I captured on Windows through WSL, including the run that failed while telling me it had worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Playwright is built for
&lt;/h2&gt;

&lt;p&gt;Playwright is deterministic. You know the page, you write selectors against it, you assert on outcomes. For CI end-to-end tests or scripted flows against a UI your team owns, it's hard to beat, because the script encodes knowledge you already have before the run starts.&lt;/p&gt;

&lt;p&gt;That assumption is where agent workflows diverge, mostly because the agent doesn’t know the page. &lt;/p&gt;

&lt;p&gt;In an agentic workflow, an agent arrives at a page it has never seen, on a DOM that may have shifted since the last run. Hand it raw HTML and you’re handing it thousands of tokens of nested markup with no stable handle to act on. It infers which node is the search box, guesses a selector, and hopes the guess survives the next render. When the layout changes, the guess breaks silently.&lt;/p&gt;

&lt;p&gt;A script solves this by knowing the answer in advance. An agent can't, so it needs the page described in a form it can reason over. I wanted to see what that description actually looks like, so I ran some tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the agent receives
&lt;/h2&gt;

&lt;p&gt;I installed the CLI first, expecting the usual dependency archaeology:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv tool &lt;span class="nb"&gt;install &lt;/span&gt;browser-act-cli &lt;span class="nt"&gt;--python&lt;/span&gt; 3.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It resolved cleanly and dropped a single executable.&lt;/p&gt;

&lt;p&gt;Another thing that caught my attention next was that the CLI refuses to ship the agent's instructions as a static file. The skill stub points at a command instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;browser-act get-skills core &lt;span class="nt"&gt;--skill-version&lt;/span&gt; 2.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workflow content comes back matched to the installed version, so the guidance can't drift away from the binary driving it. For a tool whose commands change across releases, I thought that was a real answer to instruction rot.&lt;/p&gt;

&lt;p&gt;The loop it served me is Open, State, Interact, Verify, Close. State is the part that matters, and here's what I got back against &lt;code&gt;quotes.toscrape.com/scroll&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;url=https://quotes.toscrape.com/scroll
|SCROLL|&amp;lt;html /&amp;gt; (0.0 pages above, 0.7 pages below,
        left=0,top=0,width=1905,height=1716)
    [1]&amp;lt;a /&amp;gt;
        Quotes to Scrape
    [2]&amp;lt;a /&amp;gt;
        Login
    "The world as we have created it is a process of our thinking..."
    by
    Albert Einstein
    Tags:
    [3]&amp;lt;a class=tag /&amp;gt;
        change
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every actionable element carries an index. To reach login, the agent clicks &lt;code&gt;[2]&lt;/code&gt;, and it does that without writing a selector or holding a DOM model between turns. I also liked that scroll position arrives as page-fractions, since the agent knows 0.7 of a page sits below it without measuring anything.&lt;/p&gt;

&lt;p&gt;I captured the same moment visually with &lt;code&gt;screenshot --full&lt;/code&gt;:&lt;/p&gt;

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

&lt;p&gt;The viewport was 1716 pixels tall and had not been scrolled, yet the capture runs all the way to the footer. Between them these are two views of one moment, the screenshot for a human auditing what happened and the indexed state for the agent deciding what to do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where network capture earns its place
&lt;/h2&gt;

&lt;p&gt;State told me what was rendered, but I wanted to know where it came from, so I pulled the XHR traffic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csvs"&gt;&lt;code&gt;&lt;span class="k"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;mime&lt;/span&gt;&lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;url&lt;/span&gt;
&lt;span class="k"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;,,,&lt;/span&gt;&lt;span class="nv"&gt;https:&lt;/span&gt;&lt;span class="c1"&gt;//ogads-pa.clients6.google.com/$rpc/...GetAsyncData&lt;/span&gt;
&lt;span class="k"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;application&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="k"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;https:&lt;/span&gt;&lt;span class="c1"&gt;//quotes.toscrape.com/api/quotes?page=1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second row is the interesting one. The page renders its cards from a JSON endpoint, which means an agent can read &lt;code&gt;api/quotes?page=1&lt;/code&gt; directly rather than parsing rendered markup back into structured data. The first row is a Google ads call the page also fired, and I'd note that real capture always includes noise the agent has to filter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;One gotcha I hit: without &lt;code&gt;--format json&lt;/code&gt; the CLI writes CSV, which will bite you if you're piping into a parser.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure that reported success
&lt;/h2&gt;

&lt;p&gt;The scroll taught me more than anything that worked.&lt;/p&gt;

&lt;p&gt;I opened the page, read state, ran &lt;code&gt;scroll down --amount 3&lt;/code&gt;, waited, then read state again. Both snapshots came back &lt;strong&gt;identical&lt;/strong&gt;. Same &lt;code&gt;top=0&lt;/code&gt;, same tag indices &lt;code&gt;[1]&lt;/code&gt; through &lt;code&gt;[19]&lt;/code&gt;. Only &lt;code&gt;page=1&lt;/code&gt; had been fetched, when a successful scroll should have pulled &lt;code&gt;page=2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I assumed a race condition, so I re-ran the whole thing with &lt;code&gt;wait stable --timeout 15000&lt;/code&gt; and a second settle pass. Same result.&lt;/p&gt;

&lt;p&gt;What threw me is that the command had reported success both times, echoing back &lt;code&gt;scrolled=down amount=3&lt;/code&gt; with exit code 0. That confirms the command executed, which turns out to be a very different claim from the viewport having moved. When I read the page markdown, &lt;code&gt;Loading...&lt;/code&gt; was still sitting at the bottom.&lt;/p&gt;

&lt;p&gt;Calibration fixed it. Running &lt;code&gt;--amount 3000&lt;/code&gt; gave me this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|SCROLL|&amp;lt;html /&amp;gt; (0.7 pages above, 2.1 pages below, height=3794)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare that against the earlier &lt;code&gt;height=1716&lt;/code&gt;. The document had more than doubled, which only happens when new content loads, and the network capture confirmed where it came from:&lt;/p&gt;

&lt;p&gt;json&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="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://quotes.toscrape.com/api/quotes?page=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;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&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="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://quotes.toscrape.com/api/quotes?page=2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&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;So the amount behaves like pixels, and my original 3 meant three pixels of movement on a 1716-pixel viewport. That's a documentation gap rather than a bug.&lt;/p&gt;

&lt;p&gt;The lesson sits in the first attempt, though. Nothing errored anywhere in that sequence. Every command returned success, every state snapshot looked valid, and the page underneath had not moved at all. Verification has to come from the page's own evidence, whether that's a changed scroll position, a taller document, or a new network call. An agent trusting exit codes here would have confidently reported reading a list it never scrolled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crossing a login boundary
&lt;/h2&gt;

&lt;p&gt;A public page is the easy case. I wanted to know whether state survives authentication, so I pointed the loop at &lt;code&gt;saucedemo.com&lt;/code&gt;, a Sauce Labs sandbox with published credentials.&lt;/p&gt;

&lt;p&gt;Here's what I got before logging in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzx7wm5ua162ocrzi2f65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzx7wm5ua162ocrzi2f65.png" alt="Two fields and a button. The agent sees this as indices 2, 3, and 4." width="800" height="500"&gt;&lt;/a&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="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://www.saucedemo.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Swag Labs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"[1]&amp;lt;div id=root /&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s2"&gt;[2]&amp;lt;input placeholder=Username id=user-name /&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s2"&gt;[3]&amp;lt;input placeholder=Password type=password /&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s2"&gt;[4]&amp;lt;input id=login-button type=submit /&amp;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;I typed into &lt;code&gt;[2]&lt;/code&gt; and &lt;code&gt;[3]&lt;/code&gt;, then clicked &lt;code&gt;[4]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;url=https://www.saucedemo.com/inventory.html
    [2]&amp;lt;button id=react-burger-menu-btn /&amp;gt; Open Menu
    [3]&amp;lt;a class=shopping_cart_link /&amp;gt;
    [9]&amp;lt;a id=item_4_title_link /&amp;gt; Sauce Labs Backpack  $29.99
    [10]&amp;lt;button id=add-to-cart-sauce-labs-backpack /&amp;gt; Add to cart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The URL moved, the indices renumbered against a completely different page, and the session carried authentication forward. &lt;code&gt;[10]&lt;/code&gt; is now a real add-to-cart action, and nothing in my setup had to know in advance that a product grid was coming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F20h34twt88ykfy4zc3ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F20h34twt88ykfy4zc3ma.png" alt="The page behind the login, captured in the same session." width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did fumble this on the first attempt, which is worth passing on. I picked indices 1, 2, and 3 for username, password, and submit, when the correct mapping was 2, 3, and 4, because &lt;code&gt;[1]&lt;/code&gt; was the root &lt;code&gt;&amp;lt;div id=root /&amp;gt;&lt;/code&gt; wrapper. The state had shown me that correctly and I misread it. Re-reading state fixed it in a single turn, which I'd contrast against a stale selector, since that one needs a human to open the script and rewrite it.&lt;/p&gt;

&lt;p&gt;The network capture then surfaced something I wouldn't have predicted:&lt;/p&gt;

&lt;p&gt;json&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="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://events.backtrace.io/api/unique-events/submit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&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;No authentication call at all. Sauce Demo does its auth client-side, so the only traffic I captured was Backtrace telemetry returning 401. If I'd built an agent that confirms login by watching for an auth response, it would have failed here silently, and one command told me that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the same login in Playwright
&lt;/h2&gt;

&lt;p&gt;Then I wrote the same flow as a script: &lt;code&gt;goto&lt;/code&gt;, fill &lt;code&gt;#user-name&lt;/code&gt; and &lt;code&gt;#password&lt;/code&gt;, click &lt;code&gt;#login-button&lt;/code&gt;, wait for the inventory URL. Headless Chromium, exit code 0, six products found.&lt;/p&gt;

&lt;p&gt;Both tools passed. I'd add context, though, because Sauce Demo is a test sandbox with stable documented IDs, built so that selector-based scripts have something predictable to hit. It's the most favourable page Playwright will ever see.&lt;/p&gt;

&lt;p&gt;What interested me more is what Sauce Demo couldn't test. It never challenged either tool, with no fingerprinting and no interstitial anywhere in the flow. So my run measured whether a form can be driven, and told me nothing about whether the browser reaches the page at all.&lt;/p&gt;

&lt;p&gt;So I pointed both at &lt;code&gt;deviceandbrowserinfo.com/are_you_a_bot&lt;/code&gt;. BrowserAct's stealth browser came back with this:&lt;/p&gt;

&lt;p&gt;json&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="nl"&gt;"isBot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"details"&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;"hasBotUserAgent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hasWebdriverTrue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isPlaywright"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"isHeadlessChrome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isAutomatedWithCDP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hasSuspiciousWeakSignals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;My Playwright script came back with this:&lt;/p&gt;

&lt;p&gt;json&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="nl"&gt;"isBot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"details"&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;"hasBotUserAgent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hasWebdriverTrue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hasWebdriverInFrameTrue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isAutomatedWithCDP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"isAutomatedWithCDPInWebWorker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;Five separate flags tripped. The user agent announced itself, &lt;code&gt;navigator.webdriver&lt;/code&gt; read true in the main frame and inside frames, and the CDP automation was visible from both the page and a web worker. The page rendered "You are a bot" where the other run had said "You are human!"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fip8lcivwaqt5lod8fliu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fip8lcivwaqt5lod8fliu.png" alt="The detection page's own verdict on default headless Chromium." width="800" height="1327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I should be clear that this is default headless Playwright. Stealth plugins exist for exactly this reason and would change the result, so the fair framing is that hardening is work you take on yourself, while the stealth browser arrived that way.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bot.sannysoft.com&lt;/code&gt; agreed on the BrowserAct side, showing WebDriver missing, the Chrome object present, and PluginArray correct. I noticed one nuance in the fp-collect output, where &lt;code&gt;webDriver: true&lt;/code&gt; sits alongside &lt;code&gt;webDriverValue: false&lt;/code&gt;, and that reflects the property existing while set to false, which is standard Chrome rather than a leak.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;BrowserAct&lt;/th&gt;
&lt;th&gt;Playwright (default)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;How it clicks&lt;/td&gt;
&lt;td&gt;Index from live state&lt;/td&gt;
&lt;td&gt;Selector written in advance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs the page mapped first&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sauce Demo login&lt;/td&gt;
&lt;td&gt;Reached inventory&lt;/td&gt;
&lt;td&gt;Reached inventory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detection verdict&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isBot: false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;isBot: true&lt;/code&gt;, five flags&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two housekeeping notes from these runs. My stealth quota ran out partway through, so the scroll confirmation used local Chrome, though scroll behaviour is identical either way. And when I ran under WSL without &lt;code&gt;sudo&lt;/code&gt;, the apt install of Chromium libraries failed, at which point BrowserAct unpacked the dependencies into &lt;code&gt;~/.local/share/&lt;/code&gt; and loaded them through &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; rather than dying. I'd call that a good default, though expect a slow first run while it fetches.&lt;/p&gt;

&lt;h2&gt;
  
  
  When BrowserAct is the right tool
&lt;/h2&gt;

&lt;p&gt;Four situations came up across these runs where BrowserAct did something a plain script would have struggled with, and I hit each one directly.&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;quotes.toscrape.com/scroll&lt;/code&gt; I never wrote a selector. I read indexed state, acted on &lt;code&gt;[2]&lt;/code&gt;, and re-read after the page changed. When I point an agent at a site it hasn't seen, or at a UI that shifts between runs, that loop is what lets it keep going instead of stalling on a selector that no longer matches. This is the case for research and monitoring work, where the target is rarely a page you built.&lt;/p&gt;

&lt;p&gt;The detection run is the one I keep coming back to. My stealth browser cleared &lt;code&gt;deviceandbrowserinfo&lt;/code&gt; and &lt;code&gt;sannysoft&lt;/code&gt; as human on the same page where my headless Playwright tripped five flags and got "You are a bot." An agent that reasons perfectly is useless when the site fingerprints it and never serves the page. On protected targets that's the reason I'd reach for the stealth browser rather than a raw headless script.&lt;/p&gt;

&lt;p&gt;The SauceDemo login showed me the third. I authenticated, landed on &lt;code&gt;/inventory.html&lt;/code&gt;, and the session carried forward into a page with real add-to-cart actions I hadn't seen before the login. For a dashboard check or an account operation, the part that only exists after login is the whole job, and the session held across that boundary without me scripting the transition.&lt;/p&gt;

&lt;p&gt;The fourth came out of the network capture. On the quotes run it handed me the &lt;code&gt;api/quotes&lt;/code&gt; endpoint the page was reading from, and on SauceDemo it showed me the auth was client-side with no login call at all. When the data I want arrives over XHR, reading it from the network beats parsing rendered cards, and it told me how each page actually worked rather than how it looked.&lt;/p&gt;

&lt;p&gt;I'll keep one thing honest, though. If the page is one you own, the selectors are stable, and nothing is trying to keep you out, a plain Playwright script is simpler and cheaper than an agent loop. My SauceDemo login proved that much, since both tools passed and the script had less to reason about. BrowserAct earned its cost on the runs where the page was unfamiliar, protected, gated behind a session, or feeding data through a network call, and that describes production more often than it describes a sandbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it against one workflow
&lt;/h2&gt;

&lt;p&gt;If your agent works in clean demos but falls over on real sites, the test that told me the most was a small one. &lt;/p&gt;

&lt;p&gt;Point it at a single workflow you care about, then check the page's own evidence rather than the exit code. &lt;/p&gt;

&lt;p&gt;That's where a browser layer either earns its keep or shows you that a script was fine all along.&lt;/p&gt;

</description>
      <category>playwright</category>
      <category>ai</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Did Cursor Kill the Model Router Companies?</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Wed, 22 Jul 2026 22:16:21 +0000</pubDate>
      <link>https://dev.to/arindam_1729/did-cursor-kill-the-model-router-companies-1lg4</link>
      <guid>https://dev.to/arindam_1729/did-cursor-kill-the-model-router-companies-1lg4</guid>
      <description>&lt;p&gt;Cursor has launched &lt;a href="https://cursor.com/blog/router" rel="noopener noreferrer"&gt;&lt;strong&gt;Cursor Router&lt;/strong&gt;&lt;/a&gt;, an intelligent model-routing system designed for teams and enterprises. &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2079993729532989500-41" src="https://platform.twitter.com/embed/Tweet.html?id=2079993729532989500"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2079993729532989500-41');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2079993729532989500&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;On the surface, it sounds familiar: inspect a request, decide how difficult it is, and send it to the model that offers the best balance between quality and cost.&lt;/p&gt;

&lt;p&gt;That is already the central promise behind products such as OpenRouter, Not Diamond, Portkey, Martian, and Amazon Bedrock Intelligent Prompt Routing. &lt;/p&gt;

&lt;p&gt;But Cursor's entry into this market is different in one important way: Cursor does not operate outside the workflow. &lt;/p&gt;

&lt;p&gt;It owns the coding environment in which the request is created, processed, evaluated, and, if the result is useful, accepted into the codebase.&lt;/p&gt;

&lt;p&gt;Cursor has not literally killed the model-routing industry. It may, however, have made standalone model routing much harder to sell as an independent product for AI-assisted software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an AI Model Router?
&lt;/h2&gt;

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

&lt;p&gt;Different AI models are good at different jobs. A frontier reasoning model might be necessary for a complex architectural change, while a smaller and cheaper model could easily rename a variable, explain a function, or generate routine boilerplate.&lt;/p&gt;

&lt;p&gt;Without routing, users often select one powerful model and use it for everything. This is simple, but inefficient. Easy work gets completed at frontier-model prices even when a less expensive model could produce an equally useful result.&lt;/p&gt;

&lt;p&gt;A model router sits between the user and a collection of models. It analyzes each request and chooses where to send it. Depending on the platform, that decision may consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task type and complexity&lt;/li&gt;
&lt;li&gt;Expected response quality&lt;/li&gt;
&lt;li&gt;Cost and latency&lt;/li&gt;
&lt;li&gt;Model availability&lt;/li&gt;
&lt;li&gt;Provider reliability&lt;/li&gt;
&lt;li&gt;Context-window requirements&lt;/li&gt;
&lt;li&gt;Security and data-retention policies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The basic pitch is compelling: use expensive intelligence only when it is actually needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Cursor Router Works
&lt;/h2&gt;

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

&lt;p&gt;According to Cursor, approximately 60% of its developers select a single model as their daily driver. Cursor Router attempts to eliminate that habit by classifying every request before an AI model begins working.&lt;/p&gt;

&lt;p&gt;The router analyzes the query, available context, task complexity, and domain. It combines those signals with Cursor's knowledge of how individual models behave on real coding tasks. The request is then sent to the model considered most appropriate for the job.&lt;/p&gt;

&lt;p&gt;Cursor offers three routing modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence&lt;/strong&gt; prioritizes frontier-level performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balance&lt;/strong&gt; aims for strong quality at a more practical cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt; seeks the highest useful intelligence while minimizing token spending.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Administrators can control which modes are available, decide how the router is rolled out across teams, and allow or block specific models.&lt;/p&gt;

&lt;p&gt;Cursor says it trained the router using more than 600,000 live requests and evaluated it through online A/B tests covering millions of additional requests. &lt;/p&gt;

&lt;p&gt;During early access, participating enterprises reportedly achieved frontier-level performance at roughly 30–50% lower cost. Cursor also reports that broader online testing produced frontier-quality results with savings of approximately 60%.&lt;/p&gt;

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

&lt;p&gt;These are Cursor's own results and should be independently validated across different organizations and workloads. Even so, the scale and type of its training data reveal why this launch matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor's Real Advantage Is Not the Classifier
&lt;/h2&gt;

&lt;p&gt;The model-selection algorithm is only part of Cursor Router's advantage. The more important asset is Cursor's position inside the development workflow.&lt;/p&gt;

&lt;p&gt;A general-purpose router can see the prompt and perhaps some application metadata. Cursor can potentially learn from a much richer sequence of events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the developer asked&lt;/li&gt;
&lt;li&gt;What code and project context surrounded the request&lt;/li&gt;
&lt;li&gt;Which model generated the response&lt;/li&gt;
&lt;li&gt;Whether the developer accepted or rejected the result&lt;/li&gt;
&lt;li&gt;How much of the generated code survived later edits&lt;/li&gt;
&lt;li&gt;Which models perform best for particular coding tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a powerful feedback loop. Cursor routes hundreds of millions of coding requests each week and can observe signals that are closely connected to real developer satisfaction. Instead of optimizing only for benchmarks or synthetic evaluations, it can optimize using evidence from production coding workflows.&lt;/p&gt;

&lt;p&gt;That distribution advantage is difficult for an external router to reproduce. Cursor owns the interface, the context, and the outcome signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Existing Router Market
&lt;/h2&gt;

&lt;p&gt;Cursor is entering an increasingly crowded category.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenRouter
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://openrouter.ai/docs/guides/routing/routers/auto-router" rel="noopener noreferrer"&gt;OpenRouter&lt;/a&gt; provides a unified API for accessing hundreds of models across numerous inference providers. Its Auto Router automatically selects a model for each prompt and is powered by Not Diamond. OpenRouter also handles provider selection, pricing preferences, and fallbacks.&lt;/p&gt;

&lt;p&gt;Its value extends well beyond model classification. For developers building general AI applications, one API key, broad model access, provider redundancy, and standardized request handling remain important infrastructure benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not Diamond
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://docs.notdiamond.ai/docs/what-is-not-diamond" rel="noopener noreferrer"&gt;Not Diamond&lt;/a&gt; specializes in intelligent model routing and prompt optimization. Developers can use a pre-trained router or train a custom router using their own application data. This makes it applicable to customer support, document processing, research, sales, and other workloads, not only coding.&lt;/p&gt;

&lt;p&gt;Not Diamond also powers OpenRouter's Auto Router, demonstrating that specialized routing technology can be distributed through larger platforms rather than sold only as a standalone destination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Portkey
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://portkey.ai/docs/product/ai-gateway" rel="noopener noreferrer"&gt;Portkey&lt;/a&gt; positions routing as one capability within a broader AI gateway. Its platform includes conditional routing, fallbacks, retries, load balancing, caching, guardrails, budget controls, and observability.&lt;/p&gt;

&lt;p&gt;These operational features solve problems Cursor Router is not primarily designed to address. A company running several production AI applications may need centralized governance and reliability across all of them, regardless of which editor its developers use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon Bedrock
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-routing.html" rel="noopener noreferrer"&gt;Amazon Bedrock Intelligent Prompt Routing&lt;/a&gt; dynamically routes prompts between supported models in the same model family. It predicts response quality and attempts to choose the best quality-and-cost combination. For organizations already committed to AWS, routing can therefore become a native cloud capability rather than another external service.&lt;/p&gt;

&lt;p&gt;This highlights the broader trend: model routing is being absorbed into the platforms that already own inference, application infrastructure, or user workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Did Cursor Kill the Router Companies?
&lt;/h2&gt;

&lt;p&gt;Not exactly.&lt;/p&gt;

&lt;p&gt;Cursor Router is optimized around software development and is currently offered to Teams and Enterprise customers across Cursor's desktop, web, iOS, CLI, and SDK experiences. It does not replace a general AI gateway for companies operating many models across multiple applications and departments.&lt;/p&gt;

&lt;p&gt;Independent routing platforms can continue to compete through capabilities such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing for non-coding workloads&lt;/li&gt;
&lt;li&gt;Custom evaluation data and application-specific routers&lt;/li&gt;
&lt;li&gt;Bring-your-own-provider keys&lt;/li&gt;
&lt;li&gt;Cross-provider failover and load balancing&lt;/li&gt;
&lt;li&gt;Centralized security and compliance controls&lt;/li&gt;
&lt;li&gt;Cost tracking across several applications&lt;/li&gt;
&lt;li&gt;Guardrails, caching, rate limits, and observability&lt;/li&gt;
&lt;li&gt;Self-hosted or cloud-neutral deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What Cursor has threatened is the narrowest version of the router-company pitch: &lt;em&gt;we will inspect your coding prompt and select the best model for it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When that capability is built directly into the coding product and trained using feedback the coding product uniquely owns it becomes difficult to justify another service between the developer and the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Is Becoming a Platform Feature
&lt;/h2&gt;

&lt;p&gt;The history of software infrastructure is filled with standalone products that eventually became native platform features. Logging, authentication, analytics, deployment, and monitoring all followed versions of this pattern. A new technical requirement first creates a specialized market. Then larger platforms absorb the most universal parts of the solution.&lt;/p&gt;

&lt;p&gt;AI model routing appears to be entering that stage.&lt;/p&gt;

&lt;p&gt;OpenRouter has integrated automatic selection into its multi-model gateway. Amazon has added routing to Bedrock. Portkey includes it within an operational AI gateway. Cursor now embeds it directly into an AI coding environment.&lt;/p&gt;

&lt;p&gt;This does not mean routing technology has no value. It means the value is moving. A basic classifier that chooses between a cheap model and an expensive model may no longer be enough to support an entire company. Successful router businesses will need proprietary outcome data, specialized workflows, custom optimization, governance, or infrastructure that platforms cannot easily reproduce.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for AI Development
&lt;/h2&gt;

&lt;p&gt;Cursor Router points toward a future in which users stop manually choosing model names.&lt;/p&gt;

&lt;p&gt;Most people do not want to compare benchmarks every week or decide whether a particular request requires Claude, GPT, Gemini, Grok, or another model. They want the best available outcome within their preferred limits for cost, speed, and privacy.&lt;/p&gt;

&lt;p&gt;The model picker may eventually become an advanced setting rather than the center of the AI interface. Products will compete on how well they understand intent, assemble context, select intelligence, operate tools, and evaluate the final result.&lt;/p&gt;

&lt;p&gt;In that world, the winning router may not be the company with the smartest isolated classifier. It may be the platform with the richest understanding of the work being performed.&lt;/p&gt;

&lt;p&gt;Cursor already owns that context for millions of coding interactions. Cursor Router is its attempt to turn that context into an economic and product advantage.&lt;/p&gt;

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

&lt;p&gt;Cursor did not kill OpenRouter, Not Diamond, Portkey, Martian, or the wider routing ecosystem. Those products serve broader infrastructure needs, and many provide features far beyond automatic model selection.&lt;/p&gt;

&lt;p&gt;But Cursor has delivered a serious warning to every standalone router company: if your entire product is choosing a model, the platform that owns the workflow may eventually choose it for you.&lt;/p&gt;

&lt;p&gt;For AI coding, model routing is no longer merely an external infrastructure category. It is becoming a native feature of the development environment.&lt;/p&gt;

&lt;p&gt;The router companies are not dead but the simple router pitch might be.&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>ai</category>
      <category>mcp</category>
      <category>llm</category>
    </item>
    <item>
      <title>Open Knowledge Format (OKF) Explained</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Fri, 10 Jul 2026 05:43:48 +0000</pubDate>
      <link>https://dev.to/arindam_1729/open-knowledge-format-okf-explained-1jkk</link>
      <guid>https://dev.to/arindam_1729/open-knowledge-format-okf-explained-1jkk</guid>
      <description>&lt;p&gt;Large language models are becoming more capable every day, but they all depend on one thing: high-quality context.&lt;/p&gt;

&lt;p&gt;Projects like Andrej Karpathy's LLM Wiki have sparked conversations around representing knowledge in a way that's easier for both humans and AI to understand. The Open Knowledge Format (OKF) takes a different approach by introducing an open, vendor-neutral format for representing knowledge using Markdown and YAML.&lt;/p&gt;

&lt;p&gt;In this video, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the Open Knowledge Format (OKF) is&lt;/li&gt;
&lt;li&gt;Why it was created&lt;/li&gt;
&lt;li&gt;How it differs from traditional knowledge catalogs&lt;/li&gt;
&lt;li&gt;The structure of an OKF bundle&lt;/li&gt;
&lt;li&gt;How the Reference Agent generates knowledge automatically&lt;/li&gt;
&lt;li&gt;How the Visualizer turns knowledge into an interactive graph&lt;/li&gt;
&lt;li&gt;Why treating knowledge as code could become an important idea for AI systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're building AI applications, developer tools, documentation systems, or simply interested in how knowledge is evolving in the AI era, this video will give you a solid understanding of OKF and the ideas behind it.&lt;/p&gt;

&lt;p&gt;If you enjoyed the video, consider subscribing for more content on AI engineering, open source, developer tools, and modern software architecture.&lt;/p&gt;

</description>
      <category>okf</category>
      <category>llmwiki</category>
      <category>karpathy</category>
      <category>llm</category>
    </item>
    <item>
      <title>Building a Debate Council of LLMs to Stress-Test NVIDIA Cosmos 3</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Wed, 24 Jun 2026 13:19:01 +0000</pubDate>
      <link>https://dev.to/arindam_1729/building-a-debate-council-of-llms-to-stress-test-nvidia-cosmos-3-2ihc</link>
      <guid>https://dev.to/arindam_1729/building-a-debate-council-of-llms-to-stress-test-nvidia-cosmos-3-2ihc</guid>
      <description>&lt;p&gt;A benchmark score tells you how a model did on a test. It does not tell you whether the model can hold a position, take a punch, and adjust without falling apart.&lt;/p&gt;

&lt;p&gt;That second thing is what I wanted to know about &lt;a href="https://nvidianews.nvidia.com/news/nvidia-launches-cosmos-3-the-open-frontier-foundation-model-for-physical-ai" rel="noopener noreferrer"&gt;NVIDIA Cosmos 3&lt;/a&gt;, which NVIDIA had just shipped. So instead of running yet another eval, I did something more fun. I built the model an arena and made it argue with itself.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2061515414837100955-360" src="https://platform.twitter.com/embed/Tweet.html?id=2061515414837100955"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2061515414837100955-360');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2061515414837100955&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The result is &lt;strong&gt;Cosmos Arena&lt;/strong&gt;, a multi-agent debate council. You hand it a motion, something like "This house believes AGI will arrive before 2035," and five roles fight it out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Advocate argues for, a Skeptic argues against&lt;/li&gt;
&lt;li&gt;They trade rebuttals across several rounds&lt;/li&gt;
&lt;li&gt;An optional Pragmatist pokes holes in both sides&lt;/li&gt;
&lt;li&gt;An Arbiter scores everything and hands down a verdict&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the catch that makes it a real test: every seat runs on the same model. The only thing that changes is the role.&lt;/p&gt;

&lt;p&gt;That is surprisingly hard to fake. A model that just knows how to sound smart will produce two confident speeches that never touch. A model that can actually reason opens round two by answering the exact weakness the other side exposed in round one. You watch the difference happen, turn by turn.&lt;/p&gt;

&lt;p&gt;This tutorial is the full build. By the end you will have a working Streamlit app, you will get why the orchestration uses LangGraph instead of one model pretending to be everyone, and you will know how to serve Cosmos 3 through Nebius Token Factory.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, what Cosmos 3 actually is
&lt;/h2&gt;

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

&lt;p&gt;Let me be honest about the model up front, because it is not a normal chat model, and the name can mislead you.&lt;/p&gt;

&lt;p&gt;NVIDIA built Cosmos 3 for &lt;strong&gt;Physical AI&lt;/strong&gt;: robots, autonomous vehicles, factory floors, anything that has to understand motion, causality, and physics in the real world. NVIDIA &lt;a href="https://blogs.nvidia.com/blog/cosmos-3-physical-ai-open-world-foundation-model/" rel="noopener noreferrer"&gt;launched it on June 1, 2026 at GTC Taipei&lt;/a&gt; and calls it the first fully open omnimodel with native vision reasoning.&lt;/p&gt;

&lt;p&gt;Under the hood it is a Mixture-of-Transformers that pairs a &lt;strong&gt;reasoning transformer&lt;/strong&gt; with an &lt;strong&gt;expert generation transformer&lt;/strong&gt;. One half thinks about object interactions, motion, and space. The other half generates video and action trajectories.&lt;/p&gt;

&lt;p&gt;The whole point is to let a robot reason before it acts, which cuts physical AI training cycles from months down to days. The &lt;a href="https://developer.nvidia.com/blog/develop-physical-ai-reasoning-world-and-action-models-with-nvidia-cosmos-3/" rel="noopener noreferrer"&gt;NVIDIA technical blog&lt;/a&gt; goes deep if you want the full picture.&lt;/p&gt;

&lt;p&gt;So why use a robotics world model to run a debate? Because that reasoning transformer is the interesting part. NVIDIA trained it to reason about the physical world, and I wanted to see how well that transfers to something it was never sold for: a pure-language argument, no images, no video, just ideas. That transfer tells you far more than a single-prompt score ever will.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosmos 3 specs at a glance
&lt;/h2&gt;

&lt;p&gt;Here are the details that matter for this project.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Cosmos 3 Super&lt;/th&gt;
&lt;th&gt;Cosmos 3 Nano&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total parameters&lt;/td&gt;
&lt;td&gt;64B&lt;/td&gt;
&lt;td&gt;16B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split&lt;/td&gt;
&lt;td&gt;32B reasoner + 32B generator&lt;/td&gt;
&lt;td&gt;8B reasoner + 8B generator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture&lt;/td&gt;
&lt;td&gt;Mixture-of-Transformers (reasoning + generation)&lt;/td&gt;
&lt;td&gt;Mixture-of-Transformers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built for&lt;/td&gt;
&lt;td&gt;Post-training robotics and AV models at the highest physics accuracy&lt;/td&gt;
&lt;td&gt;Fast video and action reasoning in a fraction of a second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;OpenMDW (open for commercial and non-commercial use)&lt;/td&gt;
&lt;td&gt;OpenMDW&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Released&lt;/td&gt;
&lt;td&gt;June 1, 2026 (GTC Taipei)&lt;/td&gt;
&lt;td&gt;June 1, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few more things worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is genuinely &lt;strong&gt;omnimodal&lt;/strong&gt;. It takes in and generates text, images, video, ambient sound, and action sequences, all in one model.&lt;/li&gt;
&lt;li&gt;It was trained on one of the largest multimodal physical AI datasets out there, billions of samples across text, image, video, sound, and action.&lt;/li&gt;
&lt;li&gt;It shipped with a &lt;strong&gt;Cosmos Coalition&lt;/strong&gt; of robotics and AI labs (Agile Robots, Black Forest Labs, Runway, Skild AI, and others) building on top of it.&lt;/li&gt;
&lt;li&gt;NVIDIA is upfront about the limits: generation can drift over time, and the reasoning can still hallucinate, since there is no physics simulator actually running in the loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our build, the parts that matter are the reasoner tower and how well the model holds a role. The debate leans hard on both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it runs: Nebius Token Factory
&lt;/h2&gt;

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

&lt;p&gt;A 64B omni-model is not something I want to babysit on my own GPUs. So every model call in this project goes through &lt;a href="https://dub.sh/nebius" rel="noopener noreferrer"&gt;Nebius Token Factory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Token Factory is Nebius's production inference platform. It takes open and partner models, including NVIDIA's, and serves them behind one fast, OpenAI-compatible API, with the posttraining and governance pieces handled for you.&lt;/p&gt;

&lt;p&gt;NVIDIA models like Nemotron already run there, and Nebius has been &lt;a href="https://nebius.com/newsroom/nebius-teams-with-nvidia-to-build-cloud-for-robotics-and-physical-ai" rel="noopener noreferrer"&gt;building cloud infrastructure with NVIDIA specifically for robotics and physical AI&lt;/a&gt;. That makes it a natural home for Cosmos.&lt;/p&gt;

&lt;p&gt;Why it fits this project so well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI-compatible API.&lt;/strong&gt; Anything built for OpenAI works with a base-URL swap. The base URL is &lt;code&gt;https://api.tokenfactory.nebius.com/v1/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drop-in LangChain support.&lt;/strong&gt; The &lt;a href="https://pypi.org/project/langchain-nebius/" rel="noopener noreferrer"&gt;&lt;code&gt;langchain-nebius&lt;/code&gt;&lt;/a&gt; package gives you a &lt;code&gt;ChatNebius&lt;/code&gt; model that slots straight into LangGraph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No GPUs to provision.&lt;/strong&gt; You point at a model name and pay per token. That is the whole setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One key for five seats.&lt;/strong&gt; Every council member shares a single &lt;code&gt;NEBIUS_API_KEY&lt;/code&gt;, so there are no per-agent credentials to juggle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Grab a key from the &lt;a href="https://tokenfactory.nebius.com/" rel="noopener noreferrer"&gt;Nebius Token Factory console&lt;/a&gt; and you are ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;

&lt;p&gt;The council has five roles. Four of them are model calls. The fifth, the Moderator, is the graph itself, and that turns out to be the decision that makes everything work.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The Advocate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;proponent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Argues for the motion, rebuts the Skeptic each round&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Skeptic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;opponent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Argues against the motion, rebuts the Advocate each round&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Pragmatist&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pragmatist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Independent member who stress-tests both sides (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Arbiter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;judge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scores logic, evidence, and rebuttal, then gives a verdict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Moderator&lt;/td&gt;
&lt;td&gt;the graph&lt;/td&gt;
&lt;td&gt;Routes turns, threads the transcript, decides when to stop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The flow goes from opening statements, through alternating rebuttal rounds, to an optional reality check, and finally a scored verdict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        +--------------+      +-------------+
START -&amp;gt;|  proponent   | ---&amp;gt; |  opponent   | --&amp;gt; (more rounds?)
        +--------------+      +-------------+         |
              ^  more rounds: next_round              | no
              +---------------------------------------+
                                                      v
                                  (pragmatist?) -&amp;gt; judge -&amp;gt; END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why a graph and not one clever prompt
&lt;/h2&gt;

&lt;p&gt;You could try the lazy version: one prompt that says "argue both sides of X, then judge it." It reads fine and proves nothing.&lt;/p&gt;

&lt;p&gt;The problem is that the model writes the "for" case and the "against" case in a single breath. They do not respond to each other, because they were written together. There is no exchange, just a model acting out the idea of a debate.&lt;/p&gt;

&lt;p&gt;A real debate needs structure that a prompt cannot promise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each side gets its own turn, so each argument is a focused generation&lt;/li&gt;
&lt;li&gt;A rebuttal sees what the other side actually just said&lt;/li&gt;
&lt;li&gt;Rounds stack up, so later the Advocate answers a real objection instead of repeating its opener&lt;/li&gt;
&lt;li&gt;The judge reads the full transcript and scores it on fixed criteria&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a state machine, not a prompt, which is exactly what LangGraph is for. Putting the structure in code means each role gets its own isolated call, rebuttals genuinely see the prior turn, and the round count is enforced rather than left to the model's mood.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.11 or higher&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://dub.sh/nebius" rel="noopener noreferrer"&gt;Nebius Token Factory&lt;/a&gt; account and API key&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/astral-sh/uv" rel="noopener noreferrer"&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/a&gt; for dependencies (&lt;code&gt;pip install uv&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dependency list is short on purpose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="py"&gt;"langgraph&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="s"&gt;",&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="py"&gt;"langchain-nebius&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="s"&gt;",&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="py"&gt;"langchain-core&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="s"&gt;",&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="py"&gt;"python-dotenv&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s"&gt;",&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    &lt;span class="py"&gt;"streamlit&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.47&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="s"&gt;",&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cosmos_arena_debate_council/
  app.py              # Streamlit UI and live debate streaming
  cosmos_council.py   # LangGraph debate graph: nodes, routing, model
  pyproject.toml      # Dependencies
  .env.example        # Environment variable template
  assets/             # NVIDIA and Nebius logos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Arindam200/awesome-ai-apps.git
&lt;span class="nb"&gt;cd &lt;/span&gt;awesome-ai-apps/advance_ai_agents/cosmos_arena_debate_council
uv &lt;span class="nb"&gt;sync
cp&lt;/span&gt; .env.example .env   &lt;span class="c"&gt;# then add your NEBIUS_API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEBIUS_API_KEY=your_api_key_here
# Optional overrides
COSMOS_MODEL=nvidia/Cosmos3-Super-Reasoner
NEBIUS_BASE_URL=https://api.tokenfactory.nebius.com/v1/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Wire up Cosmos 3 and handle the reasoning channel
&lt;/h2&gt;

&lt;p&gt;This is the one gotcha that will trip you up, so it goes first.&lt;/p&gt;

&lt;p&gt;The stock &lt;code&gt;ChatNebius&lt;/code&gt; integration reads the answer from &lt;code&gt;message.content&lt;/code&gt;, the usual OpenAI shape. But Cosmos, served as a reasoner, often puts its answer in a non-standard &lt;code&gt;reasoning&lt;/code&gt; field and leaves &lt;code&gt;content&lt;/code&gt; empty. Use the integration as-is and every council member comes back blank.&lt;/p&gt;

&lt;p&gt;The fix is a small subclass that folds the reasoning field back in. If &lt;code&gt;content&lt;/code&gt; is empty, the reasoning is the answer. If both are there, the reasoning becomes separate chain-of-thought for the UI to show.&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;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.outputs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatResult&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_nebius&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatNebius&lt;/span&gt;

&lt;span class="n"&gt;DEFAULT_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.tokenfactory.nebius.com/v1/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nvidia/Cosmos3-Super-Reasoner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CosmosChatNebius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChatNebius&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;ChatNebius that surfaces the non-standard `reasoning` field.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_create_chat_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generation_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ChatResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;_create_chat_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generation_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;choice&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
            &lt;span class="n"&gt;reasoning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reasoning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;
            &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="c1"&gt;# Real answer present, keep reasoning as separate chain-of-thought.
&lt;/span&gt;                &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;additional_kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reasoning_content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Empty content, so the reasoning is the answer.
&lt;/span&gt;                &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cosmos can also do it the other way, wrapping its reasoning in &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; tags inside the content. A small splitter pulls the two apart so the UI never mixes thinking into the actual argument:&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;re&lt;/span&gt;

&lt;span class="n"&gt;_THINK_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;think&amp;gt;(.*?)&amp;lt;/think&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOTALL&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IGNORECASE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;split_reasoning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Separate the visible answer from the model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s &amp;lt;think&amp;gt; reasoning.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;reasoning_parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_THINK_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_THINK_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;think&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;  &lt;span class="c1"&gt;# unclosed reasoning block
&lt;/span&gt;        &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;think&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reasoning_parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;think&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reasoning_parts&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A shared factory ties it together. Every seat calls this same function, so the model never changes, only the prompt does:&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;os&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ChatNebius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Create the shared Cosmos reasoner backed by Nebius Token Factory.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CosmosChatNebius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;COSMOS_MODEL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NEBIUS_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NEBIUS_BASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;temperature&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;
  
  
  Step 2: Give each seat a persona
&lt;/h2&gt;

&lt;p&gt;The roles are just system prompts, but they are written to force genuinely different behavior. The Advocate and Skeptic are told to rebut the other side point by point before adding anything new. The Pragmatist takes no side. The Arbiter has to produce a fixed scorecard. Here are two of them:&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="n"&gt;PROPONENT_PROMPT&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;You are The Advocate, a council member in the Cosmos Arena debate.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your role: argue persuasively and rigorously IN FAVOR of the motion.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Guidelines:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- Make the strongest honest case for the motion.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- Ground claims in reasoning, evidence, and concrete examples.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- If you are given the opposition&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s prior argument, directly REBUT it &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;point by point before adding new arguments.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- Be sharp and confident, but never fabricate facts.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- Keep it focused: 3-5 tight paragraphs in markdown. End with your &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;single strongest line.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- Output ONLY your argument. Do not narrate your process.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;JUDGE_PROMPT&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;You are The Arbiter, the impartial judge of the Cosmos Arena debate.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You will be given the full debate transcript.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deliver your verdict as markdown with EXACTLY these sections:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;### Scorecard&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A markdown table scoring each side (Proponent, Opponent) from 0-10 on &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**Logic**, **Evidence**, and **Rebuttal**, with a **Total** column.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;### Verdict&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;State the winner (or an honest draw) in one bold sentence, then 2-3 &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentences justifying it based strictly on the arguments made.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;### Strongest Argument&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Quote or paraphrase the single most decisive point.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;### What Would Change the Outcome&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;One short paragraph on the evidence or reasoning that would flip the result.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where you find out if Cosmos 3 can really be five different people. Weaker models leak. The Skeptic starts agreeing, or the Arbiter picks a winner before it reads anything. A strong reasoner keeps the seats clean all the way through.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Model the debate as state
&lt;/h2&gt;

&lt;p&gt;The whole debate lives in one typed state object. The trick is &lt;code&gt;transcript&lt;/code&gt;, an append-only list. Each node returns only its single new turn, and LangGraph's reducer, &lt;code&gt;operator.add&lt;/code&gt;, tacks it onto the running transcript. That means each streamed update is exactly one new turn, which is perfect for a live UI.&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;operator&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypedDict&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;   &lt;span class="c1"&gt;# proponent | opponent | pragmatist | judge
&lt;/span&gt;    &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;     &lt;span class="c1"&gt;# debate round (0 for judge and pragmatist)
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;      &lt;span class="c1"&gt;# the visible argument
&lt;/span&gt;    &lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="c1"&gt;# the model's chain-of-thought, if any
&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DebateState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;current_round&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="c1"&gt;# operator.add makes each node APPEND its turn to the transcript.
&lt;/span&gt;    &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Turn&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One small helper grabs the other side's most recent turn. This is the piece that makes rebuttals real instead of generic:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_latest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Turn&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;turn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Write the nodes
&lt;/h2&gt;

&lt;p&gt;Each council member is a node: one model call with a role prompt and a user prompt built from the live transcript. Watch how the proponent's prompt changes between the opening round and later rounds. From round two on, it gets handed the Skeptic's latest argument and told to rebut it point by point. That is the whole difference between a debate and two people talking past each other.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&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;role&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;system&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inline_reasoning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;split_reasoning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reasoning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;additional_kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reasoning_content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;inline_reasoning&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;proponent_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DebateState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;rnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_round&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rnd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The motion before the council:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;motion&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deliver your OPENING case in favor of the motion.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The motion before the council:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;motion&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Skeptic&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s most recent argument was:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;_latest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;transcript&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;opponent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is round &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Rebut the Skeptic point by point, then &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;press your strongest new arguments for the motion.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PROPONENT_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcript&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="nc"&gt;Turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;)]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The judge node works the same way but reads the entire transcript and produces the scorecard. Since the transcript is already clean and structured, there is no fragile report parsing. Clean text in, verdict out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Let the graph moderate
&lt;/h2&gt;

&lt;p&gt;Here is the payoff. The Moderator is not a model deciding what comes next, it is plain deterministic routing. START to proponent to opponent, then a conditional edge decides: run another round, or wrap up? If rounds remain, bump the counter and loop back. If not, run the optional Pragmatist, then the Arbiter, then end.&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;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_debate_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_pragmatist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ... node definitions: proponent, opponent, pragmatist, judge ...
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route_after_opponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DebateState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_round&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;rounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;increment_round&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pragmatist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use_pragmatist&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;judge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebateState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proponent_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;opponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opponent_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;increment_round&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;increment_round_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;judge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;judge_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use_pragmatist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pragmatist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pragmatist_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proponent&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;opponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;opponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;route_after_opponent&lt;/span&gt;&lt;span class="p"&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;increment_round&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;pragmatist&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;judge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use_pragmatist&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;increment_round&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;judge&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;increment_round&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;proponent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use_pragmatist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pragmatist&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;judge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;judge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Stream it live in Streamlit
&lt;/h2&gt;

&lt;p&gt;The UI streams with &lt;code&gt;stream_mode="updates"&lt;/code&gt;, so each member's argument shows up the moment its node finishes. Color-coded card, correct round, and a collapsible panel that exposes Cosmos 3's chain-of-thought.&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;config&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;recursion_limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;stream_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;updates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="n"&gt;new_turns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;new_turns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="c1"&gt;# skip the increment_round bookkeeping step
&lt;/span&gt;        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="n"&gt;turn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_turns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reasoning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;live&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&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 streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:8501&lt;/code&gt;, pick your number of rounds (1 to 4) and whether to seat the Pragmatist, type in a motion, and hit "Convene the Council."&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like in action
&lt;/h2&gt;

&lt;p&gt;Let me run the motion "This house believes AGI will arrive before 2035."&lt;/p&gt;

&lt;p&gt;The Advocate opens strong on compute scaling curves, efficiency gains, and the money pouring into the field. Confident, concrete, ends on a sharp line.&lt;/p&gt;

&lt;p&gt;The Skeptic does not blink. A trend line is not a mechanism, benchmark progress is not general capability, and "before 2035" is a specific claim that needs a specific argument the other side has not made.&lt;/p&gt;

&lt;p&gt;Round two is where it gets good. The Advocate opens by quoting the Skeptic's "no mechanism" point and answering it head-on before pressing forward. The rebuttal threading is working. This is now an actual exchange.&lt;/p&gt;

&lt;p&gt;The Pragmatist steps outside the fight and calls it: both sides are arguing definitions. What would really settle it is a measurable capability threshold tied to a date. Name it, or you are just debating vibes.&lt;/p&gt;

&lt;p&gt;Then the Arbiter closes with a scorecard:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Side&lt;/th&gt;
&lt;th&gt;Logic&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;th&gt;Rebuttal&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Proponent&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opponent&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It gives the win to the Skeptic, narrowly. The Advocate argued well and rebutted directly, but leaned on extrapolation where the Skeptic demanded a mechanism, and that hard 2035 deadline raised a bar the Advocate never quite cleared.&lt;/p&gt;

&lt;p&gt;The fun part is not who won. It is that the round-two rebuttal genuinely engaged the round-one objection. That only happens if the model can hold a position, absorb a counter, and adjust, which is exactly the reasoning I was trying to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this tells you about Cosmos 3
&lt;/h2&gt;

&lt;p&gt;Running a few motions through the arena surfaces things a benchmark never will.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role discipline.&lt;/strong&gt; Does the Skeptic stay skeptical for four straight rounds, or quietly start agreeing? Cosmos held its seats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebuttal quality.&lt;/strong&gt; Do later rounds answer the specific prior point, or just restate the opener with new adjectives? This is the clearest signal of real reasoning, and you can see it live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Judgment calibration.&lt;/strong&gt; Does the Arbiter's verdict actually follow from the transcript, or does it pick a side and backfill? Read the scorecard against what was said and you will know fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A debate is really a reasoning stress test in disguise: adversarial, multi-turn, and either self-consistent across rounds or not. For a model whose reasoner was trained mostly on physical and spatial problems, watching it carry that reasoning into abstract language debate is a genuinely interesting result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trade-offs, honestly
&lt;/h2&gt;

&lt;p&gt;This is not free. A two-round debate with the Pragmatist is six full reasoning-model calls: the Advocate twice, the Skeptic twice, the Pragmatist, and the Arbiter. Reasoning models also emit a lot of thinking tokens. More rounds means more cost and more waiting.&lt;/p&gt;

&lt;p&gt;For this use case it is worth it, because the structure is the product and watching the reasoning unfold is the whole point. For a plain question-and-answer task, it would be massive overkill. Match the architecture to the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;You now have a working multi-agent debate council. It models a structured debate as an explicit LangGraph state machine instead of a prompt, threads real rebuttals through a shared append-only transcript, runs every seat on NVIDIA Cosmos 3 while surfacing its chain-of-thought, and serves the whole thing through one &lt;a href="https://dub.sh/nebius" rel="noopener noreferrer"&gt;Nebius Token Factory&lt;/a&gt; key over an OpenAI-compatible API.&lt;/p&gt;

&lt;p&gt;From here the graph makes it easy to keep going. Add seats like a Historian or a Domain Expert. Let the Arbiter call a tie-breaker round. Wire in retrieval so arguments cite real sources. Or run a tournament of motions and chart which side the model tends to favor. Each one is just a few more nodes and edges.&lt;/p&gt;

&lt;p&gt;Want to try it? Clone the &lt;a href="https://github.com/Arindam200/awesome-ai-apps" rel="noopener noreferrer"&gt;repo&lt;/a&gt;, grab a &lt;a href="https://tokenfactory.nebius.com/" rel="noopener noreferrer"&gt;Nebius Token Factory&lt;/a&gt; key, and convene your own council. Pick a motion you genuinely cannot call, and see how Cosmos 3 reasons its way through it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by Arindam Majumder. Part of the &lt;a href="https://github.com/Arindam200/awesome-ai-apps" rel="noopener noreferrer"&gt;awesome-ai-apps&lt;/a&gt; collection, powered by &lt;a href="https://langchain-ai.github.io/langgraph/" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt;, &lt;a href="https://developer.nvidia.com/blog/develop-physical-ai-reasoning-world-and-action-models-with-nvidia-cosmos-3/" rel="noopener noreferrer"&gt;NVIDIA Cosmos 3&lt;/a&gt;, and &lt;a href="https://dub.sh/nebius" rel="noopener noreferrer"&gt;Nebius Token Factory&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nvidia</category>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>The Best Vercel Analytics Alternative When You Outgrow the Free Tier</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Sat, 13 Jun 2026 20:16:35 +0000</pubDate>
      <link>https://dev.to/raah/the-best-vercel-analytics-alternative-when-you-outgrow-the-free-tier-2e0l</link>
      <guid>https://dev.to/raah/the-best-vercel-analytics-alternative-when-you-outgrow-the-free-tier-2e0l</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vercel Analytics is a convenient starting point for Vercel-hosted projects, especially when you only need simple traffic analytics.&lt;/li&gt;
&lt;li&gt;The Hobby plan includes a capped monthly Web Analytics allowance. If your site grows beyond that allowance, you may need to upgrade or move to another analytics setup.&lt;/li&gt;
&lt;li&gt;Speed Insights is separate from Web Analytics and has its own data-point limits and pricing model.&lt;/li&gt;
&lt;li&gt;Raah is a strong Vercel Analytics alternative when you want traffic analytics, Core Web Vitals, network performance, third-party script monitoring, frontend errors, and user journeys in one dashboard.&lt;/li&gt;
&lt;li&gt;You do not need to move your app away from Vercel to use Raah. Add one lightweight beacon and keep your existing hosting workflow.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Vercel Analytics is one of the easiest ways to add traffic analytics to a Vercel-hosted site. If you already deploy with Vercel, the setup is simple, the dashboard is clean, and the data is useful enough for many early projects.&lt;/p&gt;

&lt;p&gt;But the free tier has limits.&lt;/p&gt;

&lt;p&gt;On the Hobby plan, Vercel Analytics includes a capped amount of monthly Web Analytics events. Once your site grows beyond that allowance, tracking can stop until the next billing cycle unless you upgrade. Vercel also prices additional Web Analytics events on paid plans, and Speed Insights has its own separate usage model.&lt;/p&gt;

&lt;p&gt;That is fine for some teams. But if you want predictable analytics, privacy-friendly tracking, Web Vitals, network performance, and user behavior insights in one place, you may want a Vercel Analytics alternative.&lt;/p&gt;

&lt;p&gt;That is where &lt;a href="https://raah.dev/" rel="noopener noreferrer"&gt;Raah&lt;/a&gt; fits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why people look for a Vercel Analytics alternative
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ptj0jq7vvzapl7aarbo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ptj0jq7vvzapl7aarbo.png" alt="Vercel Analytics dashboard with visitor charts and event tracking" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most people do not start looking for an alternative because Vercel Analytics is hard to use. They start looking because their needs change.&lt;/p&gt;

&lt;p&gt;Common reasons include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your site is growing beyond the Hobby analytics allowance.&lt;/li&gt;
&lt;li&gt;You do not want analytics tied to your hosting provider.&lt;/li&gt;
&lt;li&gt;You want traffic analytics and performance monitoring in one dashboard.&lt;/li&gt;
&lt;li&gt;You need deeper frontend observability than pageviews alone.&lt;/li&gt;
&lt;li&gt;You want cookie-free analytics without consent banner complexity.&lt;/li&gt;
&lt;li&gt;You want to monitor Core Web Vitals, API calls, third-party scripts, and user journeys together.&lt;/li&gt;
&lt;li&gt;You deploy across Vercel, Netlify, Cloudflare, custom servers, or multiple platforms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vercel Analytics is convenient if your whole world lives inside Vercel. Raah is built for teams that want analytics to follow the product, not the hosting provider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.raah.dev%2Fimages%2Fblog%2Fvercel-analytics-alternative%2Fvisitor-chart-dark.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.raah.dev%2Fimages%2Fblog%2Fvercel-analytics-alternative%2Fvisitor-chart-dark.avif" alt="Vercel Analytics visitor chart showing traffic activity" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vercel Analytics free tier: what to know
&lt;/h2&gt;

&lt;p&gt;Vercel's Hobby plan includes a free Web Analytics allowance, but it is capped. Vercel's public pricing also lists paid Web Analytics usage at a per-event rate on paid plans.&lt;/p&gt;

&lt;p&gt;Speed Insights is separate from Web Analytics. On the Hobby plan, Vercel provides a free Speed Insights allowance for one project, with its own data-point limits.&lt;/p&gt;

&lt;p&gt;That means your actual analytics setup may involve more than one usage bucket:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Analytics events&lt;/li&gt;
&lt;li&gt;Speed Insights data points&lt;/li&gt;
&lt;li&gt;Add-ons if you are on a paid plan&lt;/li&gt;
&lt;li&gt;Usage-based pricing as traffic grows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For small personal projects, this may be enough. For a growing product, SaaS app, content site, or startup landing page, those limits can become part of your analytics decision.&lt;/p&gt;

&lt;p&gt;For the exact current numbers, always check the official &lt;a href="https://vercel.com/pricing" rel="noopener noreferrer"&gt;Vercel pricing page&lt;/a&gt; and &lt;a href="https://vercel.com/docs/speed-insights/limits-and-pricing" rel="noopener noreferrer"&gt;Speed Insights limits and pricing documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to use instead: Raah
&lt;/h2&gt;

&lt;p&gt;Raah is a privacy-first website analytics and frontend observability platform for developers.&lt;/p&gt;

&lt;p&gt;You add one lightweight script to your site, and Raah gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pageviews and visitor analytics&lt;/li&gt;
&lt;li&gt;Referrers and UTM campaign tracking&lt;/li&gt;
&lt;li&gt;Device, browser, country, and city breakdowns&lt;/li&gt;
&lt;li&gt;Core Web Vitals monitoring&lt;/li&gt;
&lt;li&gt;Network request performance&lt;/li&gt;
&lt;li&gt;API and endpoint timing&lt;/li&gt;
&lt;li&gt;Third-party script performance&lt;/li&gt;
&lt;li&gt;User journey visibility&lt;/li&gt;
&lt;li&gt;Frontend error tracking&lt;/li&gt;
&lt;li&gt;Performance alerts&lt;/li&gt;
&lt;li&gt;Cookie-free tracking without fingerprinting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raah is built for teams that want to understand both traffic and user experience.&lt;/p&gt;

&lt;p&gt;Traditional analytics tools tell you what pages people visit. Raah also helps you understand whether those pages are fast, which APIs are slow, which third-party scripts are hurting performance, and where users are coming from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfymbj9hf2jp1zfl5z7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfymbj9hf2jp1zfl5z7w.png" alt="Raah user analytics dashboard showing visitor trends and traffic breakdowns" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vercel Analytics vs Raah
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Vercel Analytics&lt;/th&gt;
&lt;th&gt;Raah&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic pageview analytics&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works outside Vercel&lt;/td&gt;
&lt;td&gt;Limited by setup and use case&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookie-free analytics&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core Web Vitals&lt;/td&gt;
&lt;td&gt;Via Speed Insights&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network request monitoring&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API performance from the browser&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third-party script performance&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User journey insights&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy-friendly by default&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting-provider independent&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vercel Analytics is a good fit if you want simple analytics for a Vercel project.&lt;/p&gt;

&lt;p&gt;Raah is a better fit if you want a fuller picture of what users experience after they land on your site.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you switch from Vercel Analytics?
&lt;/h2&gt;

&lt;p&gt;You should consider switching when analytics becomes part of how you run the product, not just something you occasionally check.&lt;/p&gt;

&lt;p&gt;For example, switch when you want to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which marketing campaigns are bringing users who actually engage?&lt;/li&gt;
&lt;li&gt;Which pages are slow for real users?&lt;/li&gt;
&lt;li&gt;Are API calls slowing down the user journey?&lt;/li&gt;
&lt;li&gt;Which third-party scripts are hurting load time?&lt;/li&gt;
&lt;li&gt;Where are users dropping off?&lt;/li&gt;
&lt;li&gt;Are performance issues happening for specific countries, browsers, or networks?&lt;/li&gt;
&lt;li&gt;Can I monitor analytics and frontend reliability in one dashboard?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only need a simple pageview counter, Vercel Analytics may be enough.&lt;/p&gt;

&lt;p&gt;If you need traffic analytics plus real-user performance monitoring, Raah gives you a broader view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85m3seotmr0n87r6qz3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85m3seotmr0n87r6qz3l.png" alt="Raah Web Vitals dashboard showing real user performance metrics" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add Raah to a Vercel site
&lt;/h2&gt;

&lt;p&gt;You do not need to move your app away from Vercel to use Raah.&lt;/p&gt;

&lt;p&gt;Raah works with Vercel-hosted sites, Next.js apps, React apps, Astro sites, Vue apps, Nuxt apps, SvelteKit apps, and other frontend frameworks.&lt;/p&gt;

&lt;p&gt;The setup is usually one script tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script
  &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://t.raah.dev/script.js"&lt;/span&gt;
  &lt;span class="na"&gt;data-pid=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_PROJECT_ID"&lt;/span&gt;
  &lt;span class="na"&gt;data-domain=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_DOMAIN"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After deployment, open your Raah dashboard and visit your site. Data usually starts appearing within a few minutes.&lt;/p&gt;

&lt;p&gt;If you use Next.js, you can also follow the framework-specific setup in the &lt;a href="https://raah.dev/docs/getting-started/install-the-beacon" rel="noopener noreferrer"&gt;Raah beacon installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Raah is a strong Vercel Analytics alternative
&lt;/h2&gt;

&lt;p&gt;The biggest reason to use Raah is that it combines analytics and frontend observability.&lt;/p&gt;

&lt;p&gt;You do not just see that a page received traffic. You can see whether the experience was good.&lt;/p&gt;

&lt;p&gt;That matters because traffic without performance context can be misleading. A campaign may bring users, but if the landing page has poor LCP, slow API calls, or a blocking third-party script, those users may leave before converting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdrdlk2go086qw3dhpi9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdrdlk2go086qw3dhpi9.png" alt="Raah observability dashboard showing frontend performance and reliability signals" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Raah helps you connect those dots:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Acquisition:&lt;/strong&gt; Where users came from.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavior:&lt;/strong&gt; What pages and journeys they followed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Experience:&lt;/strong&gt; How fast the site felt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability:&lt;/strong&gt; Which requests, scripts, or errors affected the session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes Raah useful not only for marketers, but also for founders, developers, and product teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final verdict
&lt;/h2&gt;

&lt;p&gt;Vercel Analytics is a convenient starting point for Vercel projects. The free Hobby allowance is useful for small sites, but growing products often need more flexibility, deeper visibility, and analytics that are not tied to one hosting platform.&lt;/p&gt;

&lt;p&gt;If you are looking for a Vercel Analytics alternative that gives you privacy-friendly web analytics, Core Web Vitals, network performance, third-party script monitoring, and user journey insights in one dashboard, Raah is built for that.&lt;/p&gt;

&lt;p&gt;You can keep hosting on Vercel.&lt;/p&gt;

&lt;p&gt;Just use Raah to understand what your users are actually experiencing.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>vercel</category>
      <category>webdev</category>
      <category>web</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Tue, 09 Jun 2026 16:13:29 +0000</pubDate>
      <link>https://dev.to/arindam_1729/-43l1</link>
      <guid>https://dev.to/arindam_1729/-43l1</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/raah/introducing-raah-4mng" class="crayons-story__hidden-navigation-link"&gt;Introducing Raah&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/raah"&gt;
            &lt;img alt="Raah logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F13422%2F850915c3-efdf-4c9d-9f56-06e1f7fd4f13.png" class="crayons-logo__image" width="128" height="128"&gt;
          &lt;/a&gt;

          &lt;a href="/arindam_1729" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F965723%2F8c3a1bb4-eb47-4302-a280-09eedb8bc785.png" alt="arindam_1729 profile" class="crayons-avatar__image" width="800" height="678"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/arindam_1729" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Arindam Majumder 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Arindam Majumder 
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png" width="166" height="102"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3722391" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/arindam_1729" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F965723%2F8c3a1bb4-eb47-4302-a280-09eedb8bc785.png" class="crayons-avatar__image" alt="" width="800" height="678"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Arindam Majumder &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/raah" class="crayons-story__secondary fw-medium"&gt;Raah&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/raah/introducing-raah-4mng" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 9&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/raah/introducing-raah-4mng" id="article-link-3722391"&gt;
          Introducing Raah
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/web"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;web&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webanalytics"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webanalytics&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/raah/introducing-raah-4mng" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;6&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/raah/introducing-raah-4mng#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Introducing Raah</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Tue, 09 Jun 2026 14:30:00 +0000</pubDate>
      <link>https://dev.to/raah/introducing-raah-4mng</link>
      <guid>https://dev.to/raah/introducing-raah-4mng</guid>
      <description>&lt;p&gt;Today, we are introducing Raah, a privacy-first analytics and frontend observability platform for teams that need a clearer view of what real users experience in production.&lt;/p&gt;

&lt;p&gt;Most products treat analytics, performance, errors, and uptime as separate problems. In practice, they are the same question from different angles: are people finding your product, using it, and getting a fast, reliable experience?&lt;/p&gt;

&lt;p&gt;Raah answers that from one lightweight beacon. You get traffic analytics, Core Web Vitals, browser errors, API timing, third-party script impact, alerts, and status pages in one dashboard, without cookies or fingerprinting.&lt;/p&gt;

&lt;p&gt;The goal is simple: help small teams move from scattered signals to production truth.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we built Raah
&lt;/h2&gt;

&lt;p&gt;Most teams stitch together analytics, Web Vitals tooling, error tracking, uptime checks, and backend monitoring. Each tool is useful on its own, but the complete picture is still hard to read.&lt;/p&gt;

&lt;p&gt;You may know a page received traffic, but not whether it loaded slowly. You may know an API was healthy from your server logs, but not whether users on a regional network saw high latency. You may know conversion dropped, but not whether a third-party script, JavaScript error, or poor INP contributed to the problem.&lt;/p&gt;

&lt;p&gt;Raah is built around a simple belief: product and engineering teams should be able to see user behavior and user experience together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdrdlk2go086qw3dhpi9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdrdlk2go086qw3dhpi9.png" alt="Raah observability dashboard showing frontend performance and reliability signals" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Raah gives you
&lt;/h2&gt;

&lt;p&gt;Raah starts with the questions teams ask every week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many people visited, where did they come from, and which pages mattered?&lt;/li&gt;
&lt;li&gt;Which pages are slow for real users, not just in a lab test?&lt;/li&gt;
&lt;li&gt;Which API endpoints are creating the worst p95 or p99 experience?&lt;/li&gt;
&lt;li&gt;Are errors concentrated in a browser, region, ISP, or release?&lt;/li&gt;
&lt;li&gt;Did a marketing campaign bring traffic that actually engaged?&lt;/li&gt;
&lt;li&gt;Can we explain an incident with real user evidence?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of forcing those answers across several dashboards, Raah brings the main signals into one workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfymbj9hf2jp1zfl5z7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfymbj9hf2jp1zfl5z7w.png" alt="Raah user analytics dashboard showing traffic, referrers, and visitor trends" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Analytics without the usual privacy baggage
&lt;/h2&gt;

&lt;p&gt;Raah tracks visits, pageviews, referrers, UTM campaigns, devices, geography, sessions, and engagement without setting cookies or fingerprinting users.&lt;/p&gt;

&lt;p&gt;That makes it a practical alternative for teams that want useful product analytics without turning a simple website into a consent and tracking project.&lt;/p&gt;

&lt;p&gt;The goal is not to recreate every enterprise marketing analytics feature. The goal is to give developers, founders, and product teams a clear read on what is happening and what deserves attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend observability built in
&lt;/h2&gt;

&lt;p&gt;Traffic alone does not tell you whether the experience was good. Raah also captures frontend reliability and performance signals from real browsers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core Web Vitals including LCP, CLS, INP, FCP, and TTFB&lt;/li&gt;
&lt;li&gt;Browser-level network timing including DNS, TCP, TLS, TTFB, and download phases&lt;/li&gt;
&lt;li&gt;API endpoint latency, error rate, and percentile breakdowns&lt;/li&gt;
&lt;li&gt;JavaScript errors and unhandled promise rejections&lt;/li&gt;
&lt;li&gt;Third-party script performance&lt;/li&gt;
&lt;li&gt;Session-level context for debugging what happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85m3seotmr0n87r6qz3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85m3seotmr0n87r6qz3l.png" alt="Raah Web Vitals dashboard showing real user performance metrics" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Real user network monitoring
&lt;/h2&gt;

&lt;p&gt;Synthetic checks are useful, but they run from known locations under controlled conditions. They do not show what every user saw from their own browser, device, ISP, and geography.&lt;/p&gt;

&lt;p&gt;Raah captures browser-level network telemetry from live traffic, so you can compare API and page performance by endpoint, country, ISP, status code, and timing phase.&lt;/p&gt;

&lt;p&gt;That matters when a service looks healthy from your infrastructure but feels slow to customers in a specific region or network.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79x36wlu105n3l9ivpl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79x36wlu105n3l9ivpl7.png" alt="Raah network report showing DNS, TCP, TLS, TTFB, and download timing" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Built for small teams that need production truth
&lt;/h2&gt;

&lt;p&gt;Raah is designed for teams that need practical visibility without a heavyweight rollout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SaaS teams debugging inconsistent endpoint latency&lt;/li&gt;
&lt;li&gt;Founders watching traffic, campaigns, performance, and reliability from one place&lt;/li&gt;
&lt;li&gt;Agencies managing client websites without cookie-heavy analytics setups&lt;/li&gt;
&lt;li&gt;Product teams connecting user behavior to frontend experience&lt;/li&gt;
&lt;li&gt;Engineering teams that want alerts and evidence before users complain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can start with a single script tag and let real traffic populate the dashboard.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a project in the Raah dashboard.&lt;/li&gt;
&lt;li&gt;Install the lightweight script.&lt;/li&gt;
&lt;li&gt;Let live traffic populate metrics.&lt;/li&gt;
&lt;li&gt;Use breakdowns by endpoint, ISP, geography, and session context to investigate outliers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Raah was built to help teams move from “we think it is fine” to “we know what users are seeing.”&lt;/p&gt;

</description>
      <category>web</category>
      <category>webanalytics</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Claude Opus 4.8: Effort Controls, Dynamic Workflows, and an Honest-by-Default Coding Agent</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Fri, 29 May 2026 04:51:37 +0000</pubDate>
      <link>https://dev.to/arindam_1729/claude-opus-48-effort-controls-dynamic-workflows-and-an-honest-by-default-coding-agent-3eao</link>
      <guid>https://dev.to/arindam_1729/claude-opus-48-effort-controls-dynamic-workflows-and-an-honest-by-default-coding-agent-3eao</guid>
      <description>&lt;p&gt;The frontier model race has been moving in fits and starts. OpenAI shipped GPT-5.5 and a new Codex line. Google pushed Gemini 3.1 Pro and a faster Gemini Flash. xAI keeps iterating on Grok. And now Anthropic has shipped &lt;strong&gt;Claude Opus 4.8&lt;/strong&gt;, only 41 days after Opus 4.7, which is an unusually short release cycle for them and a clear signal about how the rest of 2026 is going to feel.&lt;/p&gt;

&lt;p&gt;Opus 4.8 is not a flashy rebrand. The headline numbers are real (SWE-bench Pro at 69.2%, USAMO 2026 at 96.7%, GraphWalks at 1M tokens jumping from 40.3% to 68.1%), but the more interesting story is structural: effort controls you can dial per request, dynamic workflows that orchestrate hundreds of parallel subagents, a fast mode that is roughly three times cheaper than it used to be, and a measurable drop in the kind of overconfident, slightly-deceptive coding behavior that makes agents annoying to trust.&lt;/p&gt;

&lt;p&gt;In this article, I will walk you through everything you need to know about Opus 4.8. We will cover the release details, the new effort tiers, the Dynamic Workflows feature in Claude Code, the pricing changes, the honesty and alignment improvements, two practical things you can build with it today, and an honest assessment of where it still falls short. By the end, you should have a clear mental model of when to upgrade, when to wait, and how to actually use the new controls.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Claude Opus 4.8?
&lt;/h2&gt;

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

&lt;p&gt;Claude Opus 4.8 is Anthropic's new flagship model, released on &lt;strong&gt;May 28, 2026&lt;/strong&gt; and available immediately across the Claude API, Amazon Bedrock, Google Cloud Vertex AI, and Microsoft Foundry. The API model ID is &lt;code&gt;claude-opus-4-8&lt;/code&gt;. It ships at the same headline price as Opus 4.7, keeps the 1M-token context window, and is positioned squarely at agentic coding, long-horizon reasoning, and multi-day workflows.&lt;/p&gt;

&lt;p&gt;Here is what makes Opus 4.8 stand out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effort controls everywhere&lt;/strong&gt;: low, high (default), extra (&lt;code&gt;xhigh&lt;/code&gt;), and max tiers you can pick per request, with high tuned to spend roughly the same tokens as Opus 4.7's default while doing better work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Workflows in Claude Code&lt;/strong&gt;: a research preview that lets the model plan a job, spin up hundreds of parallel subagents, verify their outputs adversarially, and resume across multi-day runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheaper fast mode&lt;/strong&gt;: 2.5× output speed at $10/$50 per million tokens, roughly three times cheaper than the previous Opus fast mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honesty by default&lt;/strong&gt;: a four-fold reduction in unreported code flaws versus Opus 4.7, a 0% rate of uncritically reporting flawed results (the first Claude model to hit zero on that test), and a ten-fold reduction in overconfidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big agentic coding gains&lt;/strong&gt;: SWE-bench Pro at 69.2%, leading every published competitor on that benchmark.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-context retrieval breakthrough&lt;/strong&gt;: GraphWalks BFS at 1M tokens jumps from 40.3% to 68.1% F1, the biggest single benchmark gain of the release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New API ergonomics&lt;/strong&gt;: the Messages API now accepts &lt;code&gt;system&lt;/code&gt; entries inside the &lt;code&gt;messages&lt;/code&gt; array, letting you update instructions mid-task without breaking the prompt cache.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pricing and Availability
&lt;/h2&gt;

&lt;p&gt;Opus 4.8 launches at the same standard rate as Opus 4.7, which keeps the upgrade math simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standard&lt;/strong&gt;: $5 per million input tokens, $25 per million output tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast mode&lt;/strong&gt;: $10 / $50 per million tokens for roughly 2.5× the output speed. Anthropic describes this as "three times cheaper than fast mode for previous models," which is the real story here: latency-sensitive workloads that were borderline on the old Opus fast mode become economically reasonable on 4.8.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context window&lt;/strong&gt;: 1,000,000 tokens, unchanged from 4.7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access&lt;/strong&gt;: Claude API, Amazon Bedrock, Google Cloud Vertex AI, Microsoft Foundry, claude.ai, Claude Code, Cowork, and (as of release day) GitHub Copilot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because price did not move, the upgrade decision for most teams is just a function of whether the benchmark and reliability gains help your specific workload.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark Performance
&lt;/h2&gt;

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

&lt;p&gt;The benchmark deltas are the cleanest part of the release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coding
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SWE-bench Pro&lt;/strong&gt;: &lt;strong&gt;69.2%&lt;/strong&gt; (up from 64.3% on Opus 4.7). For comparison, GPT-5.5 sits at 58.6% and the next competitor at 54.2%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SWE-bench Verified&lt;/strong&gt;: 88.6% (up from 87.6%).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SWE-bench Multilingual&lt;/strong&gt;: 84.4% (up from 80.5%).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Opus 4.8 leads every SWE-bench variant. This is the most useful headline number for anyone building a coding agent today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Math and Reasoning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;USAMO 2026&lt;/strong&gt;: &lt;strong&gt;96.7%&lt;/strong&gt; (up from 69.3% on 4.7). A 27.4-point jump in one model cycle is not a normal benchmark delta. Anthropic is describing this as a qualitative change in mathematical reasoning depth, not a tuning win.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Long-Context Retrieval
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GraphWalks BFS at 1M tokens&lt;/strong&gt;: &lt;strong&gt;68.1% F1&lt;/strong&gt; (up from 40.3%).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GraphWalks Parents at 1M tokens&lt;/strong&gt;: &lt;strong&gt;83.3% F1&lt;/strong&gt; (up from 56.6%).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the release's biggest relative lead. If your application leans hard on long-context retrieval (legal review, large repo navigation, research synthesis), 4.8 is a different model than 4.7 for that work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Notable Scores
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;HLE with tools: 57.9%&lt;/li&gt;
&lt;li&gt;OSWorld-Verified (computer use): 83.4%&lt;/li&gt;
&lt;li&gt;MCP-Atlas: 82.2%&lt;/li&gt;
&lt;li&gt;Finance Agent v2: 53.9%&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where It Regressed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GPQA Diamond&lt;/strong&gt;: 93.6% vs 94.2% on 4.7. Near-saturated benchmark, so variance at the top is expected, but worth flagging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal-Bench 2.1&lt;/strong&gt;: 74.6%, behind GPT-5.5's 78.2%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multilingual tasks&lt;/strong&gt;: trails Gemini 3.1 Pro and GPT-5.5 in several languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take the benchmarks as directional. The honesty and reliability deltas below matter more for production use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Effort Control: The Knob You Have Been Waiting For
&lt;/h2&gt;

&lt;p&gt;Opus 4.8 exposes four effort tiers, and you can set them per request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Low&lt;/strong&gt;: fast responses, minimal token use. Best for summarization, classification, and simple Q&amp;amp;A.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High&lt;/strong&gt; (default): Anthropic's "best balance" tier. Tuned to spend similar tokens to Opus 4.7's default while outperforming it on coding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extra&lt;/strong&gt; (&lt;code&gt;xhigh&lt;/code&gt;): recommended for difficult tasks and long-running async workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Max&lt;/strong&gt;: maximum token depth. Reserve for quality-only priorities where you do not care about cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The effort knob is exposed in claude.ai and Cowork (all plans), in Claude Code via the existing effort menu, and in the API. Claude Code's rate limits have been raised to accommodate the new high default. This is the kind of control that used to live behind enterprise sales conversations, and getting it as a first-class request parameter is a quiet but meaningful win.&lt;/p&gt;

&lt;p&gt;A practical migration heuristic: move to Opus 4.8 on the default high tier first, then sample representative tasks at xhigh to model the token-cost delta before turning it on in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dynamic Workflows: Hundreds of Subagents, Multi-Day Jobs
&lt;/h2&gt;

&lt;p&gt;The biggest new feature in this release is &lt;strong&gt;Dynamic Workflows&lt;/strong&gt;, a research preview inside Claude Code that lets Opus 4.8 orchestrate work normally reserved for a small engineering team.&lt;/p&gt;

&lt;p&gt;The capability, in short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model plans a job.&lt;/li&gt;
&lt;li&gt;It spins up tens or hundreds of parallel subagents to execute pieces of it.&lt;/li&gt;
&lt;li&gt;Other agents adversarially try to refute the findings before they are reported.&lt;/li&gt;
&lt;li&gt;State is checkpointed, so jobs survive interruptions and resume across multi-day runs.&lt;/li&gt;
&lt;li&gt;Coordination happens outside the conversation thread, so the main session stays responsive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The use cases Anthropic is pointing at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Codebase-wide bug hunts and dead-code discovery.&lt;/li&gt;
&lt;li&gt;Security and hardening audits.&lt;/li&gt;
&lt;li&gt;Large migrations: framework swaps, language ports, API deprecations.&lt;/li&gt;
&lt;li&gt;Verification-heavy tasks where you want independent attempts plus an adversarial reviewer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The canonical case study is &lt;strong&gt;Bun's Zig-to-Rust port&lt;/strong&gt;, run by Jarred Sumner: 750,000 lines of Rust generated, 99.8% of the test suite passing, eleven days from first commit to merge. The workflow first mapped lifetime requirements, then parallel writers generated every &lt;code&gt;.rs&lt;/code&gt; file with two reviewers per file, and an overnight fix loop addressed a data-copy optimization. That is a real-world result, not a benchmark.&lt;/p&gt;

&lt;h3&gt;
  
  
  Activation
&lt;/h3&gt;

&lt;p&gt;Inside Claude Code, you turn it on in any of three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable auto mode in Claude Code.&lt;/li&gt;
&lt;li&gt;Ask explicitly: "create a workflow."&lt;/li&gt;
&lt;li&gt;Toggle the &lt;code&gt;ultracode&lt;/code&gt; setting, which sets effort to &lt;code&gt;xhigh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first trigger shows you a preview and requires confirmation. Dynamic Workflows is available on Max, Team, and Enterprise (admin-enabled), and via the APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Cost Warning
&lt;/h3&gt;

&lt;p&gt;Workflows consume substantially more tokens than standard sessions. Plan your budgets before flipping this on in production. The same feature that finishes a quarter's worth of work in days will also spend a quarter's worth of tokens in the same window if you do not watch it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Honesty, Reliability, and Alignment
&lt;/h2&gt;

&lt;p&gt;This is the part of the release that does not show up cleanly in a benchmark table but matters most for anyone shipping agents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Honesty
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Four-fold reduction&lt;/strong&gt; in unreported code flaws versus Opus 4.7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code summary honesty&lt;/strong&gt;: fails to flag important events only 3.7% of the time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uncritically reporting flawed results&lt;/strong&gt;: &lt;strong&gt;0%&lt;/strong&gt;. First Claude model to score zero on that test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overconfidence&lt;/strong&gt;: more than ten-fold improvement over Opus 4.7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy investigation&lt;/strong&gt;: perfect score. Opus 4.7 gave incorrect answers 25% of the time on the same probe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read those as one trend: Opus 4.8 is significantly less likely to hand you a confident-sounding summary that papers over a real problem. Bridgewater Associates' testimonial in Anthropic's launch coverage explicitly calls out "Opus 4.8's tendency to proactively flag issues with the inputs and outputs of an analysis" as the differentiator.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alignment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Stronger prosocial behavior and user-autonomy support.&lt;/li&gt;
&lt;li&gt;Substantially lower deceptive and misuse-enabling behaviors than 4.7.&lt;/li&gt;
&lt;li&gt;Reckless or destructive actions reduced significantly.&lt;/li&gt;
&lt;li&gt;Overall alignment risk rated "very low."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Agentic Security Caveat
&lt;/h3&gt;

&lt;p&gt;One regression worth taking seriously: prompt-injection robustness dropped. &lt;strong&gt;Gray Swan attack success rate climbed to roughly 9.6%, up from 6.0% on Opus 4.7.&lt;/strong&gt; If your pipeline ingests untrusted external content (scraped web pages, user-submitted documents, third-party tool output) review your sandboxing approach before upgrading.&lt;/p&gt;




&lt;h2&gt;
  
  
  API Enhancements You Should Actually Notice
&lt;/h2&gt;

&lt;p&gt;The Messages API now accepts &lt;code&gt;system&lt;/code&gt; entries inside the &lt;code&gt;messages&lt;/code&gt; array. In practice that means you can update instructions mid-task without breaking the prompt cache, which has been a real pain point for long-horizon agents.&lt;/p&gt;

&lt;p&gt;Concrete use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adjusting tool permissions partway through a session.&lt;/li&gt;
&lt;li&gt;Reallocating a token budget after a planning step.&lt;/li&gt;
&lt;li&gt;Injecting environment context (the user just switched repos, a long-running job finished) without restarting the whole conversation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For long-running agentic workflows, this single change is more useful than it sounds.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Opus 4.8 Compares to the Field
&lt;/h2&gt;

&lt;p&gt;A short read on where 4.8 sits today:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vs. GPT-5.5:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opus 4.8 leads on SWE-bench Pro (69.2% vs 58.6%) and on GDPval-AA ELO by roughly 121 points.&lt;/li&gt;
&lt;li&gt;GPT-5.5 still leads Terminal-Bench 2.1 (78.2% vs 74.6%).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;vs. Gemini 3.1 Pro:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opus 4.8 leads on SWE-bench variants and long-context retrieval.&lt;/li&gt;
&lt;li&gt;Gemini 3.1 Pro leads on GPQA Diamond (94.3% vs 93.6%) and on several multilingual tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read those numbers as "Opus 4.8 is the strongest agentic coding model right now, but the multilingual and terminal-harness wins are not universal."&lt;/p&gt;




&lt;h2&gt;
  
  
  Honest Assessment: Strengths and Limitations
&lt;/h2&gt;

&lt;p&gt;Opus 4.8 is the most useful coding model Anthropic has shipped, but it is worth going in with calibrated expectations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it shines:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agentic coding gains are real. The SWE-bench Pro lead over GPT-5.5 is large enough to matter on real workloads.&lt;/li&gt;
&lt;li&gt;The honesty improvements (four-fold drop in unreported flaws, zero rate on uncritical reporting, ten-fold drop in overconfidence) translate directly into less time spent double-checking the agent.&lt;/li&gt;
&lt;li&gt;Dynamic Workflows is a genuine shift, not a gimmick. The Bun port is the kind of result that would have been a quarter of work and is now eleven days.&lt;/li&gt;
&lt;li&gt;Effort control as a first-class parameter is the right primitive for cost-aware agent design.&lt;/li&gt;
&lt;li&gt;Fast mode at roughly one-third the previous price unlocks latency-sensitive workloads that were borderline before.&lt;/li&gt;
&lt;li&gt;Same pricing as 4.7 makes the upgrade decision easy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where to be careful:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prompt-injection robustness regressed (Gray Swan ~9.6% vs 6.0%). If you handle untrusted content, audit your sandbox before upgrading.&lt;/li&gt;
&lt;li&gt;Terminal-Bench 2.1 still trails GPT-5.5. If your workload is shell-heavy, benchmark both.&lt;/li&gt;
&lt;li&gt;Multilingual tasks remain a relative weakness. Gemini 3.1 Pro and GPT-5.5 win in several languages.&lt;/li&gt;
&lt;li&gt;Dynamic Workflows can burn tokens fast. Budget carefully or you will discover the cost on your invoice.&lt;/li&gt;
&lt;li&gt;Vending-Bench 2 regressed, hinting at potential issues with highly structured, multi-step transactional interactions. Worth testing if that is your domain.&lt;/li&gt;
&lt;li&gt;Pipelines tightly tuned to 4.7 prompts will need re-validation. The honesty improvements change how the model communicates uncertainty, which can ripple through downstream parsing.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When to Upgrade and When to Wait
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Upgrade from Opus 4.7 if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You run agentic coding workflows and want the honesty improvements.&lt;/li&gt;
&lt;li&gt;Long-context retrieval is core to your product (the GraphWalks delta is the biggest gain in the release).&lt;/li&gt;
&lt;li&gt;You have been hitting silent failures or overconfident outputs.&lt;/li&gt;
&lt;li&gt;You want fast mode at the new lower price.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stay on Opus 4.7 if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your production pipeline is meticulously prompt-tuned to 4.7 and you do not have a re-validation window.&lt;/li&gt;
&lt;li&gt;You rely on the GPQA Diamond delta at the top of the curve.&lt;/li&gt;
&lt;li&gt;You ingest untrusted external content and cannot tighten sandboxing right now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A safe default migration path: switch the model ID, leave effort at &lt;code&gt;high&lt;/code&gt;, validate a representative sample of tasks, then experiment with &lt;code&gt;xhigh&lt;/code&gt; for the hardest workloads.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Learn Next
&lt;/h2&gt;

&lt;p&gt;A few directions worth exploring once you have Opus 4.8 running:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effort tuning per workload&lt;/strong&gt;: profile token spend at each tier on real traffic. The right tier is almost never the same across your app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Workflows playbooks&lt;/strong&gt;: build templates for codebase audits, migrations, and dead-code sweeps. The reusable bit is the workflow shape, not the prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mid-task system messages&lt;/strong&gt;: refactor your long-horizon agents to use the new in-array &lt;code&gt;system&lt;/code&gt; entries instead of restarting threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mythos preview&lt;/strong&gt;: Anthropic has hinted that Mythos-class models will reach general availability in the coming weeks, with the same same-price upgrade pattern. Worth tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheaper-with-Opus-capability tier&lt;/strong&gt;: Anthropic also signaled cheaper models with Opus-level capability are in the works, which will reshape which tier you run by default.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anthropic's documentation, the Claude API release notes, and the model card for Opus 4.8 are the best primary sources for any of this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Opus 4.8 is not a rebrand and it is not a victory lap. It is a focused release that pushes on the parts of agentic coding that actually slow teams down: silent failures, overconfident summaries, single-thread workflows, and a coarse effort model. The benchmark wins are real, but the more durable shift is structural. Effort controls give you a cost dial. Dynamic Workflows give you a way to run multi-day jobs. The honesty improvements give you a model you can trust to flag its own mistakes.&lt;/p&gt;

&lt;p&gt;The 41-day cycle from 4.7 to 4.8, the Mythos hints, and the cheaper-fast-mode pricing together signal that Anthropic is racing. That is good for everyone building on top of these models, but it also means the right play is to upgrade incrementally, measure what changed, and keep your prompts and sandboxes loose enough to absorb the next jump.&lt;/p&gt;

&lt;p&gt;If you are building agents right now, switch the model ID, leave effort at high, test your hardest workloads at xhigh, and try one Dynamic Workflow on something you have been putting off. That is enough to see why this release matters.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>opus</category>
      <category>anthropic</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building AI Agents That Actually Remember: Memory Systems Explained</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Thu, 28 May 2026 14:39:46 +0000</pubDate>
      <link>https://dev.to/arindam_1729/building-ai-agents-that-actually-remember-memory-systems-explained-4078</link>
      <guid>https://dev.to/arindam_1729/building-ai-agents-that-actually-remember-memory-systems-explained-4078</guid>
      <description>&lt;p&gt;You built an AI agent. It calls tools, plans multi-step workflows, and the first time you run it, the demo feels magical. Then you run it again the next day, and it greets you like a stranger. Same clarifying questions. Same mistakes. Same steps reconstructed from scratch.&lt;/p&gt;

&lt;p&gt;That is not a tooling problem. That is a memory problem.&lt;/p&gt;

&lt;p&gt;Most agents shipping today are stateless. They execute inside a loop, but they do not accumulate knowledge across runs. Every session starts at zero, which means every improvement they appeared to make last time is gone. If agents are going to automate real work, they have to get better the longer you use them. That only happens with memory, and not just stored data, but structured, evolving memory that compresses experience into knowledge.&lt;/p&gt;

&lt;p&gt;In this article, I will break down what memory really means inside an agent, where the standard implementations fall short, how to design memory as a first-class layer in your agent loop, and finally how a system like &lt;strong&gt;Engram&lt;/strong&gt; handles this in practice. By the end, you should have a clear mental model for adding real long-term memory to whatever you are building.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you like Video more, You can watch this:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/hrciMR7e7Fk"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What "Memory" Actually Means in an Agent
&lt;/h2&gt;

&lt;p&gt;When people say "memory" in AI, they usually mean storing chat history and pulling it back later. That is not memory. That is replay.&lt;/p&gt;

&lt;p&gt;An agent already has context during execution. The system prompt, the tools, the intermediate tool calls, the partial outputs, all of it sits inside the model's context window for the duration of a single run. The moment the run ends, that context evaporates.&lt;/p&gt;

&lt;p&gt;The common patch is to dump everything into a vector database, then retrieve the chunks that look semantically similar to the next prompt. This keeps the agent informed, but it does not make it smarter. It is the equivalent of handing someone a transcript of a meeting they never attended and hoping they get up to speed.&lt;/p&gt;

&lt;p&gt;Real memory does something more interesting. It compresses raw experience into reusable knowledge. Humans do not remember entire conversations word for word. We remember conclusions, preferences, and patterns. Agents need the same transformation layer between raw execution and stored memory, or they will keep drowning in their own logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Most Agents Are Built Today
&lt;/h2&gt;

&lt;p&gt;The default agent loop looks roughly like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user gives the agent a task.&lt;/li&gt;
&lt;li&gt;The agent plans a sequence of steps.&lt;/li&gt;
&lt;li&gt;It calls tools, observes results, and produces an output.&lt;/li&gt;
&lt;li&gt;The whole transcript is dumped into a database, often a vector store.&lt;/li&gt;
&lt;li&gt;On the next run, similar chunks are retrieved and injected back into the prompt.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At a glance, this feels like memory. In practice it builds a system that can &lt;strong&gt;recall&lt;/strong&gt; but cannot &lt;strong&gt;learn&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The agent never refines what it knows. It never resolves contradictions. It never updates outdated information. It just accumulates. Over time, the store fills with multiple versions of the same idea, conflicting preferences, and abandoned half-thoughts. Retrieval gets noisier, irrelevant context starts crowding the prompt, token usage climbs, and accuracy drops.&lt;/p&gt;

&lt;p&gt;This is the reason so many agents feel stuck at the same level no matter how many sessions you put through them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Missing Piece: A Learning Loop
&lt;/h2&gt;

&lt;p&gt;The gap is a learning step between execution and storage.&lt;/p&gt;

&lt;p&gt;Most loops look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input → plan → execute → store → end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A real long-term-memory loop should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input → plan → execute → learn → update memory → next run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That learning step is where transformation happens. Instead of saving raw logs, the system pulls out structured insights and writes those. If a user says they prefer Postgres over MySQL, that is a stable preference, not a line buried in a chat log. If an agent tried three approaches and only one worked, the successful path is a reusable strategy, not noise mixed in with two failures.&lt;/p&gt;

&lt;p&gt;Without this step, the agent keeps rediscovering the same things on every run, and you pay for it in tokens, latency, and user trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Types of Memory Inside an Agent
&lt;/h2&gt;

&lt;p&gt;It helps to split memory into layers, the same way cognitive science does. Most current systems collapse all three into one bucket, which is exactly why they get confused.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Episodic memory&lt;/strong&gt;: events. Tool calls, inputs, outputs, failures, timestamps. Useful for traceability and debugging, but rarely the right thing to inject back into a prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic memory&lt;/strong&gt;: distilled knowledge. Preferences, facts, constraints, decisions. This is what the agent should actually carry across sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procedural memory&lt;/strong&gt;: how to do things. Sequences of steps that worked before. This is where agents start becoming efficient, because they can reuse solutions instead of recomputing them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good memory system treats these differently. Episodes get logged and mostly left alone. Semantic facts get reconciled and updated in place. Procedures get versioned, scored, and promoted when they keep working.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Real Memory System Needs
&lt;/h2&gt;

&lt;p&gt;A working memory layer for agents needs three core operations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extraction&lt;/strong&gt;: take raw input and decide what is worth remembering. Most of what an agent sees is noise. Extraction is the filter that separates a durable fact ("user is on macOS Sonoma, prefers pnpm") from disposable chatter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliation&lt;/strong&gt;: compare new information with what already exists. Update when the facts have changed. Resolve when they conflict. Merge when they are redundant. This is the step that keeps memory clean instead of letting it sprawl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval&lt;/strong&gt;: when the agent runs again, hand it the relevant pieces, not the whole archive. The goal is precision, not volume. A 200-token answer with the right three facts beats a 4,000-token dump every time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This pipeline is what turns memory into something the agent can rely on instead of something it has to sift through every turn.&lt;/p&gt;




&lt;h2&gt;
  
  
  How This Changes Agent Behavior
&lt;/h2&gt;

&lt;p&gt;Once a memory layer like this is in place, the agent's behavior changes in ways the user actually notices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It stops asking the same clarifying questions because it already has the answers.&lt;/li&gt;
&lt;li&gt;It avoids paths it has already tried and failed on.&lt;/li&gt;
&lt;li&gt;It adapts to the user because preferences are stored and continuously updated.&lt;/li&gt;
&lt;li&gt;It gets faster because it reuses successful strategies instead of recomputing them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point the agent stops being a pure execution engine and starts being something closer to an accumulating knowledge system. That is the line between "impressive demo" and "tool I actually use every day."&lt;/p&gt;




&lt;h2&gt;
  
  
  Engram: A Memory System for Agents
&lt;/h2&gt;

&lt;p&gt;This brings us to &lt;strong&gt;Engram&lt;/strong&gt;, an open-source memory layer designed to sit alongside your agent rather than inside it. The project bills itself as "persistent cognitive memory for AI agents" and is built around exactly the extract → reconcile → retrieve pipeline above.&lt;/p&gt;

&lt;p&gt;Here is what makes Engram worth a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory pipeline, not a bucket&lt;/strong&gt;: incoming data flows through an extraction step that classifies items as facts, preferences, events, or decisions and assigns an importance score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliation built in&lt;/strong&gt;: new memories are checked against existing ones. Duplicates are merged, conflicts are resolved, and stale entries get pruned instead of piling up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dream Cycle&lt;/strong&gt;: a background consolidation job that runs on a schedule (the docs describe a nightly cadence). It refreshes scores, dedupes, extracts patterns across memories, and prunes things that have gone stale. The biological analogy is not a coincidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensemble retrieval&lt;/strong&gt;: multiple embedding models are queried in parallel and combined with Reciprocal Rank Fusion. Recency is weighted so fresh context wins ties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory pools&lt;/strong&gt;: shared memory spaces with access control, so multiple agents can read and write into the same knowledge base without trampling each other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open and self-hostable&lt;/strong&gt;: Apache 2.0 licensed, runs locally on Apple Silicon or CUDA, with an optional hybrid mode that mixes in cloud embeddings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Engram exposes itself through a TypeScript SDK, a REST API, and an MCP server, which means it slots into Claude Desktop, Cursor, Windsurf, and anything else that speaks the Model Context Protocol.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installing Engram
&lt;/h2&gt;

&lt;p&gt;The Python core is a single pip install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;engram-core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional extras cover the server, the MCP integration, embedding backends, or the full bundle. For the TypeScript SDK, install the client package alongside whatever agent framework you are already using.&lt;/p&gt;

&lt;p&gt;The self-hosted version of openengram.ai ships a setup wizard that walks you through account creation and model configuration, and all features unlock locally at no cost. If you want to start with the cloud-hosted control plane, you grab an API key (&lt;code&gt;ek_...&lt;/code&gt;) and point the SDK at it.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Minimal Code Walkthrough
&lt;/h2&gt;

&lt;p&gt;Here is the smallest end-to-end example using the Python SDK:&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;from&lt;/span&gt; &lt;span class="n"&gt;engram&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Memory&lt;/span&gt;

&lt;span class="n"&gt;mem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User prefers Python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preference&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;importance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Project uses Postgres, not MySQL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;importance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;programming language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;store&lt;/code&gt; is the extraction entry point. You tag each memory with a type and an importance score so the consolidation pass can reason about it later. &lt;code&gt;search&lt;/code&gt; runs full-text and semantic retrieval. &lt;code&gt;recall&lt;/code&gt; pulls the top-N most relevant memories for prompt injection.&lt;/p&gt;

&lt;p&gt;The TypeScript flavor is just as light:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Engram&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="s1"&gt;@engram/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;engram&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Engram&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ek_...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;engram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User prefers dark mode&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;memories&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;engram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UI preferences&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both SDKs share the same mental model: write through &lt;code&gt;remember&lt;/code&gt; / &lt;code&gt;store&lt;/code&gt;, read through &lt;code&gt;recall&lt;/code&gt; / &lt;code&gt;search&lt;/code&gt;, and let the consolidation pipeline keep the underlying store clean in the background.&lt;/p&gt;

&lt;p&gt;You can also link memories explicitly to build a small knowledge graph the agent can walk:&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="n"&gt;bug_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Login fails on Safari&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error_fix&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;importance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fix_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Added WebKit prefix to CSS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error_fix&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bug_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fix_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;caused_by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bug_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;link&lt;/code&gt; call is what turns a flat collection of facts into procedural memory the agent can actually follow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project 1: Give a Developer Agent a Real Long-Term Memory
&lt;/h2&gt;

&lt;p&gt;Let us put this together with a concrete scenario. You are building a developer agent that helps scaffold and maintain a project. Without memory, every new session restarts the same conversation about your stack.&lt;/p&gt;

&lt;p&gt;Bootstrap a tiny project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;agent-with-memory &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;agent-with-memory
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;engram-core openai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wire memory into a basic loop:&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;from&lt;/span&gt; &lt;span class="n"&gt;engram&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Memory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;mem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;role&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;system&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Known about the user:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="si"&gt;}&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;

    &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;importance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;importance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Set up a new Node service. I prefer Postgres and pnpm.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Add a users table to the project.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the first call, the agent has nothing to recall, so it answers from scratch and writes two events to memory. On the second call, &lt;code&gt;mem.context()&lt;/code&gt; returns the relevant prior decisions (Postgres, pnpm) and injects them into the system prompt. The agent never has to ask "what package manager do you use" again, and you never have to repeat yourself.&lt;/p&gt;

&lt;p&gt;If you then say "actually, switch this project to Bun," Engram's reconciliation step updates the existing preference rather than appending a contradicting one. That is the difference between a memory system and a log.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project 2: Wire Engram Into Your Coding Agent Over MCP
&lt;/h2&gt;

&lt;p&gt;The second project shows how to plug Engram into an existing coding agent without writing client code at all. Most modern coding agents (Claude Desktop, Cursor, Windsurf, the Antigravity CLI, and others) speak MCP, and Engram ships an MCP server out of the box.&lt;/p&gt;

&lt;p&gt;Start the MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"engram-core[mcp]"&lt;/span&gt;
engram mcp serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add it to your agent's MCP config. For Claude Desktop, edit &lt;code&gt;claude_desktop_config.json&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;"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;"engram"&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;"engram"&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;"mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serve"&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;Restart the agent. From inside any session you can now ask things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Remember that this project uses Drizzle ORM, not Prisma.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What have I told you about my testing setup?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls Engram's MCP tools to write and read memories, and the consolidation loop keeps the store tidy in the background. The same memory pool is now visible to every MCP-aware agent you use, which is the part most people underestimate the first time they try it.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Think About Memory While Building Agents
&lt;/h2&gt;

&lt;p&gt;When you sit down to design an agent, the first question is usually "which model?" or "which tools?" That is the wrong starting point. The first question should be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does this agent need to remember, and how should that memory evolve?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Decide what qualifies as durable knowledge for your domain. Decide what should never be stored (raw PII, transient state, things that age out fast). Decide how updates and conflicts are resolved. Then design your loop so that every execution contributes back to that memory, not just consumes from it.&lt;/p&gt;

&lt;p&gt;A few practical heuristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Store conclusions, not transcripts.&lt;/strong&gt; A summarized decision is worth ten chat logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score importance at write time.&lt;/strong&gt; Future-you needs a signal for what to keep when the store gets crowded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconcile, do not append.&lt;/strong&gt; When the same fact shows up twice, the system should update, not duplicate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve narrowly.&lt;/strong&gt; A small, precise context wins over a giant relevant-ish blob.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is what turns a collection of tools into a system that actually improves over time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Honest Assessment: Strengths and Limitations
&lt;/h2&gt;

&lt;p&gt;Engram is one of the most thoughtful entries in the agent-memory space right now, but it is worth going in with calibrated expectations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it shines:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The extract → reconcile → retrieve pipeline matches the way memory should work, not just the way it is easiest to ship.&lt;/li&gt;
&lt;li&gt;The Dream Cycle is the right idea. Background consolidation is what keeps memory stores from rotting over weeks of use.&lt;/li&gt;
&lt;li&gt;Ensemble retrieval with RRF is a meaningful step up from single-model vector search. Recall stays high even when the query phrasing drifts from how the memory was originally written.&lt;/li&gt;
&lt;li&gt;MCP support means it works with the agent you are already using today, not just a bespoke SDK.&lt;/li&gt;
&lt;li&gt;Apache 2.0 and self-hostable. Your memories live where you want them to live.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where to be careful:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extraction is LLM-driven, which means it can occasionally classify the wrong thing as a durable fact. Importance scoring helps, but you should still spot-check what is being written.&lt;/li&gt;
&lt;li&gt;"Memory" is only as good as your write discipline. If you treat it as a dump-everything store, you will recreate the noisy-vector-DB problem inside a nicer wrapper.&lt;/li&gt;
&lt;li&gt;The ecosystem around agent memory is moving fast, and Engram is one of several real implementations (some Go, some Rust, some Python). Pick the one whose architecture and license match your deployment, and expect interfaces to keep evolving for the next year.&lt;/li&gt;
&lt;li&gt;Hybrid cloud mode is convenient but read the data-handling policy if you are working with sensitive content. Self-hosting is the safer default for regulated workloads.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What to Learn Next
&lt;/h2&gt;

&lt;p&gt;Once you have a memory layer wired in, there are a few directions worth exploring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory pools&lt;/strong&gt;: share a single store across multiple agents (a researcher, a writer, a reviewer) and watch them coordinate without you writing any glue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procedural memory&lt;/strong&gt;: start storing successful tool-call sequences as reusable strategies, not just facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eval your memory&lt;/strong&gt;: write tests that check whether your agent remembers the right things across sessions. Memory regressions are real and they are easy to miss without a harness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP everywhere&lt;/strong&gt;: once memory is exposed as MCP, every agent you use can read and write into the same brain. That is when things actually get interesting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Engram documentation at &lt;code&gt;engram.to&lt;/code&gt; and &lt;code&gt;openengram.ai&lt;/code&gt; is the best place to go deeper, and the GitHub organizations behind the various implementations are active and worth tracking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Most agents today feel powerful in the moment and forget everything afterward. That is the ceiling on what they can become.&lt;/p&gt;

&lt;p&gt;Memory raises that ceiling. It lets agents accumulate knowledge, refine behavior, and adapt with use instead of resetting every session. Engram is one good implementation of this idea, but the larger shift is architectural. Agents are not just reasoning systems anymore. They are learning systems, and memory is the layer that makes the learning stick.&lt;/p&gt;

&lt;p&gt;If you are building agents right now, focus less on making them smarter inside a single run. Focus on making them better across many runs.&lt;/p&gt;

&lt;p&gt;That is where the real leverage is. Give it a try in your next project and see how quickly the dynamic changes.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>memory</category>
      <category>ai</category>
      <category>rag</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Arindam Majumder </dc:creator>
      <pubDate>Mon, 25 May 2026 19:28:42 +0000</pubDate>
      <link>https://dev.to/arindam_1729/-1d23</link>
      <guid>https://dev.to/arindam_1729/-1d23</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/arindam_1729/antigravity-cli-a-hands-on-guide-to-googles-terminal-coding-agent-5bc7" class="crayons-story__hidden-navigation-link"&gt;Antigravity CLI: A Hands-On Guide to Google's Terminal Coding Agent&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/arindam_1729" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F965723%2F8c3a1bb4-eb47-4302-a280-09eedb8bc785.png" alt="arindam_1729 profile" class="crayons-avatar__image" width="800" height="678"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/arindam_1729" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Arindam Majumder 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Arindam Majumder 
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png" width="166" height="102"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3720002" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/arindam_1729" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F965723%2F8c3a1bb4-eb47-4302-a280-09eedb8bc785.png" class="crayons-avatar__image" alt="" width="800" height="678"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Arindam Majumder &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/arindam_1729/antigravity-cli-a-hands-on-guide-to-googles-terminal-coding-agent-5bc7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/arindam_1729/antigravity-cli-a-hands-on-guide-to-googles-terminal-coding-agent-5bc7" id="article-link-3720002"&gt;
          Antigravity CLI: A Hands-On Guide to Google's Terminal Coding Agent
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/antigravity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;antigravity&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/arindam_1729/antigravity-cli-a-hands-on-guide-to-googles-terminal-coding-agent-5bc7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;29&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/arindam_1729/antigravity-cli-a-hands-on-guide-to-googles-terminal-coding-agent-5bc7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              4&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            8 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
  </channel>
</rss>
