<?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: eleonorarocchi</title>
    <description>The latest articles on DEV Community by eleonorarocchi (@eleonorarocchi).</description>
    <link>https://dev.to/eleonorarocchi</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%2F886966%2Fe7384b4e-0bff-4739-bd9a-a796b6ef7110.png</url>
      <title>DEV Community: eleonorarocchi</title>
      <link>https://dev.to/eleonorarocchi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eleonorarocchi"/>
    <language>en</language>
    <item>
      <title>How I Use Codex to Build Applications Without Losing Control</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Fri, 31 Jul 2026 05:19:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/how-i-use-codex-to-build-applications-without-losing-control-18l7</link>
      <guid>https://dev.to/eleonorarocchi/how-i-use-codex-to-build-applications-without-losing-control-18l7</guid>
      <description>&lt;p&gt;In 2026, there is a great deal of discussion around &lt;strong&gt;Agentic Coding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every week, a new framework, orchestrator, or multi-agent system appears. To anyone unfamiliar with these concepts, it may seem as though developing with AI requires an infrastructure that is almost more complex than the application itself.&lt;/p&gt;

&lt;p&gt;This perspective can discourage both beginners and more experienced developers who are still hesitant about using AI.&lt;/p&gt;

&lt;p&gt;A few days ago, I watched &lt;strong&gt;Cole Medin's&lt;/strong&gt; video, &lt;a href="https://www.youtube.com/watch?v=goOZSXmrYQ4" rel="noopener noreferrer"&gt;&lt;em&gt;My COMPLETE Agentic Coding Workflow to Build Anything (No Fluff or Overengineering)&lt;/em&gt;&lt;/a&gt;, in which he gives a very practical demonstration of how he organizes development with Claude Code.&lt;/p&gt;

&lt;p&gt;As I watched it, I realized that the real value of the video was not Claude, but the method. I therefore decided to run an experiment: apply the same principles to Codex, adapting the structure to its conventions.&lt;/p&gt;

&lt;p&gt;This article describes that port and what I learned during the process.&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI Layer in the Original Workflow
&lt;/h2&gt;

&lt;p&gt;In the original workflow, Cole defines an &lt;strong&gt;AI Layer&lt;/strong&gt; as the set of resources stored in the repository that help the coding agent understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what it needs to build;&lt;/li&gt;
&lt;li&gt;how it should build it;&lt;/li&gt;
&lt;li&gt;which workflows it should follow;&lt;/li&gt;
&lt;li&gt;which information it should consult depending on the task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layer includes the PRD, global rules, reference documentation, commands, and any relevant Skills.&lt;/p&gt;

&lt;p&gt;One particularly important detail is the distinction between &lt;strong&gt;commands&lt;/strong&gt; and &lt;strong&gt;Skills&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In Cole's project, the main workflows are Markdown files stored in the &lt;code&gt;.claude/commands/&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/
└── commands/
    ├── commit.md
    ├── create-prd.md
    ├── create-rules.md
    ├── execute.md
    ├── init-project.md
    ├── plan-feature.md
    └── prime.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cole explains that, in Claude Code, commands and Skills have become technically very similar concepts. However, he continues to distinguish between them from an operational perspective.&lt;/p&gt;

&lt;p&gt;A command is a workflow that the user explicitly chooses to start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/prime
/create-prd
/plan-feature
/execute
/commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Skill, on the other hand, represents a capability or a set of instructions that the agent can use when the context requires it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands and Skills in Codex
&lt;/h2&gt;

&lt;p&gt;Cole's distinction is particularly useful for the port because slash commands and Skills are also different concepts in Codex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slash commands&lt;/strong&gt; are actions that can be invoked from the interface using &lt;code&gt;/&lt;/code&gt;. Many are built-in commands that change the mode or state of the session, although the list may also include enabled Skills and custom prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills&lt;/strong&gt;, by contrast, are reusable workflows organized into directories containing a &lt;code&gt;SKILL.md&lt;/code&gt; file. At a minimum, this file specifies the Skill's name, description, and operating instructions.&lt;/p&gt;

&lt;p&gt;Codex initially loads only the Skill's metadata and reads the full instructions when it decides to use it. This mechanism prevents unnecessary use of the context window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Porting the Workflow to Codex
&lt;/h2&gt;

&lt;p&gt;To bring the methodology to Codex, I converted the Claude Code Markdown commands into Codex Skills while preserving their semantics as &lt;strong&gt;workflows explicitly started by the user&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The resulting structure looks 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;.agents/
└── skills/
    ├── agent-browser/
    │   └── SKILL.md
    ├── commit/
    │   └── SKILL.md
    ├── create-prd/
    │   └── SKILL.md
    ├── create-rules/
    │   └── SKILL.md
    ├── execute/
    │   └── SKILL.md
    ├── init-project/
    │   └── SKILL.md
    ├── plan-feature/
    │   └── SKILL.md
    └── prime/
        └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To preserve the semantics of user-initiated workflows, it is possible to disable implicit invocation for Skills that we do not want Codex to select autonomously.&lt;/p&gt;

&lt;p&gt;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;prime/
├── SKILL.md
└── agents/
    └── openai.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;openai.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allow_implicit_invocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents Codex from implicitly activating &lt;code&gt;prime&lt;/code&gt;, &lt;code&gt;execute&lt;/code&gt;, or &lt;code&gt;commit&lt;/code&gt; based on the prompt. The Skills must be invoked explicitly, 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;$create-prd
$create-rules
$prime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this point onward, whenever I refer to &lt;code&gt;$create-prd&lt;/code&gt;, &lt;code&gt;$create-rules&lt;/code&gt;, &lt;code&gt;$prime&lt;/code&gt;, &lt;code&gt;$plan-feature&lt;/code&gt;, &lt;code&gt;$execute&lt;/code&gt;, and &lt;code&gt;$commit&lt;/code&gt;, I mean the custom Skills created for my port, not features preinstalled in Codex.&lt;/p&gt;

&lt;h2&gt;
  
  
  From &lt;code&gt;CLAUDE-template.md&lt;/code&gt; to &lt;code&gt;AGENTS.md&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Converting the commands was not the only necessary change.&lt;/p&gt;

&lt;p&gt;The original repository included a &lt;code&gt;CLAUDE-template.md&lt;/code&gt; file, which served as the basis for the global instructions provided to Claude. In the port, I transformed it into an &lt;code&gt;AGENTS.md&lt;/code&gt; file at the root of the project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; is the native mechanism through which Codex receives persistent instructions and context. At the beginning of a session, Codex builds an instruction chain: it starts at the repository root and moves down to the current working directory, loading any &lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;AGENTS.override.md&lt;/code&gt; files it encounters along the way. Instructions defined deeper in the directory tree can supplement or replace more general ones.&lt;/p&gt;

&lt;p&gt;Persistent instructions and Skills therefore have different responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt; defines how Codex should work within the repository;&lt;/li&gt;
&lt;li&gt;Skills describe scoped workflows such as &lt;code&gt;prime&lt;/code&gt;, &lt;code&gt;create-prd&lt;/code&gt;, &lt;code&gt;plan-feature&lt;/code&gt;, &lt;code&gt;execute&lt;/code&gt;, and &lt;code&gt;commit&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Specialized documentation can live in separate files, provided that &lt;code&gt;AGENTS.md&lt;/code&gt;, a Skill, or a plan clearly specifies when it should be consulted.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Experiment: A Todo List
&lt;/h2&gt;

&lt;p&gt;Once I had finished reclassifying the files, I still needed to verify whether the method actually worked with Codex.&lt;/p&gt;

&lt;p&gt;To focus on the process rather than product complexity, I deliberately chose a simple application: a personal todo list.&lt;/p&gt;

&lt;p&gt;I launched Codex in the folder containing the base files and gave it a brief similar to this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to create a simple todo list application that allows me to add items, view the list, delete items, and mark them as completed.&lt;/p&gt;

&lt;p&gt;I do not need authentication. I would like to use Next.js and deploy the application to Vercel for personal use.&lt;/p&gt;

&lt;p&gt;I would like your recommendations regarding the architecture. I would also like a subagent to research best practices for this type of dashboard.&lt;/p&gt;

&lt;p&gt;Once the research is complete, ask me all the questions necessary to clarify even the smallest product details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Codex began asking me questions until the main open points had been clarified.&lt;/p&gt;

&lt;p&gt;The goal of this phase is not merely to describe what we expect, but to eliminate as many assumptions as possible. Once the requirements were sufficiently clear, I invoked the following Skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$create-prd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  From the Brief to the PRD
&lt;/h2&gt;

&lt;p&gt;The resulting &lt;code&gt;PRD.md&lt;/code&gt; file represents what we want to build. In my case, it contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the product objective;&lt;/li&gt;
&lt;li&gt;primary users;&lt;/li&gt;
&lt;li&gt;use cases;&lt;/li&gt;
&lt;li&gt;MVP features;&lt;/li&gt;
&lt;li&gt;out-of-scope features;&lt;/li&gt;
&lt;li&gt;the technology stack;&lt;/li&gt;
&lt;li&gt;architectural constraints;&lt;/li&gt;
&lt;li&gt;non-functional requirements;&lt;/li&gt;
&lt;li&gt;general success criteria;&lt;/li&gt;
&lt;li&gt;implementation phases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The division into phases is particularly important. It makes little sense to ask Codex to implement the entire product in a single session.&lt;/p&gt;

&lt;p&gt;Each phase should be small enough to be planned, implemented, and validated separately. This makes the process easier to verify, while the PRD effectively also becomes a roadmap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Project Rules
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, the repository already contained a base &lt;code&gt;AGENTS.md&lt;/code&gt; file derived from the previous &lt;code&gt;CLAUDE-template.md&lt;/code&gt;. This file includes the initial structure and general guidelines that I want to preserve across every project.&lt;/p&gt;

&lt;p&gt;After defining what needed to be built, I invoked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$create-rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my workflow, this Skill did not create &lt;code&gt;AGENTS.md&lt;/code&gt; from scratch. It analyzed the PRD and the repository, then expanded the existing file with project-specific information, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the technology stack;&lt;/li&gt;
&lt;li&gt;development, build, and test commands;&lt;/li&gt;
&lt;li&gt;the directory structure;&lt;/li&gt;
&lt;li&gt;conventions;&lt;/li&gt;
&lt;li&gt;architectural decisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is important for the final result to remain concise enough. &lt;code&gt;AGENTS.md&lt;/code&gt; should contain instructions that are generally applicable to the repository. Specialized documentation can live in separate files, provided that &lt;code&gt;AGENTS.md&lt;/code&gt;, a Skill, or a plan clearly indicates when it should be consulted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Context Reset: &lt;code&gt;$prime&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Once the initial project definition was complete, I opened a new session and invoked:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This is the first intentional context reset.&lt;/strong&gt; The new session does not inherit the long initial conversation. Instead, it reconstructs the project through &lt;code&gt;PRD.md&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;, the repository, and the Git history.&lt;/p&gt;

&lt;p&gt;When I open the new session, Codex has already loaded the applicable instructions contained in &lt;code&gt;AGENTS.md&lt;/code&gt;. The &lt;code&gt;$prime&lt;/code&gt; Skill then completes its mental model by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reading the PRD;&lt;/li&gt;
&lt;li&gt;exploring the repository;&lt;/li&gt;
&lt;li&gt;identifying the entry points;&lt;/li&gt;
&lt;li&gt;checking the Git status;&lt;/li&gt;
&lt;li&gt;reviewing recent commits;&lt;/li&gt;
&lt;li&gt;determining which phases have already been completed;&lt;/li&gt;
&lt;li&gt;identifying the next objective.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end, Codex provides a summary of its understanding of the project.&lt;/p&gt;

&lt;p&gt;This phase should be reviewed carefully. If the agent's mental model is incorrect, it is best to intervene before moving on to implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The PIV Cycle
&lt;/h2&gt;

&lt;p&gt;At this point, we reach the core of the &lt;strong&gt;PIV&lt;/strong&gt; cycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plan → Implement → Validate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each phase of the PRD goes through these three steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plan: Turning a Phase into a Plan
&lt;/h2&gt;

&lt;p&gt;I selected the first phase identified by Codex and invoked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$plan-feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This phase does not produce any code yet. Its purpose is to turn a PRD feature into a detailed technical plan.&lt;/p&gt;

&lt;p&gt;Codex analyzes the repository, consults the relevant documentation, and defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the objective of the feature;&lt;/li&gt;
&lt;li&gt;the current state of the project;&lt;/li&gt;
&lt;li&gt;architectural decisions;&lt;/li&gt;
&lt;li&gt;the files to create or modify;&lt;/li&gt;
&lt;li&gt;the tasks to perform;&lt;/li&gt;
&lt;li&gt;edge cases;&lt;/li&gt;
&lt;li&gt;the testing and validation strategy;&lt;/li&gt;
&lt;li&gt;the criteria required for the work to be considered complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, &lt;code&gt;$plan-feature&lt;/code&gt; produced a new persistent file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.agents/
└── plans/
    └── implement-todo-dashboard-mvp.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This detail is important: the plan does not remain confined to the conversation but becomes an artifact stored in the repository.&lt;/p&gt;

&lt;p&gt;The document must be complete enough to be executed by a new Codex session that did not participate in the discussion during which the plan was prepared.&lt;/p&gt;

&lt;p&gt;Before proceeding, I reviewed the file to verify that it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;was consistent with the PRD;&lt;/li&gt;
&lt;li&gt;did not expand the scope;&lt;/li&gt;
&lt;li&gt;contained sufficiently clear tasks;&lt;/li&gt;
&lt;li&gt;defined genuinely verifiable completion criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implement: Executing the Plan in a New Context
&lt;/h2&gt;

&lt;p&gt;Once the plan had been approved, I opened a new session dedicated to execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the second intentional context reset.&lt;/strong&gt; The new session does not need to know every question that was asked, every rejected alternative, or the intermediate reasoning that occurred during planning. It only needs the decisions consolidated in the plan and the persistent context stored in the repository.&lt;/p&gt;

&lt;p&gt;I then invoked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$execute .agents/plans/implement-todo-dashboard-mvp.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During this phase, Codex followed the tasks defined in the document, created the necessary files, implemented the todo list dashboard, and added the planned checks.&lt;/p&gt;

&lt;p&gt;The purpose of &lt;code&gt;$execute&lt;/code&gt; is to carry out an already approved plan. If an important unforeseen decision emerges during the work, the agent stops and asks for clarification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate: Verifying the Result
&lt;/h2&gt;

&lt;p&gt;Once implementation is complete, the third phase of the PIV cycle begins: validation.&lt;/p&gt;

&lt;p&gt;Codex runs the checks defined in the plan, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run typecheck
npm run lint
npm run build
npm run &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a web application, however, these checks are not sufficient. The actual behavior of the interface must also be verified.&lt;/p&gt;

&lt;p&gt;In my case, the main scenarios were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding a new item;&lt;/li&gt;
&lt;li&gt;displaying it in the list;&lt;/li&gt;
&lt;li&gt;marking it as completed;&lt;/li&gt;
&lt;li&gt;deleting it;&lt;/li&gt;
&lt;li&gt;reloading the page;&lt;/li&gt;
&lt;li&gt;verifying that the state was persisted correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As in Cole's example, the &lt;code&gt;agent-browser&lt;/code&gt; Skill can be used to automate these flows and test the application as a user would.&lt;/p&gt;

&lt;p&gt;Automated verification does not eliminate the need for human verification. At the end of the process, it is still important to personally test the application's main flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git as Long-Term Memory
&lt;/h2&gt;

&lt;p&gt;After verifying that the feature worked correctly, I invoked:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The Skill standardizes the commit message, describing what was implemented and how it was validated.&lt;/p&gt;

&lt;p&gt;The Git history therefore takes on an additional role: it does not merely preserve code changes but becomes a form of long-term memory for Codex.&lt;/p&gt;

&lt;p&gt;During a future execution of &lt;code&gt;$prime&lt;/code&gt;, the agent can review recent commits to understand how the project has evolved and which parts of the PRD have already been addressed.&lt;/p&gt;

&lt;p&gt;With this methodology, the repository contains several layers of memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PRD.md          → what we want to build
AGENTS.md       → how Codex should work
.agents/plans/  → how to implement individual features
Git history     → what was actually changed
Tests           → what must continue to work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the next feature, a new context is opened, &lt;code&gt;$prime&lt;/code&gt; is run again, and another PIV cycle begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: A Lightweight Method or a Complete Framework?
&lt;/h2&gt;

&lt;p&gt;At this point, a comparison with more structured frameworks such as the &lt;a href="https://docs.bmad-method.org/" rel="noopener noreferrer"&gt;BMAD Method&lt;/a&gt; is inevitable.&lt;/p&gt;

&lt;p&gt;BMAD aims to cover the entire development lifecycle: from initial analysis and product definition to architecture, the breakdown into epics and stories, implementation, and review. To achieve this, it provides specialized agents, guided workflows, intermediate artifacts, and modules dedicated to specific areas.&lt;/p&gt;

&lt;p&gt;The method presented by Cole, and adapted by me for Codex, starts from the opposite choice: use the smallest possible number of components and fully understand the role of each one.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;PRD.md&lt;/code&gt;, an &lt;code&gt;AGENTS.md&lt;/code&gt;, a few persistent plans, and a small number of Skills make up almost the entire system. A small structure is easier to customize and evolve alongside the project.&lt;/p&gt;

&lt;p&gt;To be clear, this does not mean that the workflow is inherently better than BMAD. It simply offers a different trade-off.&lt;/p&gt;

&lt;p&gt;A complete framework may be useful when a standardized process, clearly defined roles, numerous project artifacts, and greater consistency across different people or initiatives are required.&lt;/p&gt;

&lt;p&gt;The lighter approach may be more suitable when the goal is to get started quickly, maintain direct control over the process, and modify each component according to the needs of a specific repository.&lt;/p&gt;

&lt;p&gt;Naturally, simplicity comes at a cost: there is no external framework deciding which documents to produce, which checks to apply, or how to handle every possible scenario. The responsibility for evolving the Skills, &lt;code&gt;AGENTS.md&lt;/code&gt;, tests, and rules remains with the developer.&lt;/p&gt;

&lt;p&gt;Before starting a new project with a coding agent, the question should therefore be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How much structure does this project actually need?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For my experiment, I did not need to adopt the complete process of a framework such as BMAD, even though I knew that BMAD also offered lighter workflows for more limited tasks. I wanted a process that was structured enough to avoid &lt;em&gt;vibe coding&lt;/em&gt;, but simple enough to be understood, modified, and controlled directly.&lt;/p&gt;

&lt;p&gt;And this may be the most important takeaway: using a coding agent without losing control does not necessarily require more automation. Sometimes, all it takes is a small number of clear artifacts, explicit steps, and the discipline not to skip planning and validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;

&lt;p&gt;If you're interested in using the ready-made scaffolding for Codex, you can find it here: &lt;a href="https://github.com/eleonorarocchi/codex-agentic-starter" rel="noopener noreferrer"&gt;https://github.com/eleonorarocchi/codex-agentic-starter&lt;/a&gt;&lt;br&gt;
.. and please give it a star ;-)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>Setting Up a Local AI Coding Agent with Ollama and Aider (part 4)</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Tue, 21 Jul 2026 19:26:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-part-4-4g6n</link>
      <guid>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-part-4-4g6n</guid>
      <description>&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Once the setup with Aider, Ollama, Grafana, and Streamlit was working, I decided to push it a little further.&lt;/p&gt;

&lt;p&gt;The idea was to test a newer model based on a different approach from traditional autoregressive models: DiffusionGemma.&lt;/p&gt;

&lt;p&gt;The model I wanted to try was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;google/diffusiongemma-26B-A4B-it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The naming is interesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;26B = total number of parameters
A4B = approximately 4B active parameters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a Mixture-of-Experts model, but that does not mean it runs like a 4B model.&lt;/p&gt;

&lt;p&gt;When running it locally, you still have to handle a very large model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Did Not Use It with Aider
&lt;/h2&gt;

&lt;p&gt;My main workflow was:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;However, DiffusionGemma was not supported by Ollama in my setup. I therefore changed the goal: instead of using it with Aider, I tested it directly with the dedicated &lt;code&gt;llama.cpp&lt;/code&gt; runner.&lt;/p&gt;

&lt;p&gt;I did not expect it to become part of my daily workflow, but I still wanted to run a technical experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Hugging Face CLI
&lt;/h2&gt;

&lt;p&gt;Inside WSL, I installed the Hugging Face CLI using its dedicated installer:&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;cd&lt;/span&gt; ~
curl &lt;span class="nt"&gt;-LsSf&lt;/span&gt; https://hf.co/cli/install.sh | bash
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I verified the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hf &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Downloading the GGUF Model
&lt;/h2&gt;

&lt;p&gt;I downloaded the Q4_K_M quantization:&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; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/models/diffusiongemma

hf download unsloth/diffusiongemma-26B-A4B-it-GGUF &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--local-dir&lt;/span&gt; ~/models/diffusiongemma &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include&lt;/span&gt; &lt;span class="s2"&gt;"*Q4_K_M*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I checked that the file was present:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ~/models/diffusiongemma &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.gguf"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The download completed successfully, but the file is large: approximately 16 GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Dedicated Runner
&lt;/h2&gt;

&lt;p&gt;To test the model without Ollama, I used the DiffusionGemma branch of &lt;code&gt;llama.cpp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, I installed the required dependencies:&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;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git cmake build-essential
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I cloned the repository and checked out the relevant branch:&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; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/src
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/src

git clone https://github.com/ggml-org/llama.cpp llama.cpp-diffusiongemma
&lt;span class="nb"&gt;cd &lt;/span&gt;llama.cpp-diffusiongemma

git fetch origin pull/24423/head:diffusiongemma
git checkout diffusiongemma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a CPU-only build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmake &lt;span class="nt"&gt;-B&lt;/span&gt; build &lt;span class="nt"&gt;-DGGML_NATIVE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON
cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build &lt;span class="nt"&gt;-j&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--config&lt;/span&gt; Release &lt;span class="nt"&gt;--target&lt;/span&gt; llama-diffusion-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the build:&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; build/bin/llama-diffusion-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the Model
&lt;/h2&gt;

&lt;p&gt;I stored the model path in a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find ~/models/diffusiongemma &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*Q4_K_M*.gguf"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MODEL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I launched the runner:&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;cd&lt;/span&gt; ~/src/llama.cpp-diffusiongemma

./build/bin/llama-diffusion-cli &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MODEL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-ngl&lt;/span&gt; 0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cnv&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; 256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command ran successfully, but on the machine I was using, performance was far too slow for practical use.&lt;/p&gt;

&lt;p&gt;I also tried a lower output limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-diffusion-cli &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MODEL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-ngl&lt;/span&gt; 0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cnv&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And another variant with an explicit thread count:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./build/bin/llama-diffusion-cli &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MODEL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-ngl&lt;/span&gt; 0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cnv&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; 64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bottleneck
&lt;/h2&gt;

&lt;p&gt;My machine has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intel Core i7-1355U
48 GB of RAM
Intel Iris Xe
no dedicated GPU
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The available RAM is enough to load many quantized models, but that does not make them fast enough for interactive use.&lt;/p&gt;

&lt;p&gt;The real bottlenecks are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mobile CPU
memory bandwidth
lack of dedicated VRAM
the higher computational cost of the diffusion architecture
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fact that a model is described as &lt;code&gt;26B-A4B&lt;/code&gt; does not mean it is equivalent to a dense 4B model.&lt;/p&gt;

&lt;p&gt;It only means that a subset of the parameters is activated for each token. The full model is still large, and when running it locally, you still pay the cost in memory usage, I/O, and runtime complexity.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
    </item>
    <item>
      <title>Setting Up a Local AI Coding Agent with Ollama and Aider (part 3)</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Fri, 17 Jul 2026 20:14:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-part-3-23gk</link>
      <guid>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-part-3-23gk</guid>
      <description>&lt;h2&gt;
  
  
  Dashboard
&lt;/h2&gt;

&lt;p&gt;After collecting the metrics in &lt;code&gt;ollama_usage.jsonl&lt;/code&gt;, I wanted a way to visualize them.&lt;/p&gt;

&lt;p&gt;I used two tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Streamlit → quick, operational view
Grafana   → more stable dashboards and long-term monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both read the same data, but in different ways.&lt;/p&gt;

&lt;p&gt;The final architecture looks 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;Aider → proxy on 11435 → ollama_usage.jsonl
                            ├─ Streamlit
                            └─ exporter → Prometheus → Grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Streamlit
&lt;/h2&gt;

&lt;p&gt;Streamlit was the fastest way to build a local user interface.&lt;/p&gt;

&lt;p&gt;Inside WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv ~/.venvs/aider-dashboard
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.venvs/aider-dashboard/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;streamlit pandas streamlit-autorefresh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I created the dashboard:&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;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/aider_usage_dashboard.py &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;'
import json
from pathlib import Path

import pandas as pd
import streamlit as st
from streamlit_autorefresh import st_autorefresh

LOG_PATH = Path.home() / "ollama_usage.jsonl"

st.set_page_config(
    page_title="Aider / Ollama usage dashboard",
    layout="wide",
)

st_autorefresh(interval=5000, key="aider_dashboard_refresh")

st.title("Aider / Ollama usage dashboard")
st.caption("Local statistics: tokens, response times, and generation speed.")

if not LOG_PATH.exists():
    st.warning(f"No file found: {LOG_PATH}")
    st.stop()

rows = []
with LOG_PATH.open("r", encoding="utf-8") as f:
    for line in f:
        line = line.strip()
        if not line:
            continue
        try:
            rows.append(json.loads(line))
        except json.JSONDecodeError:
            pass

if not rows:
    st.warning("The file exists, but it does not contain any valid metrics yet.")
    st.stop()

df = pd.DataFrame(rows)

if "ts" in df.columns:
    df["ts"] = pd.to_datetime(df["ts"], errors="coerce")
    df = df.sort_values("ts")
    df["run"] = range(1, len(df) + 1)
else:
    df["run"] = range(1, len(df) + 1)

numeric_cols = [
    "prompt_tokens",
    "response_tokens",
    "total_tokens",
    "wall_time_s",
    "ollama_total_s",
    "load_s",
    "prompt_eval_s",
    "generation_s",
    "generation_tokens_per_s",
]

for col in numeric_cols:
    if col in df.columns:
        df[col] = pd.to_numeric(df[col], errors="coerce")

total_calls = len(df)
total_tokens = int(df["total_tokens"].sum()) if "total_tokens" in df.columns else 0
avg_time = df["wall_time_s"].mean() if "wall_time_s" in df.columns else None
avg_tps = df["generation_tokens_per_s"].mean() if "generation_tokens_per_s" in df.columns else None

c1, c2, c3, c4 = st.columns(4)

c1.metric("Recorded responses", total_calls)
c2.metric("Total tokens", f"{total_tokens:,}")
c3.metric("Average response time", f"{avg_time:.1f}s" if pd.notna(avg_time) else "n/a")
c4.metric("Average tokens/s", f"{avg_tps:.2f}" if pd.notna(avg_tps) else "n/a")

st.divider()

left, right = st.columns(2)

with left:
    st.subheader("Tokens per response")
    token_cols = [c for c in ["prompt_tokens", "response_tokens", "total_tokens"] if c in df.columns]
    if token_cols:
        st.line_chart(df.set_index("run")[token_cols])

with right:
    st.subheader("Response times")
    time_cols = [c for c in ["wall_time_s", "ollama_total_s", "generation_s", "prompt_eval_s"] if c in df.columns]
    if time_cols:
        st.line_chart(df.set_index("run")[time_cols])

left, right = st.columns(2)

with left:
    st.subheader("Generation speed")
    if "generation_tokens_per_s" in df.columns:
        st.line_chart(df.set_index("run")[["generation_tokens_per_s"]])

with right:
    st.subheader("Input vs output tokens")
    cols = [c for c in ["prompt_tokens", "response_tokens"] if c in df.columns]
    if cols:
        st.bar_chart(df.set_index("run")[cols])

st.divider()

st.subheader("Latest responses")
show_cols = [
    c for c in [
        "ts",
        "model",
        "prompt_tokens",
        "response_tokens",
        "total_tokens",
        "wall_time_s",
        "ollama_total_s",
        "generation_s",
        "generation_tokens_per_s",
        "done_reason",
    ]
    if c in df.columns
]

st.dataframe(
    df[show_cols].tail(50).sort_index(ascending=False),
    use_container_width=True,
)

st.caption(f"Reading data from: {LOG_PATH}")
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.venvs/aider-dashboard/bin/activate
streamlit run ~/aider_usage_dashboard.py &lt;span class="nt"&gt;--server&lt;/span&gt;.address 127.0.0.1 &lt;span class="nt"&gt;--server&lt;/span&gt;.port 8501
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8501
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used this as a quick operational dashboard. Of course, this was only the starting point; I later customized it with all the metrics I actually needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grafana
&lt;/h2&gt;

&lt;p&gt;Grafana, a widely used data visualization and analytics tool, requires a few additional components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exporter → Prometheus → Grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker Desktop was already installed on my Windows PC, but I first had to enable WSL integration from Docker Desktop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Settings → Resources → WSL Integration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, inside WSL, I fixed the Docker permissions:&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;sudo &lt;/span&gt;groupadd docker 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
newgrp docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker version
docker compose version
docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monitoring Directory
&lt;/h2&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; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/monitoring/llm-grafana
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/monitoring/llm-grafana

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; prometheus
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; grafana/provisioning/datasources
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ollama-jsonl-exporter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prometheus Exporter
&lt;/h2&gt;

&lt;p&gt;The exporter reads the JSONL file and exposes Prometheus metrics on port &lt;code&gt;9108&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ollama-jsonl-exporter/Dockerfile &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;DOCKER&lt;/span&gt;&lt;span class="sh"&gt;'
FROM python:3.12-slim
WORKDIR /app
COPY exporter.py /app/exporter.py
ENV LOG_PATH=/data/ollama_usage.jsonl
ENV PORT=9108
EXPOSE 9108
CMD ["python", "/app/exporter.py"]
&lt;/span&gt;&lt;span class="no"&gt;DOCKER
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;exporter.py&lt;/code&gt; file is the component that converts the JSONL data into Prometheus metrics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prometheus
&lt;/h2&gt;

&lt;p&gt;Prometheus is the monitoring engine. It is responsible for collecting and storing metrics such as CPU usage, memory consumption, and application-specific measurements.&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;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; prometheus/prometheus.yml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="sh"&gt;'
global:
  scrape_interval: 5s
  evaluation_interval: 5s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["prometheus:9090"]

  - job_name: "aider-ollama"
    static_configs:
      - targets: ["ollama-jsonl-exporter:9108"]
&lt;/span&gt;&lt;span class="no"&gt;YAML
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Grafana Data Source
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; grafana/provisioning/datasources/prometheus.yml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="sh"&gt;'
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
&lt;/span&gt;&lt;span class="no"&gt;YAML
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;

&lt;p&gt;The working configuration mounts the entire &lt;code&gt;prometheus&lt;/code&gt; directory rather than the individual configuration file.&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;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; docker-compose.yml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="sh"&gt;'
services:
  ollama-jsonl-exporter:
    build:
      context: ./ollama-jsonl-exporter
    container_name: ollama-jsonl-exporter
    restart: unless-stopped
    volumes:
      - &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/ollama_usage.jsonl:/data/ollama_usage.jsonl:ro
    ports:
      - "127.0.0.1:9108:9108"

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus-llm
    restart: unless-stopped
    depends_on:
      - ollama-jsonl-exporter
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=30d"
    volumes:
      - ./prometheus:/etc/prometheus:ro
      - prometheus_data:/prometheus
    ports:
      - "127.0.0.1:9090:9090"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana-llm
    restart: unless-stopped
    depends_on:
      - prometheus
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    ports:
      - "127.0.0.1:3001:3000"

volumes:
  prometheus_data:
  grafana_data:
&lt;/span&gt;&lt;span class="no"&gt;YAML
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start the stack:&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;cd&lt;/span&gt; ~/monitoring/llm-grafana
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose ps
curl http://127.0.0.1:9108/metrics | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 20
curl http://127.0.0.1:9090/-/ready
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grafana is available at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the first login, you need to configure a user account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Grafana Queries
&lt;/h2&gt;

&lt;p&gt;In the Grafana panels, I used &lt;code&gt;Code&lt;/code&gt; mode instead of the visual query builder.&lt;/p&gt;

&lt;p&gt;Recorded responses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum(aider_ollama_calls_total)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum(aider_ollama_tokens_total)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Latest response time:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Tokens per second for the latest response:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;For KPIs, I used &lt;code&gt;Stat&lt;/code&gt; panels, while for trends I used &lt;code&gt;Time series&lt;/code&gt; panels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Daily Workflow
&lt;/h2&gt;

&lt;p&gt;Terminal 1:&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;cd&lt;/span&gt; ~
python3 ~/ollama_usage_proxy.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terminal 2:&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;cd&lt;/span&gt; ~/repos/my-project
aider14stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terminal 3:&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;cd&lt;/span&gt; ~/monitoring/llm-grafana
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terminal 4:&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;source&lt;/span&gt; ~/.venvs/aider-dashboard/bin/activate
streamlit run ~/aider_usage_dashboard.py &lt;span class="nt"&gt;--server&lt;/span&gt;.address 127.0.0.1 &lt;span class="nt"&gt;--server&lt;/span&gt;.port 8501
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, I ended up with two complementary views:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Streamlit → operational debugging
Grafana   → stable monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is still an experimental setup. For a more mature environment, I would probably consolidate everything into a single tool.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
    </item>
    <item>
      <title>Setting Up a Local AI Coding Agent with Ollama and Aider (part 2)</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Tue, 14 Jul 2026 20:48:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-part-2-1ngk</link>
      <guid>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-part-2-1ngk</guid>
      <description>&lt;h2&gt;
  
  
  Metrics
&lt;/h2&gt;

&lt;p&gt;Once I had Aider working with a local Ollama instance, there was still one thing missing: understanding what was actually happening under the hood.&lt;/p&gt;

&lt;p&gt;I wanted to see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how many tokens were being processed&lt;/li&gt;
&lt;li&gt;how long each response took&lt;/li&gt;
&lt;li&gt;how fast text generation was&lt;/li&gt;
&lt;li&gt;whether one model was slower than another&lt;/li&gt;
&lt;li&gt;whether the context window was growing too large&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aider alone didn't provide enough visibility. However, Ollama exposes several useful metrics in the final response returned by its API.&lt;/p&gt;

&lt;p&gt;So I decided to add a small local proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The request flow became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Aider
  ↓
Local proxy on port 11435
  ↓
Ollama on Windows (11434)
  ↓
qwen2.5-coder:14b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy performs two simple tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;forwards every request to Ollama&lt;/li&gt;
&lt;li&gt;stores the execution statistics in a JSONL file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The resulting log file is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/ollama_usage.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Proxy
&lt;/h2&gt;

&lt;p&gt;Inside WSL:&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;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/ollama_usage_proxy.py &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;'
#!/usr/bin/env python3
import json
import time
import urllib.request
from datetime import datetime, timezone
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler

UPSTREAM = "http://127.0.0.1:11434"
LOG_FILE = "/home/xxxxx/ollama_usage.jsonl"

def ns_to_s(value):
    if isinstance(value, (int, float)):
        return value / 1_000_000_000
    return None

def safe_div(a, b):
    if not a or not b:
        return None
    return a / b

class OllamaProxy(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.0"

    def log_message(self, format, *args):
        return

    def do_GET(self):
        self.forward()

    def do_POST(self):
        self.forward()

    def forward(self):
        length = int(self.headers.get("Content-Length", "0") or "0")
        body = self.rfile.read(length) if length else None

        url = UPSTREAM + self.path
        headers = {
            k: v for k, v in self.headers.items()
            if k.lower() not in {
                "host",
                "content-length",
                "connection",
                "accept-encoding",
            }
        }

        request = urllib.request.Request(
            url,
            data=body,
            headers=headers,
            method=self.command,
        )

        started = time.perf_counter()
        final_obj = None

        try:
            with urllib.request.urlopen(request, timeout=None) as response:
                self.send_response(response.status)
                self.send_header(
                    "Content-Type",
                    response.headers.get("Content-Type", "application/json"),
                )
                self.end_headers()

                for line in response:
                    self.wfile.write(line)
                    self.wfile.flush()

                    try:
                        obj = json.loads(line.decode("utf-8"))
                        if obj.get("done") is True:
                            final_obj = obj
                    except Exception:
                        pass

        except Exception as exc:
            self.send_error(502, f"Proxy error: {exc}")
            return

        wall_time_s = time.perf_counter() - started

        if not final_obj:
            return

        prompt_tokens = final_obj.get("prompt_eval_count")
        response_tokens = final_obj.get("eval_count")

        prompt_eval_s = ns_to_s(final_obj.get("prompt_eval_duration"))
        eval_s = ns_to_s(final_obj.get("eval_duration"))
        total_s = ns_to_s(final_obj.get("total_duration"))
        load_s = ns_to_s(final_obj.get("load_duration"))

        row = {
            "ts": datetime.now(timezone.utc).isoformat(),
            "endpoint": self.path,
            "method": self.command,
            "model": final_obj.get("model"),
            "done_reason": final_obj.get("done_reason"),
            "prompt_tokens": prompt_tokens,
            "response_tokens": response_tokens,
            "total_tokens": (prompt_tokens or 0) + (response_tokens or 0),
            "wall_time_s": round(wall_time_s, 3),
            "ollama_total_s": round(total_s, 3) if total_s is not None else None,
            "load_s": round(load_s, 3) if load_s is not None else None,
            "prompt_eval_s": round(prompt_eval_s, 3) if prompt_eval_s is not None else None,
            "generation_s": round(eval_s, 3) if eval_s is not None else None,
            "prompt_tokens_per_s": round(safe_div(prompt_tokens, prompt_eval_s), 2)
            if safe_div(prompt_tokens, prompt_eval_s) else None,
            "generation_tokens_per_s": round(safe_div(response_tokens, eval_s), 2)
            if safe_div(response_tokens, eval_s) else None,
        }

        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(json.dumps(row, ensure_ascii=False) + "&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;")

if __name__ == "__main__":
    server = ThreadingHTTPServer(("127.0.0.1", 11435), OllamaProxy)
    print("Ollama usage proxy listening on http://127.0.0.1:11435")
    print(f"Forwarding requests to {UPSTREAM}")
    print(f"Writing statistics to {LOG_FILE}")
    server.serve_forever()
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then make it executable:&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;chmod&lt;/span&gt; +x ~/ollama_usage_proxy.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starting the Proxy
&lt;/h2&gt;

&lt;p&gt;In a WSL terminal:&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;cd&lt;/span&gt; ~
python3 ~/ollama_usage_proxy.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leave this terminal running while using Aider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Aider Through the Proxy
&lt;/h2&gt;

&lt;p&gt;In a second WSL terminal:&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;cd&lt;/span&gt; ~/repos/my-project
&lt;span class="nv"&gt;OLLAMA_API_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://127.0.0.1:11435 aider &lt;span class="nt"&gt;--model&lt;/span&gt; ollama_chat/qwen2.5-coder:14b &lt;span class="nt"&gt;--no-show-model-warnings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction is important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11434 = Direct connection to Ollama (no metrics)
11435 = Proxy enabled (metrics collected)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inspecting the JSONL Log
&lt;/h2&gt;

&lt;p&gt;After Aider generates a response:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 5 ~/ollama_usage.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make the output easier to read, I installed &lt;code&gt;jq&lt;/code&gt;, a powerful open-source command-line tool for parsing, filtering, formatting, and manipulating JSON data:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&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;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 5 ~/ollama_usage.jsonl | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical log entry looks like this:&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;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qwen2.5-coder:14b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prompt_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;310&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1590&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wall_time_s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;42.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generation_s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;37.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generation_tokens_per_s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating an Alias
&lt;/h2&gt;

&lt;p&gt;To avoid accidentally connecting Aider to the wrong port, I created a shell alias:&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'alias aider14stats="OLLAMA_API_BASE=http://127.0.0.1:11435 aider --model ollama_chat/qwen2.5-coder:14b --no-show-model-warnings"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From that point on, starting Aider was as simple as:&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;cd&lt;/span&gt; ~/repos/my-project
aider14stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Logging should be part of the design from the very beginning.&lt;/p&gt;

&lt;p&gt;Without metrics, a local model may simply &lt;em&gt;feel&lt;/em&gt; slow. With proper measurements, I can understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;how much input I'm sending
how much output I'm receiving
how long each request takes
how many tokens per second are being generated
whether the model was already loaded into memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having access to this information completely changes the way I can evaluate and compare locally hosted LLMs.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>Setting Up a Local AI Coding Agent with Ollama and Aider</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Sat, 11 Jul 2026 13:41:12 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-1jdi</link>
      <guid>https://dev.to/eleonorarocchi/setting-up-a-local-ai-coding-agent-with-ollama-and-aider-1jdi</guid>
      <description>&lt;p&gt;Over the past few months, I've experimented with several workflows for using LLMs in software development. In this article, I describe the local setup I've validated on my own PC: Ollama running on Windows, Aider inside Ubuntu on WSL2, and a code-focused model running entirely on the local machine.&lt;/p&gt;

&lt;p&gt;The machine I used for my first experiment runs Windows 11 with an Intel Core i7-1355U CPU, 48 GiB of RAM, and no dedicated NVIDIA GPU. It's generally a capable machine, but not particularly well suited for AI inference. Because it lacks a dedicated GPU, I had to run the model in CPU-only mode.&lt;/p&gt;

&lt;p&gt;The goal of this setup was to create an environment where both the source code and the data remain entirely on the local machine—far from the cloud-based frontier model approach.&lt;/p&gt;

&lt;p&gt;From an architectural standpoint, I decided to keep Ollama on Windows because I also use the installed models with other Windows applications, and I wanted to avoid maintaining duplicate model installations. Aider, on the other hand, runs inside WSL, where installation and configuration are simpler and the Linux command-line environment is more convenient.&lt;/p&gt;

&lt;p&gt;Ollama remains exposed on the local port 11434. Aider, running inside Ubuntu WSL2, connects to Ollama through the &lt;code&gt;OLLAMA_API_BASE&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;This approach avoids duplicating models inside WSL while keeping development repositories in the Linux filesystem under &lt;code&gt;~/repos&lt;/code&gt;, where Git and other command-line tools work much more naturally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local Setup
&lt;/h2&gt;

&lt;p&gt;Since this machine is not an AI workstation, the solution had to be realistic. That meant avoiding massive GPU-hosted models, cloud APIs, and overly complex automation.&lt;/p&gt;

&lt;p&gt;The final architecture looks 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;Windows
 ├─ Ollama
 │   └─ qwen2.5-coder:14b
 │
 └─ WSL Ubuntu
     ├─ Aider
     ├─ Git
     └─ Development repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping &lt;strong&gt;Ollama on Windows&lt;/strong&gt; while running &lt;strong&gt;Aider inside WSL&lt;/strong&gt; was a natural choice. I already use Ollama with several Windows applications, so duplicating the models inside WSL made little sense. At the same time, I much prefer working with the Linux command line for software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Ollama on Windows
&lt;/h2&gt;

&lt;p&gt;I installed Ollama on Windows and downloaded the primary coding model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;qwen2.5-coder:14b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also installed the smaller model for quicker testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;qwen2.5-coder:7b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The WSL-to-Windows Connectivity Issue
&lt;/h2&gt;

&lt;p&gt;Initially, Aider running inside WSL couldn't communicate with Ollama running on Windows.&lt;/p&gt;

&lt;p&gt;To make it work, I had to configure WSL to use &lt;strong&gt;mirrored networking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;notepad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="nx"&gt;\.wslconfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I added the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[wsl2]&lt;/span&gt;
&lt;span class="py"&gt;networkingMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mirrored&lt;/span&gt;
&lt;span class="py"&gt;dnsTunneling&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;firewall&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;autoProxy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I restarted WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--shutdown&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After reopening Ubuntu, I tested the connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:11434/api/tags
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response confirmed that WSL could successfully reach the Ollama server running on Windows at &lt;code&gt;127.0.0.1:11434&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Aider in WSL
&lt;/h2&gt;

&lt;p&gt;Inside Ubuntu/WSL:&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;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git python3 python3-pip python3-venv pipx curl
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pipx ensurepath
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
pipx &lt;span class="nb"&gt;install &lt;/span&gt;aider-chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aider &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also configured Git so I could version-control my experiments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"xxxx"&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"xxxxxxx@xxxxx.xx"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the First Repository
&lt;/h2&gt;

&lt;p&gt;I created a simple test 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; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/repos
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/repos
&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I launched Aider:&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;cd&lt;/span&gt; ~/repos/my-project
&lt;span class="nv"&gt;OLLAMA_API_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://127.0.0.1:11434 aider &lt;span class="nt"&gt;--model&lt;/span&gt; ollama_chat/qwen2.5-coder:14b &lt;span class="nt"&gt;--no-show-model-warnings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Aider displayed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Aider v0.86.2
Model: ollama_chat/qwen2.5-coder:14b
Git repo: .git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I finally knew the basic setup was working correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening the Repository from Windows Explorer
&lt;/h2&gt;

&lt;p&gt;For convenience, I also wanted to access the repository directly from Windows Explorer.&lt;/p&gt;

&lt;p&gt;From inside WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;explorer.exe &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command opens the current WSL directory directly in Windows File Explorer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Once I had Aider working with a local Ollama instance, there was still one thing I wanted to understand better: what was happening under the hood. How many tokens were being processed? How long did inference take? What kind of throughput could I expect?&lt;/p&gt;

&lt;p&gt;We'll cover all of that in the next installment. 😉&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>If AI writes code, what is our job now?</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Wed, 01 Jul 2026 10:38:16 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/if-ai-writes-code-what-is-our-job-now-106a</link>
      <guid>https://dev.to/eleonorarocchi/if-ai-writes-code-what-is-our-job-now-106a</guid>
      <description>&lt;p&gt;Anthropic published a very interesting article on &lt;strong&gt;recursive self-improvement&lt;/strong&gt;: the possibility that AI systems will increasingly contribute to building better future versions of themselves.&lt;/p&gt;

&lt;p&gt;Article: &lt;a href="https://www.anthropic.com/institute/recursive-self-improvement" rel="noopener noreferrer"&gt;https://www.anthropic.com/institute/recursive-self-improvement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is a huge topic, almost science fiction: AI developing AI, increasingly fast improvement cycles, systems capable of automating growing parts of research and development.&lt;/p&gt;

&lt;p&gt;But reading the article as a developer, I think the most interesting question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Will AI replace us?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more useful question today is another one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If AI can write, test, refactor, and review code better and better, what is the real role of humans in software development?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For years, we have measured a developer's work partly by their ability to produce code: building features, fixing bugs, optimizing parts of a system, handling refactoring, and doing reviews.&lt;/p&gt;

&lt;p&gt;Today, however, an increasingly large part of these activities can be accelerated by AI tools.&lt;/p&gt;

&lt;p&gt;This means that the value of the developer is shifting from "doing" to "deciding well what should be done."&lt;/p&gt;

&lt;p&gt;One of the most important points in Anthropic's article is that AI becomes very strong when the goal is clear, especially on well-defined tasks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But are we, as developers, still truly understanding what is being produced?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because if AI generates code that works, but we can no longer explain it, maintain it, or assess its risks, then we have not really increased our productivity. We have only pushed technical debt a little further down the road.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottleneck
&lt;/h2&gt;

&lt;p&gt;In many teams, the historical problem was producing enough code. But with today's AI tools, the bottleneck shifts: it becomes the human ability to review, validate, and understand.&lt;/p&gt;

&lt;p&gt;If a tool can generate in a few minutes what used to take hours, the critical point becomes how quickly we can understand, verify, and maintain it.&lt;/p&gt;

&lt;p&gt;This is where the developer of the near future is defined: someone who owns judgment skills that cannot be delegated to AI.&lt;/p&gt;

&lt;p&gt;And so my provocation is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if part of the low productivity of those teams does not depend on the tools, but on the fact that they keep working as if we were still in 2015?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today we have tools that can accelerate coding, debugging, testing, review, documentation, and learning. But if we use them with old mindsets, rigid processes, and poorly collaborative habits, the gain remains limited.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>developer</category>
      <category>llm</category>
    </item>
    <item>
      <title>Generator-Evaluator Loops for AI Agents</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Fri, 22 May 2026 05:26:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/generator-evaluator-loops-for-ai-agents-4kd2</link>
      <guid>https://dev.to/eleonorarocchi/generator-evaluator-loops-for-ai-agents-4kd2</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Separating the generator from the evaluator improves quality and reduces premature self-validation.&lt;/li&gt;
&lt;li&gt;The loop works best when feedback is explicit and based on clear rubrics, especially for subjective or complex tasks.&lt;/li&gt;
&lt;li&gt;It is useful when the task has high value; for simple or easily testable tasks, it can become overengineering.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Separate Production and Evaluation in Tasks Without Ground Truth
&lt;/h2&gt;

&lt;p&gt;If self-evaluation is a recurring failure mode in AI agents, the most natural solution is to separate the role of producing from the role of evaluating.&lt;/p&gt;

&lt;p&gt;This is the principle behind generator-evaluator loops: one agent produces an output, another evaluates it according to explicit criteria, feedback is sent back to the generator, and the system iterates until the result reaches an acceptable threshold.&lt;/p&gt;

&lt;p&gt;The pattern is simple to describe, but powerful, especially in domains where stable ground truth does not exist: design, writing, UX, naming, strategy, documentation, software architecture, complex refactoring.&lt;/p&gt;

&lt;p&gt;In these cases, however, it is not enough to ask the model to "do better." You need to build an environment where improvement is driven by separate, structured, and repeatable critique.&lt;/p&gt;

&lt;h2&gt;
  
  
  From a Single Agent to an Agentic System
&lt;/h2&gt;

&lt;p&gt;A single agent tends to merge three different roles: it plans the work, produces the output, and finally evaluates the result.&lt;/p&gt;

&lt;p&gt;This fusion is convenient but fragile. While it may work for short tasks, in longer ones it often leads to premature convergence, because the same agent chooses a direction, develops it, then positively self-evaluates and closes the task.&lt;/p&gt;

&lt;p&gt;To create a more robust system, these roles should be separated into at least three distinct agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the planner, which breaks the request into manageable parts and defines priorities, constraints, and work sequence;&lt;/li&gt;
&lt;li&gt;the generator, which produces the artifact (e.g. code, interface, document, proposal, strategy, ...);&lt;/li&gt;
&lt;li&gt;the evaluator, which judges the output without having participated in its generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation almost resembles a miniature organizational structure, and in fact, similarly, it helps reduce coupling between decision-making, production, and approval. As in a company, each role has a different objective, and this difference introduces useful friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Analogy with GANs
&lt;/h2&gt;

&lt;p&gt;The most immediate parallel is with Generative Adversarial Networks (GANs).&lt;/p&gt;

&lt;p&gt;In a classic GAN, there are two neural networks: a generator and a discriminator. The generator produces synthetic data, for example images, while the discriminator receives both real and generated data and attempts to distinguish between them. In this way, the generator improves by trying to produce outputs plausible enough to fool the discriminator, while the discriminator improves by becoming better at detecting artificial outputs.&lt;/p&gt;

&lt;p&gt;This idea has been applied across many domains: image generation, face synthesis, super-resolution, computer vision, synthetic data generation, image-to-image translation, music, and video. Examples include models such as StyleGAN, CycleGAN, TextGAN, and MuseGAN, which show how the generative-adversarial principle can be adapted to different forms of content.&lt;/p&gt;

&lt;p&gt;In our case-AI agents-the analogy is useful because it captures an architectural intuition: a generative system improves when exposed to separate judgment.&lt;/p&gt;

&lt;p&gt;There are, however, important aspects that should not be confused with the comparison, because a generator-evaluator loop is not a GAN in the technical sense.&lt;/p&gt;

&lt;p&gt;In real GANs, there is a mathematical loss function: the discriminator is trained on real data, while the generator receives an optimization signal through gradients.&lt;/p&gt;

&lt;p&gt;In AI agents, by contrast, feedback is linguistic and heuristic: the evaluator does not directly update the generator's weights, nor does it necessarily have access to a dataset of real examples.&lt;/p&gt;

&lt;p&gt;When an evaluator judges a landing page, a piece of writing, or a strategy, it is not distinguishing "true" from "false" in the GAN sense. It is estimating how closely the output aligns with a set of preferences, criteria, and conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Subjectivity Evaluatable
&lt;/h2&gt;

&lt;p&gt;The core challenge is turning vague judgments into observable criteria.&lt;/p&gt;

&lt;p&gt;Saying "this UI is ugly" does not help an agent improve-just as saying the same thing to a human designer would not.&lt;/p&gt;

&lt;p&gt;Saying "the visual hierarchy does not sufficiently distinguish between the primary action and secondary content" is much more useful.&lt;/p&gt;

&lt;p&gt;An effective evaluator needs what are commonly called evaluation rubrics.&lt;/p&gt;

&lt;p&gt;In frontend design, for example, a rubric might include four dimensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Design quality&lt;/strong&gt;, which measures whether the result feels like a coherent system or merely an assembly of components. It evaluates visual identity, creative direction, color usage, typography, rhythm, and layout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Originality&lt;/strong&gt;, which measures whether intentional choices are present or whether the output looks derived from templates, library defaults, and generic patterns (this includes recognizing AI slop: predictable gradients, white cards, interchangeable hero sections, stock icons, personality-less compositions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Craft&lt;/strong&gt;, which measures execution: spacing, contrast, alignment, typographic hierarchy, color consistency, and attention to detail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Functionality&lt;/strong&gt;, which measures usability: whether users understand what to do, find the primary actions, navigate without ambiguity, and complete intended tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These criteria do not all need to carry the same weight. In many cases, models are already reasonably strong in craft and functionality; they produce orderly layouts, readable text, and understandable structures. The recurring issue is often the lack of originality and direction.&lt;/p&gt;

&lt;p&gt;For this reason, an evaluator focused on real quality should penalize not only errors, but also blandness.&lt;/p&gt;

&lt;p&gt;The same principle can be applied to other domains.&lt;/p&gt;

&lt;p&gt;For writing, a rubric might evaluate thesis strength, argumentative structure, informational density, rhythm, specificity, voice, redundancy, and the ability to anticipate objections.&lt;/p&gt;

&lt;p&gt;An AI-generated text may be correct, fluent, and well formatted, yet still fail to say anything memorable. In that case, a useful evaluator should be able to distinguish between superficial clarity and real argumentative value.&lt;/p&gt;

&lt;p&gt;For strategy, a rubric might evaluate diagnostic quality, explicit assumptions, trade-offs, feasibility, prioritization, risks, dependencies, metrics, and contextual alignment.&lt;/p&gt;

&lt;p&gt;And what about code? Beyond tests, a rubric should assess simplicity, maintainability, consistency with the codebase, error handling, extensibility, technical debt introduced, readability, and impact on existing abstractions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Operational Loop
&lt;/h2&gt;

&lt;p&gt;A typical generator-evaluator loop follows a simple sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the system receives a specification;&lt;/li&gt;
&lt;li&gt;the planner breaks it into subtasks and defines success criteria;&lt;/li&gt;
&lt;li&gt;the generator produces a first version of the output;&lt;/li&gt;
&lt;li&gt;the evaluator inspects the artifact using explicit criteria and, when possible, real tools such as browsers, test runners, screenshots, parsers, linters, metrics, documentation, or access to the codebase;&lt;/li&gt;
&lt;li&gt;the evaluator assigns scores, identifies issues, and produces actionable feedback;&lt;/li&gt;
&lt;li&gt;the generator receives the feedback and iterates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The cycle continues until the output exceeds a threshold, the budget is exhausted, or the system determines that human intervention is required.&lt;/p&gt;

&lt;p&gt;The core of the loop is actionable feedback, because the evaluator must not only detect failure, but also make it correctable.&lt;/p&gt;

&lt;p&gt;A generator-evaluator loop is fundamentally a matter of harness engineering, because the evaluator must have access to the right tools.&lt;/p&gt;

&lt;p&gt;That said, an evaluator does not automatically improve simply because it is separated from the generator. For it to work, it must be calibrated using explicit criteria, scoring scales, potentially few-shot examples, thresholds, and similar mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use This Pattern
&lt;/h2&gt;

&lt;p&gt;A generator-evaluator loop has a cost: more model calls, more tokens, more latency, more orchestration, and more complexity. As a result, it is impossible to apply it everywhere.&lt;/p&gt;

&lt;p&gt;As a rule of thumb, if a reliable automated test exists, it is usually better to use it.&lt;/p&gt;

&lt;p&gt;And if the task is simple or low-value, a complex loop may genuinely become overengineering.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Why AI Agents can’t judge themselves</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Fri, 15 May 2026 05:19:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/why-ai-agents-cant-judge-themselves-24fc</link>
      <guid>https://dev.to/eleonorarocchi/why-ai-agents-cant-judge-themselves-24fc</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AI agents tend to overestimate the quality of their own outputs when there is no external verification criterion. In subjective tasks (design, writing, UX, naming, strategy), simply asking the model to "reflect" is not enough: it often remains trapped in the same trajectory that produced the first plausible solution, leading to weak critiques and superficial improvements.&lt;/li&gt;
&lt;li&gt;Achieving real quality requires designing the runtime around the model: tests, rubrics, separate evaluators, external tools, and generator-evaluator loops that introduce critical distance between the system that produces the output and the one that approves it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Internal Feedback Is Not Enough in Subjective Tasks
&lt;/h2&gt;

&lt;p&gt;Sometimes, when you ask a model to evaluate a response it previously generated, it will rate it as good even when it clearly is not. Buggy code gets labeled "production-ready"; a generic layout is described as "modern and coherent"; a technically correct but flat piece of writing is called "clear, incisive, and well-structured."&lt;/p&gt;

&lt;p&gt;This behavior becomes especially evident when the task lacks binary verification.&lt;/p&gt;

&lt;p&gt;If the agent has to write a function and there is a reliable test suite available, the system has access to an external oracle: the test either passes or fails.&lt;/p&gt;

&lt;p&gt;But as soon as the task moves into domains such as design, writing, naming, UX, strategy, or product architecture, quality can no longer be reduced to an &lt;code&gt;assert&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is where the self-evaluation problem in AI agents emerges: the same system that produces the output struggles to judge it with enough critical distance. And, if we think about it, humans often behave the same way.&lt;/p&gt;

&lt;p&gt;The point, however, is not that LLMs have ego, self-esteem, or a desire to appear competent. Saying that agents "self-promote" is a useful shortcut, but technically inaccurate. A model is not trying to convince us that its output is good. More often, it simply remains inside the same probabilistic trajectory that generated the artifact in the first place.&lt;/p&gt;

&lt;p&gt;If we ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generate a landing page for a SaaS product.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And immediately afterward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Evaluate the quality of the landing page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;we have not really created two distinct processes. We have asked the same model to continue reasoning within the same semantic space, with the same context, assumptions, and implicit orientation toward completing the task.&lt;/p&gt;

&lt;p&gt;The result is often an evaluation that is overly generous, poorly discriminative, and not very useful for driving meaningful improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tasks With an Oracle and Tasks Without One
&lt;/h2&gt;

&lt;p&gt;We can distinguish between two classes of tasks.&lt;/p&gt;

&lt;p&gt;The first includes tasks with an external oracle. These are cases where quality can be verified relatively objectively: an automated test, a query returning an expected result, a formal constraint, a compiler, syntactic validation, or a numerical measurement.&lt;/p&gt;

&lt;p&gt;In software engineering, many tasks fall at least partially into this category. Code can be evaluated through unit tests, integration tests, type checkers, linters, benchmarks, and static analysis. These tools do not fully capture software quality, but they provide strong signals. If an agent produces code that does not compile or breaks a test suite, the system does not need to "guess" that something is wrong: it knows.&lt;/p&gt;

&lt;p&gt;The second class includes tasks without a clear oracle. Here, quality is subjective, multidimensional, or context-dependent. A UI can be technically correct but visually uninspired. A text can be grammatically flawless but lack a real thesis. A strategy can be well formatted yet impossible to execute. A naming proposal can be understandable but forgettable.&lt;/p&gt;

&lt;p&gt;In these cases, the problem is not just verifying whether the output is correct, but determining whether it is actually good.&lt;/p&gt;

&lt;p&gt;And unfortunately, "good" does not mean one single, clearly identifiable thing.&lt;/p&gt;

&lt;p&gt;In design, it may mean visual coherence, originality, hierarchy, usability, or identity; in writing, clarity, density, rhythm, argumentative strength, or voice; in strategy, accurate diagnosis, explicit trade-offs, feasibility, specificity, and contextual alignment.&lt;/p&gt;

&lt;p&gt;When an external oracle is missing, the agent tends to rely on its own linguistic evaluation. And that is exactly where the system becomes fragile.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Failure Mode: Premature Convergence
&lt;/h2&gt;

&lt;p&gt;The most common failure mode is not catastrophic error, but premature convergence.&lt;/p&gt;

&lt;p&gt;The agent produces a plausible solution, refines it superficially, and declares it sufficient. The result is not necessarily wrong. Often, it is worse: mediocre but defensible.&lt;/p&gt;

&lt;p&gt;This "plausible mediocrity" is difficult to detect because it contains many superficial signals of quality.&lt;/p&gt;

&lt;p&gt;An AI-generated landing page will probably include a hero section, a CTA, a feature grid, a few cards, a responsive layout, a pleasant color palette, and tidy copy. A strategy document will include neatly titled sections, bullet points, frameworks, and recommendations. A refactoring will contain cleaner names and a few extra abstractions.&lt;/p&gt;

&lt;p&gt;But all of this can still remain generic.&lt;/p&gt;

&lt;p&gt;The agent tends to improve what it has already produced instead of questioning whether the direction itself is correct. It polishes the first solution instead of challenging it. It adds local coherence, not global quality.&lt;/p&gt;

&lt;p&gt;This is where self-evaluation fails: not because the model cannot recognize any errors, but because it often does not apply criticism strong enough to break away from the first acceptable solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Limits of Reflective Prompting
&lt;/h2&gt;

&lt;p&gt;One of the earliest responses to this problem was reflective prompting: asking the model to critique its own output, identify issues, propose improvements, and iterate.&lt;/p&gt;

&lt;p&gt;This approach works to some extent because it can eliminate obvious errors, improve clarity, fix inconsistencies, and add missing details. However, its main limitation is that the critique remains inside the same process that generated the output.&lt;/p&gt;

&lt;p&gt;Prompts such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reflect on your work and improve it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Identify any problems in the previous response.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;often produce generic feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"It could be more specific";&lt;/li&gt;
&lt;li&gt;"Clarity could be improved";&lt;/li&gt;
&lt;li&gt;"I would add more concrete examples";&lt;/li&gt;
&lt;li&gt;"The structure is already solid, but it could be refined."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These observations are true, but weak, and they rarely lead to a substantial change in direction.&lt;/p&gt;

&lt;p&gt;For simple tasks this may be enough, but for high-value tasks it often is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Runtime Matters
&lt;/h2&gt;

&lt;p&gt;This problem contributed to the rise of harness engineering: designing the runtime around the model.&lt;/p&gt;

&lt;p&gt;As I described in previous articles about &lt;a href="https://dev.to/eleonorarocchi/harness-engineering-la-parte-piu-importante-degli-agenti-ai-4jnd"&gt;harnesses&lt;/a&gt;, the core idea is that the performance of an agentic system depends not only on the model itself, but also on the operational environment in which the model works. What matters is how the prompt is constructed, which tools are available, how context is managed, how intermediate states are stored, how tests are executed, how feedback is orchestrated, when the system decides to iterate, and when it decides to stop.&lt;/p&gt;

&lt;p&gt;In modern agentic systems, the model is just one component. Final behavior emerges from the interaction between the model, tools, memory, context, schedulers, evaluators, acceptance criteria, and retry mechanisms.&lt;/p&gt;

&lt;p&gt;This shift in perspective is fundamental. If the model struggles to evaluate itself, the solution is not necessarily to wait for a better model. It is to design a runtime that makes the evaluation process less fragile.&lt;/p&gt;

&lt;p&gt;In coding, this may mean running tests, reading errors, applying patches, and retrying. In design, it may mean generating screenshots, navigating the interface, and verifying interactive states. In writing, it may mean using editorial rubrics, comparing versions, and evaluating density and redundancy. In strategy, it may mean making assumptions explicit and testing alternative scenarios.&lt;/p&gt;

&lt;p&gt;The runtime introduces signals that the model alone does not reliably produce.&lt;/p&gt;

&lt;h2&gt;
  
  
  Critical Distance as an Architectural Requirement
&lt;/h2&gt;

&lt;p&gt;The self-evaluation problem can be summarized like this: generation and evaluation are too close to each other.&lt;/p&gt;

&lt;p&gt;Critical distance can be introduced in many ways. Sometimes changing the prompt, role, or critique format is enough; other times it requires a different model, a different temperature, a stricter rubric, few-shot examples, external tools, or a separate agent.&lt;/p&gt;

&lt;p&gt;The principle remains the same: the system must create a separation between the entity that produces and the entity that approves.&lt;/p&gt;

&lt;p&gt;This separation does not guarantee perfect evaluation, but it reduces the risk that the agent settles for the first plausible solution.&lt;/p&gt;

&lt;p&gt;This naturally leads to the generator-evaluator pattern: one agent produces, another evaluates, feedback returns to the first, and the cycle continues until the output surpasses a threshold.&lt;/p&gt;

&lt;p&gt;It is not always necessary: for simple tasks it can become overengineering.&lt;/p&gt;

&lt;p&gt;But for subjective, long, or high-value tasks, it becomes one of the most useful patterns in agent engineering.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>How Stripe, Shopify, and Airbnb Build AI Harnesses</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Sat, 09 May 2026 07:04:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/how-stripe-shopify-and-airbnb-build-ai-harnesses-1i6l</link>
      <guid>https://dev.to/eleonorarocchi/how-stripe-shopify-and-airbnb-build-ai-harnesses-1i6l</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There is no single model of harness engineering.&lt;/li&gt;
&lt;li&gt;OpenAI builds repository-centered harnesses, Anthropic focuses on agent cognitive continuity, while companies like Stripe, Shopify, and Airbnb develop vertical harnesses built around compliance, context, and action verification.&lt;/li&gt;
&lt;li&gt;Harness engineering is becoming a domain-specific discipline, shaped by the type of risk each company needs to control.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why There Is No Single Harness: Stripe, Shopify, Airbnb, and the Industrial Fragmentation of Agent Engineering
&lt;/h2&gt;

&lt;p&gt;After observing OpenAI's repository harness and Anthropic's runtime harness (if you haven't done so already, read my articles: &lt;a href="https://dev.to/eleonorarocchi/openai-and-the-new-cognitive-architecture-of-software-repositories-383m"&gt;OpenAI and the New Cognitive Architecture of Software Repositories&lt;/a&gt; e &lt;a href="https://dev.to/eleonorarocchi/anthropic-and-the-runtime-harness-for-persistent-agents-4mf2"&gt;Anthropic and the Runtime Harness for Persistent Agents&lt;/a&gt;), one might expect the industry to be converging toward a fairly clear formula: define memory, tools, feedback loops, constraints, and let the agents work.&lt;/p&gt;

&lt;p&gt;In reality, the opposite is happening: the more public big-tech case studies become, the more it becomes clear that the word &lt;em&gt;harness&lt;/em&gt; is starting to cover profoundly different architectures.&lt;/p&gt;

&lt;p&gt;I find this to be the most interesting signal of the sector's maturation, because it means we are no longer witnessing the birth of a standard, but rather the emergence of multiple implementation paradigms.&lt;/p&gt;

&lt;p&gt;The comparative analyses published about companies like Stripe, Shopify, and Airbnb demonstrate this very clearly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Point Is Not Model Capability. It's the Cost of Failure.
&lt;/h2&gt;

&lt;p&gt;As long as we talk about coding agents in the abstract, there is a tendency to imagine that the problem is singular: making the model more reliable.&lt;/p&gt;

&lt;p&gt;However, in industrial environments, reliability is not a neutral category; it depends on what the company considers tolerable or intolerable. That is where the divergence begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stripe: The Harness as a Compliance Boundary
&lt;/h2&gt;

&lt;p&gt;In the financial domain, the problem is not only producing a correct modification, but producing a modification that does not violate policies, introduce vulnerabilities, alter critical transactional flows, and remains fully auditable.&lt;/p&gt;

&lt;p&gt;In this context, the harness tends to become an approval gate, with automated validation, side-effect simulation, and above all, compliance controls.&lt;/p&gt;

&lt;p&gt;The agent does not operate in an open environment, but inside a risk-clearing chamber.&lt;/p&gt;

&lt;p&gt;The harness is primarily a containment boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shopify: Harnesses for Context Distribution
&lt;/h2&gt;

&lt;p&gt;Shopify's problem is almost the opposite: the commerce domain is hyper-fragmented, with different themes, plugins, merchant logics, and unpredictable customizations.&lt;/p&gt;

&lt;p&gt;The primary risk, beyond causing damage, is producing something generically correct but locally useless.&lt;/p&gt;

&lt;p&gt;For this reason, the harness must excel at contextual retrieval, access to internal documentation, merchant-state simulation, and precise distribution of relevant information.&lt;/p&gt;

&lt;p&gt;The model must not only be safe, but operate with an accurate understanding of the merchant's specific context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Airbnb: Harnesses as Perceptual Verifiability
&lt;/h2&gt;

&lt;p&gt;In customer-facing and UI-heavy workflows, the problem changes once again, because an agent can propose a technically reasonable modification while still breaking selectors, navigation, UX flows, or intermediate states.&lt;/p&gt;

&lt;p&gt;In cases like Airbnb, the harness emphasizes browser instrumentation, screenshot verification, replayability, and control over executed actions.&lt;/p&gt;

&lt;p&gt;The core question becomes: does the action actually produce the intended effect in the user environment?&lt;/p&gt;

&lt;p&gt;The harness therefore becomes a perceptual surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Best Practices to a Domain-Specific Discipline
&lt;/h2&gt;

&lt;p&gt;What these cases show is that a harness is not a universal checklist of components.&lt;/p&gt;

&lt;p&gt;A harness is a response to the failure modes that each organization considers economically most dangerous:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for OpenAI, the risk is codebase entropy;&lt;/li&gt;
&lt;li&gt;for Anthropic, it is cognitive drift;&lt;/li&gt;
&lt;li&gt;for Stripe, regulatory side effects;&lt;/li&gt;
&lt;li&gt;for Shopify, the loss of situational context;&lt;/li&gt;
&lt;li&gt;for Airbnb, the non-verifiability of actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same word, completely different problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Maturity of the Industry Is This Fragmentation
&lt;/h2&gt;

&lt;p&gt;We often interpret fragmentation as a lack of standards. But I would argue the opposite can also be true: when a discipline is young, everyone uses the same generic formulas; as it matures, specialized architectures begin to emerge.&lt;/p&gt;

&lt;p&gt;That is perhaps exactly what is happening with harness engineering.&lt;/p&gt;

&lt;p&gt;Just like choosing the best TypeScript framework, we are now entering the phase where the real question becomes: which harness architecture is most coherent with the type of risk my agent cannot afford to tolerate?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Anthropic and the Runtime Harness for Persistent Agents</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Fri, 01 May 2026 05:13:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/anthropic-and-the-runtime-harness-for-persistent-agents-4mf2</link>
      <guid>https://dev.to/eleonorarocchi/anthropic-and-the-runtime-harness-for-persistent-agents-4mf2</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Anthropic shows that the real challenge for AI agents is not starting a task, but staying coherent throughout long executions.&lt;/li&gt;
&lt;li&gt;Avoiding cognitive drift requires a runtime harness built on external memory, checkpoints, and continuous re-anchoring.&lt;/li&gt;
&lt;li&gt;The next frontier is not autonomy alone: it is cognitive continuity.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Anthropic and the Runtime Harness: the Real Problem with Agents Is Not Acting, but Not Getting Lost While They Act
&lt;/h2&gt;

&lt;p&gt;If &lt;a href="https://dev.to/eleonorarocchi/openai-and-the-new-cognitive-architecture-of-software-repositories-383m"&gt;the OpenAI case&lt;/a&gt; showed how a repository can be rethought to become readable for agents, the contribution published by Anthropic in &lt;a href="https://www.anthropic.com/engineering/harness-design-long-running-apps" rel="noopener noreferrer"&gt;&lt;em&gt;Harness design for long-running application development&lt;/em&gt;&lt;/a&gt; opens an even more delicate question: what happens when the challenge is no longer how to start a task well, but how to keep it alive for hours?&lt;/p&gt;

&lt;p&gt;Because this is where many agentic systems truly begin to break.&lt;/p&gt;

&lt;p&gt;Not at the first tool call, nor at the first planning step, but perhaps at the twentieth minute-when context starts to thin out, micro-errors begin to accumulate, and the agent keeps acting while preserving only the illusion of coherence.&lt;/p&gt;

&lt;p&gt;In its article &lt;a href="https://www.anthropic.com/engineering/harness-design-long-running-apps" rel="noopener noreferrer"&gt;&lt;em&gt;Harness design for long-running application development&lt;/em&gt;&lt;/a&gt;, Anthropic puts its finger exactly on this point: the frontier of agent engineering is not simply autonomy, but the persistence of autonomy over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Underestimated Failure Mode: Cognitive Drift
&lt;/h2&gt;

&lt;p&gt;Many agents appear to work well as long as we observe them on short tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generating a component;&lt;/li&gt;
&lt;li&gt;fixing a function;&lt;/li&gt;
&lt;li&gt;calling two or three tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But when the task stretches across dozens of files, multiple review phases, intermediate validations, and distributed dependencies, a phenomenon begins that is very familiar to those who use them in real settings: the agent continues to produce output, but progressively loses the center of its own intention.&lt;/p&gt;

&lt;p&gt;Anthropic treats this as a structural problem, not as a simple "model limitation": and this is precisely where the runtime harness emerges.&lt;/p&gt;

&lt;h2&gt;
  
  
  From the Context Window to External Cognition
&lt;/h2&gt;

&lt;p&gt;The starting point is almost brutal: the context window, by itself, is too fragile a memory to sustain long-running tasks.&lt;/p&gt;

&lt;p&gt;Even with very large contextual windows, the model suffers from imperfect compression, unstable salience, priority loss, and partial retrieval of goals.&lt;/p&gt;

&lt;p&gt;For this reason, Anthropic builds around Claude an external procedural memory composed of persistent scratchpads, task files, execution summaries, serialized checkpoints, and continuously updated state notes.&lt;/p&gt;

&lt;p&gt;In practice, the model is no longer forced to "remember everything", because it can reread what it has already established.&lt;/p&gt;

&lt;p&gt;This makes an enormous difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Harness as a System of Continuous Re-Anchoring
&lt;/h2&gt;

&lt;p&gt;In the classical paradigm, we tell the agent: continue.&lt;/p&gt;

&lt;p&gt;In the Anthropic paradigm, instead, we tell it: stop, reread where you are, summarize what you are doing, update your state, then continue.&lt;/p&gt;

&lt;p&gt;This creates a re-anchoring cycle.&lt;/p&gt;

&lt;p&gt;The agent is periodically brought back to the goal, to the progress already completed, to the constraints still open, and to the errors that have emerged.&lt;/p&gt;

&lt;p&gt;It is a form of "artificial continuity".&lt;/p&gt;

&lt;p&gt;Cognition is not allowed to flow in a monolithic way; it is broken apart, recorded, and reconsolidated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Agent Evaluation: Thinking Is Not Enough, You Need to Be Critiqued
&lt;/h2&gt;

&lt;p&gt;Another interesting aspect of Anthropic's work is the use of generator/evaluator structures: one agent produces, and a second agent evaluates quality, coherence, usability, and adherence to requirements.&lt;/p&gt;

&lt;p&gt;The result is not simply "more review".&lt;/p&gt;

&lt;p&gt;It is something subtler: verification stops being a final phase and becomes part of cognitive continuity itself.&lt;/p&gt;

&lt;p&gt;In this way, each evaluation prevents the primary agent from drifting too far away from the correct trajectory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Runtime Harness Is Not Meant to Make the Agent Act Better: It Is Meant to Make It Think Longer
&lt;/h2&gt;

&lt;p&gt;This is perhaps the most important point: while OpenAI builds above all a structural harness, Anthropic builds above all a temporal harness.&lt;/p&gt;

&lt;p&gt;The problem it is solving is no longer "how do I get Claude to generate good code?", but "how do I prevent Claude from losing the thread while it continues generating it?".&lt;/p&gt;

&lt;p&gt;It sounds like a nuance, but it completely changes the design, because here:&lt;/p&gt;

&lt;p&gt;the memory is an external artifact,&lt;br&gt;
planning is serialized,&lt;br&gt;
review is recurrent,&lt;br&gt;
the task is continuously re-anchored.&lt;/p&gt;

&lt;p&gt;So this is not only orchestration-it is assisted cognitive continuity.&lt;/p&gt;

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

&lt;p&gt;If OpenAI's repository harness teaches us that an agent needs to live inside a readable codebase, Anthropic reminds us that this is not enough.&lt;/p&gt;

&lt;p&gt;An agent may have perfect tools, perfect documentation, perfect constraints and still get lost if it is allowed to run for too long without an external memory that keeps it coherent.&lt;/p&gt;

&lt;p&gt;And this is where the runtime harness changes the game: it does not merely build an environment in which the agent can act; it builds an environment in which the agent can continue to know &lt;em&gt;why&lt;/em&gt; it is acting.&lt;/p&gt;

&lt;p&gt;In agent engineering, this may be the difference between episodic automation and real autonomy.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>OpenAI and the New Cognitive Architecture of Software Repositories</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Tue, 28 Apr 2026 05:36:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/openai-and-the-new-cognitive-architecture-of-software-repositories-383m</link>
      <guid>https://dev.to/eleonorarocchi/openai-and-the-new-cognitive-architecture-of-software-repositories-383m</guid>
      <description>&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI's latest harness engineering report suggests something deeper than "agents can write a lot of code."&lt;/li&gt;
&lt;li&gt;It suggests that the real bottleneck in agentic software is no longer just the model, but the repository itself.&lt;/li&gt;
&lt;li&gt;Once agents become primary executors, codebases must stop being designed only for human maintainers and start becoming semantically navigable computational environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  OpenAI and the Birth of the Repository Harness: When Code Must Become Readable to Agents
&lt;/h1&gt;

&lt;p&gt;Over the past few months, the concept of &lt;em&gt;harness engineering&lt;/em&gt; has become one of the most frequently discussed categories in AI engineering, especially as companies have started confronting a very simple problem: an agent may be brilliant in isolated executions, but without an environment intentionally designed around it, it quickly begins to generate entropy.&lt;/p&gt;

&lt;p&gt;As I discussed in my previous article,&lt;a href="https://dev.to/eleonorarocchi/harness-engineering-la-parte-piu-importante-degli-agenti-ai-4jnd"&gt;Harness Engineering: The Most Important Part of AI Agents&lt;/a&gt; harnesses represent the truly critical layer of an agentic system, and this infrastructure must evolve significantly when moving from prototype to production.&lt;br&gt;
The case recently published by &lt;a href="https://openai.com/it-IT/index/harness-engineering/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;, however, adds an even more important piece to the puzzle: it suggests that the first object we need to learn how to design for agents may not be the model itself, but the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Number Everyone Quoted — and the One That Actually Matters
&lt;/h2&gt;

&lt;p&gt;In the report &lt;em&gt;Harness engineering: leveraging Codex in an agent-first world&lt;/em&gt;, OpenAI explains that it built a functional internal beta with roughly one million lines of code generated entirely by Codex, zero manually written lines, and more than 1,500 pull requests handled by an extremely small team.&lt;/p&gt;

&lt;p&gt;It is an impressive figure, and naturally it made headlines.&lt;br&gt;
But stopping at the quantity means missing the central point.&lt;/p&gt;

&lt;p&gt;The real message of the report is something else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;productivity did not increase because Codex "writes code very fast";&lt;/li&gt;
&lt;li&gt;it increased because engineers stopped treating the repository as a simple container of files and started treating it as an environment computable by agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, OpenAI did not simply use a coding agent inside a codebase: it transformed the codebase into something an agent can read, interpret, and correct reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Human Codebase to Agent-Readable Codebase
&lt;/h2&gt;

&lt;p&gt;There are at least four very clear signals of this transformation.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Repository Knowledge Becomes the System of Record
&lt;/h3&gt;

&lt;p&gt;OpenAI insists on one precise point: the repository must contain the operational truth.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;versioned internal documentation;&lt;/li&gt;
&lt;li&gt;architectural maps;&lt;/li&gt;
&lt;li&gt;decision histories;&lt;/li&gt;
&lt;li&gt;files such as &lt;code&gt;AGENTS.md&lt;/code&gt; that function as a semantic entry point for agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not about adding "more documentation," but about ensuring that the repository becomes machine-queryable memory, not merely something readable by humans.&lt;/p&gt;

&lt;p&gt;The agent should not have to infer structure from scattered code; it should be able to interrogate that structure directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. CI Stops Being Just Quality Assurance and Becomes a Runtime Training Mechanism
&lt;/h3&gt;

&lt;p&gt;Linting, formatting, boundary checks, import policies, automated verification: in a traditional pipeline these serve to maintain order, while in a repository harness they serve something more: they become deterministic feedback loops that continuously teach the agent which behaviors are allowed and which are not.&lt;/p&gt;

&lt;p&gt;The agent makes a mistake, CI blocks the execution, the log returns the reason, the task is iterated again: quality control stops being post-production and becomes part of the execution-time reasoning process.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Observability Is Designed for the Agent Too
&lt;/h3&gt;

&lt;p&gt;OpenAI explains that it invested heavily in structured logs, diagnostic traces, verifiable outputs, and inspection tools.&lt;/p&gt;

&lt;p&gt;This is because an agent that cannot properly read its own failures is forced to regenerate blindly; conversely, an agent with access to semantically dense error information can perform self-debugging.&lt;/p&gt;

&lt;p&gt;Observability, therefore, is no longer just a developer dashboard: it becomes a cognitive surface.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Developers Stop Being Authors of Code and Become Authors of Constraints
&lt;/h3&gt;

&lt;p&gt;This is perhaps the most interesting point in the entire OpenAI article: human work does not disappear, it shifts.&lt;/p&gt;

&lt;p&gt;Less time spent on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;direct implementation;&lt;/li&gt;
&lt;li&gt;manual fixes;&lt;/li&gt;
&lt;li&gt;tactical coding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More time spent on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;designing repository structure;&lt;/li&gt;
&lt;li&gt;defining architectural boundaries;&lt;/li&gt;
&lt;li&gt;building feedback loops;&lt;/li&gt;
&lt;li&gt;cleaning entropy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The engineer writes fewer and fewer features, and more and more conditions of intelligibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Repository Harness as the New Unit of Design
&lt;/h2&gt;

&lt;p&gt;If we look closely, the OpenAI case suggests a strong thesis: the first mature industrial harness is not simply a wrapper around the model; it is a codebase deliberately made readable to agents.&lt;/p&gt;

&lt;p&gt;And this is an important distinction.&lt;/p&gt;

&lt;p&gt;For years we assumed that the agent problem was primarily about improving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prompting;&lt;/li&gt;
&lt;li&gt;reasoning;&lt;/li&gt;
&lt;li&gt;tool use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenAI shows that there is an upstream layer beyond all of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a mediocre agent inside an agent-readable repository can still produce usable work;&lt;/li&gt;
&lt;li&gt;a highly capable agent inside an opaque repository will still produce entropy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bottleneck is not only the model, but increasingly the computability of the environment.&lt;/p&gt;

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

&lt;p&gt;Perhaps OpenAI's most interesting contribution to the harness engineering debate is not having shown that software can be built with agents.&lt;/p&gt;

&lt;p&gt;It is having shown that, to do it seriously, we need to accept one uncomfortable fact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it is no longer enough for code to be maintainable by humans;&lt;/li&gt;
&lt;li&gt;it must become navigable, verifiable, and semantically readable by agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And this radically shifts the work of engineering.&lt;/p&gt;

&lt;p&gt;We are no longer designing only applications — we are (perhaps finally) beginning to design repositories that can be inhabited by non-deterministic intelligences.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>Building a Harness: From Prototype to Production</title>
      <dc:creator>eleonorarocchi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 05:12:00 +0000</pubDate>
      <link>https://dev.to/eleonorarocchi/building-a-harness-from-prototype-to-production-o30</link>
      <guid>https://dev.to/eleonorarocchi/building-a-harness-from-prototype-to-production-o30</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An agent doesn’t truly work because of the model, but because of the harness controlling it.&lt;/li&gt;
&lt;li&gt;Moving from demo to production requires handling errors, state, memory, and observability.&lt;/li&gt;
&lt;li&gt;A well-designed harness reduces model unpredictability and shifts complexity into code, making the system reliable and usable in real-world scenarios.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;In article &lt;a href="https://dev.to/eleonorarocchi/harness-engineering-la-parte-piu-importante-degli-agenti-ai-4jnd"&gt;Harness Engineering: The Most Important Part of AI Agents&lt;/a&gt; we saw a fundamental point: the problem with agents isn't (only) the model, but the system around it.&lt;/p&gt;

&lt;p&gt;But what does it really mean to build that system?&lt;/p&gt;

&lt;h2&gt;
  
  
  The moment everything breaks
&lt;/h2&gt;

&lt;p&gt;There's a fairly universal phase: you've implemented a demo, it works well, the model responds, uses a tool, maybe even completes multi-step tasks, and everything looks promising.&lt;/p&gt;

&lt;p&gt;Then you try to use it in a real-world context, and the problems emerge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invalid outputs&lt;/li&gt;
&lt;li&gt;incorrect API calls&lt;/li&gt;
&lt;li&gt;infinite loops&lt;/li&gt;
&lt;li&gt;loss of context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not that the model got worse—the system's complexity increased without having a harness solid enough to manage it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The harness as a control system
&lt;/h2&gt;

&lt;p&gt;It becomes clear that the harness isn't just a "container"—it's more like a control system designed to guide the model along a precise path, reducing its freedom when necessary and allowing it when useful.&lt;/p&gt;

&lt;p&gt;This is a delicate balance: too much control means loss of flexibility; too little control means loss of reliability.&lt;/p&gt;

&lt;p&gt;And this is where the real design work begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling becomes the main case
&lt;/h2&gt;

&lt;p&gt;In traditional software, errors are edge cases. Anyone with experience in agent-based systems knows that errors are the norm.&lt;/p&gt;

&lt;p&gt;The key idea, however, is that a well-designed harness does not assume everything will go well—quite the opposite.&lt;/p&gt;

&lt;p&gt;It therefore introduces mechanisms such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validating outputs before using them&lt;/li&gt;
&lt;li&gt;retrying when something goes wrong&lt;/li&gt;
&lt;li&gt;falling back to alternative paths&lt;/li&gt;
&lt;li&gt;controlled interruption of loops&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what makes the system usable.&lt;/p&gt;

&lt;h2&gt;
  
  
  State and memory: the invisible problem
&lt;/h2&gt;

&lt;p&gt;Another issue that emerges very early is state management: an agent without memory is little more than a stateless function—but adding memory introduces complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what to store&lt;/li&gt;
&lt;li&gt;for how long&lt;/li&gt;
&lt;li&gt;how to update the state&lt;/li&gt;
&lt;li&gt;what happens when it becomes inconsistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These decisions must be made when structuring the harness.&lt;/p&gt;

&lt;p&gt;And it's precisely here that many subtle bugs tend to arise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability: knowing what's happening
&lt;/h2&gt;

&lt;p&gt;When something goes wrong (and sooner or later it will), the important question is:&lt;/p&gt;

&lt;p&gt;"Can I understand what happened?"&lt;/p&gt;

&lt;p&gt;Without logging and tracing, working with agents becomes almost impossible.&lt;/p&gt;

&lt;p&gt;Because you need to see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every step of the reasoning&lt;/li&gt;
&lt;li&gt;every tool call&lt;/li&gt;
&lt;li&gt;every output transformation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And not just for debugging, but to evolve the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving complexity to the right place
&lt;/h2&gt;

&lt;p&gt;An interesting aspect is that, as you improve the harness, the system becomes more predictable—even without changing the model.&lt;/p&gt;

&lt;p&gt;This happens because complexity is being moved out of an "opaque" component (the model) and into code that can actually be controlled.&lt;/p&gt;

&lt;p&gt;It's a shift in strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less blind trust in the model&lt;/li&gt;
&lt;li&gt;more explicit control in the system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which, ultimately, is software engineering.&lt;/p&gt;

&lt;p&gt;In fact, we can say that building agents today is much closer to traditional software engineering than it might seem.&lt;/p&gt;

&lt;p&gt;There are flows, states, error handling, integrations, observability…&lt;/p&gt;

&lt;p&gt;The only difference is that instead of deterministic functions, there's a probabilistic model.&lt;/p&gt;

&lt;p&gt;The harness is what holds everything together—and that's what makes the difference between something that only works in a demo and something that truly works in production.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
