<?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: Takafumi Endo | ROUTE06</title>
    <description>The latest articles on DEV Community by Takafumi Endo | ROUTE06 (@gyu07).</description>
    <link>https://dev.to/gyu07</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%2F2326576%2F5d3119ba-b98b-49fa-95fe-a0406b33df70.png</url>
      <title>DEV Community: Takafumi Endo | ROUTE06</title>
      <link>https://dev.to/gyu07</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gyu07"/>
    <language>en</language>
    <item>
      <title>Reverse-Engineering-Driven Harness Engineering for Existing Applications</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Fri, 16 Oct 2026 02:17:53 +0000</pubDate>
      <link>https://dev.to/gyu07/reverse-engineering-driven-harness-engineering-for-existing-applications-44h</link>
      <guid>https://dev.to/gyu07/reverse-engineering-driven-harness-engineering-for-existing-applications-44h</guid>
      <description>&lt;p&gt;AI-driven legacy modernization is often discussed in terms of understanding, refactoring, or rewriting existing codebases.&lt;/p&gt;

&lt;p&gt;But with AI coding agents such as Claude Code and Codex, another direction is becoming increasingly practical: &lt;strong&gt;enabling agents to operate and extend existing applications through their existing interfaces, without necessarily rewriting their code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is especially relevant to low-code platforms and enterprise systems, where business logic is often distributed across GUI configurations, workflows, metadata, and operational procedures.&lt;/p&gt;

&lt;p&gt;Recently, I've been applying an approach that combines reverse engineering, harness engineering, operations research (OR), and runtime engineering to this problem.&lt;/p&gt;

&lt;p&gt;The idea is straightforward: discover how an application behaves, convert that knowledge into reusable operational capabilities, and provide an execution environment in which AI agents can achieve business goals while respecting the application's constraints.&lt;/p&gt;

&lt;p&gt;This article describes the approach as a practical system design and implementation framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Problem Is Not Just GUI Automation
&lt;/h2&gt;

&lt;p&gt;Consider adding an approval workflow to an existing low-code application.&lt;/p&gt;

&lt;p&gt;A developer would need to inspect the current application, understand its data and workflow structures, identify the relevant configuration screens, make changes, and verify the result.&lt;/p&gt;

&lt;p&gt;An AI agent needs to do essentially the same work.&lt;/p&gt;

&lt;p&gt;Providing GUI automation alone does not solve this problem. The agent may be able to click buttons and enter values, but it still needs to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which operations are available and when they are valid.&lt;/li&gt;
&lt;li&gt;Which application states and permissions are required.&lt;/li&gt;
&lt;li&gt;How a change affects existing functions.&lt;/li&gt;
&lt;li&gt;Whether an operation actually persisted its intended result.&lt;/li&gt;
&lt;li&gt;How to verify that the business requirement has been satisfied.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This requires more than tools. It requires application-specific operational knowledge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GUI automation provides actions. Harness engineering provides the knowledge and controls needed to use those actions reliably.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The objective is not merely to automate an existing workflow. It is to enable AI agents to operate, configure, and extend existing applications through supported interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Architecture
&lt;/h2&gt;

&lt;p&gt;I've been organizing this work into five connected phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Goal Definition:&lt;/strong&gt; Define the required business outcome and acceptance criteria.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse Engineering:&lt;/strong&gt; Discover application behavior, states, dependencies, and constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Harness Construction:&lt;/strong&gt; Convert discovered knowledge into executable operational capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Execution:&lt;/strong&gt; Plan, operate, observe, verify, and recover.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal Evaluation:&lt;/strong&gt; Determine whether the business outcome has been achieved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The system architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
    G["Business Goal&amp;lt;br/&amp;gt;Acceptance Criteria"]
    A["AI Agent&amp;lt;br/&amp;gt;Claude Code / Codex"]

    subgraph H["Agent Harness"]
        direction TB
        E["Executable Operational Model&amp;lt;br/&amp;gt;States · Actions · Effects · Constraints"]
        P["Planner&amp;lt;br/&amp;gt;Strategy Selection"]
        R["Runtime&amp;lt;br/&amp;gt;Execution · Observation · Recovery"]
        V["Evaluator&amp;lt;br/&amp;gt;Business Rules · Regression"]
    end

    S["Existing Application&amp;lt;br/&amp;gt;GUI · Configuration · Metadata"]
    RE["Reverse Engineering&amp;lt;br/&amp;gt;Observe · Analyze · Validate"]

    G --&amp;gt; A
    A --&amp;gt; E
    E --&amp;gt; P
    P --&amp;gt; R
    R --&amp;gt; S
    S --&amp;gt; RE
    RE --&amp;gt; E
    R --&amp;gt; V
    V --&amp;gt; G&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The four engineering disciplines are not separate systems. They represent different responsibilities within this process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reverse Engineering&lt;/strong&gt; discovers and validates application behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Harness Engineering&lt;/strong&gt; organizes that knowledge into reusable capabilities and controls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operations Research&lt;/strong&gt; supports action selection under cost, risk, and operational constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime Engineering&lt;/strong&gt; handles reliable execution, state tracking, verification, and recovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key artifact connecting these activities is what I call an &lt;strong&gt;Executable Operational Model (EOM)&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. From Reverse Engineering to Executable Operational Knowledge
&lt;/h2&gt;

&lt;p&gt;Traditional reverse engineering often produces documentation, design models, or recovered specifications.&lt;/p&gt;

&lt;p&gt;Here, the goal is different.&lt;/p&gt;

&lt;p&gt;The discovered knowledge must be usable by an AI agent during execution.&lt;/p&gt;

&lt;p&gt;For low-code applications, reverse engineering may involve GUI observation, operation recording, input/output comparison, state-transition analysis, and inspection of available metadata or generated code.&lt;/p&gt;

&lt;p&gt;For example, while exploring an approval workflow designer, the agent might discover that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A workflow must be unlocked before modification.&lt;/li&gt;
&lt;li&gt;Saving a change does not automatically activate it.&lt;/li&gt;
&lt;li&gt;Certain configuration changes affect dependent workflows.&lt;/li&gt;
&lt;li&gt;Validation errors become visible only after a specific operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These observations can be converted into structured operational knowledge.&lt;/p&gt;

&lt;p&gt;An EOM describes not only how to perform an operation, but also its expected effects, constraints, and verification conditions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;Current or inferred application state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;An operation available through a supported interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preconditions&lt;/td&gt;
&lt;td&gt;Conditions required before execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effects&lt;/td&gt;
&lt;td&gt;Expected changes resulting from the operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invariants&lt;/td&gt;
&lt;td&gt;Conditions that must remain true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification&lt;/td&gt;
&lt;td&gt;How actual effects are confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;How failures or uncertain outcomes are handled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confidence&lt;/td&gt;
&lt;td&gt;Whether knowledge is observed, hypothesized, or validated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Consider a workflow configuration operation:&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;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;update_approval_workflow&lt;/span&gt;

&lt;span class="na"&gt;preconditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;design_is_unlocked&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;user_has_permission&lt;/span&gt;

&lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;inspect_current_configuration&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;update_approval_rules&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;save_configuration&lt;/span&gt;

&lt;span class="na"&gt;expected_effects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;workflow_configuration_updated&lt;/span&gt;

&lt;span class="na"&gt;invariants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;existing_records_preserved&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;unrelated_workflows_unchanged&lt;/span&gt;

&lt;span class="na"&gt;verification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;reopen_configuration&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;compare_with_expected_rules&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run_workflow_tests&lt;/span&gt;

&lt;span class="na"&gt;recovery&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;inspect_actual_state&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;restore_previous_configuration_if_safe&lt;/span&gt;

&lt;span class="na"&gt;knowledge_status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;validated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simplified example, not a required schema.&lt;/p&gt;

&lt;p&gt;A conventional Skill may describe how to perform a task. The EOM provides the broader operational context: when actions are valid, how they change state, what must remain unchanged, and how correctness is established.&lt;/p&gt;

&lt;p&gt;In practice, the EOM does not need to exist as a single file or formal modeling engine. It can be distributed across Skills, configuration files, tools, state models, and test definitions.&lt;/p&gt;

&lt;p&gt;The important transformation is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reverse engineering discovers application behavior. Harness engineering converts that knowledge into executable operational capabilities.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Harness Engineering: Building the Execution Environment
&lt;/h2&gt;

&lt;p&gt;The harness connects the AI agent to the existing application.&lt;/p&gt;

&lt;p&gt;For Claude Code or Codex, it may include application instructions, Skills, GUI tools, CLI commands, MCP integrations, state inspection utilities, evaluators, and recovery procedures.&lt;/p&gt;

&lt;p&gt;These components serve different purposes.&lt;/p&gt;

&lt;p&gt;Instructions and Skills provide reusable operational knowledge. Tools expose supported application interfaces. State models and policies determine which actions are valid. Evaluators establish whether the intended results were achieved.&lt;/p&gt;

&lt;p&gt;The harness should also distinguish between observing an application and modifying it.&lt;/p&gt;

&lt;p&gt;For example, generated code or metadata may be useful for understanding structure and dependencies. However, directly modifying generated code may bypass a low-code platform's supported configuration mechanisms.&lt;/p&gt;

&lt;p&gt;In such systems, I prefer using code analysis for understanding and impact review while performing changes through the platform's supported design interfaces.&lt;/p&gt;

&lt;p&gt;The harness therefore becomes an application-specific engineering environment, rather than just a set of commands available to an LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Planning: Choosing What to Do and What to Investigate
&lt;/h2&gt;

&lt;p&gt;Once the agent has operational capabilities, it must decide how to use them.&lt;/p&gt;

&lt;p&gt;There may be several ways to reach the same goal.&lt;/p&gt;

&lt;p&gt;For example, changing approval rules might involve a known GUI procedure, a shorter but less-tested sequence, or a supported administrative interface.&lt;/p&gt;

&lt;p&gt;The shortest procedure is not always the best choice.&lt;/p&gt;

&lt;p&gt;Operations research provides useful concepts for selecting strategies under constraints.&lt;/p&gt;

&lt;p&gt;In practice, planning can consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected execution time and tool cost.&lt;/li&gt;
&lt;li&gt;Dependencies between operations.&lt;/li&gt;
&lt;li&gt;Reliability of previously observed procedures.&lt;/li&gt;
&lt;li&gt;Risk of unintended changes.&lt;/li&gt;
&lt;li&gt;Required permissions and approval boundaries.&lt;/li&gt;
&lt;li&gt;Uncertainty about the current application state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A known procedure may be preferable for production changes, while an unfamiliar but potentially faster approach may be worth exploring in a sandbox.&lt;/p&gt;

&lt;p&gt;There is also another decision: &lt;strong&gt;whether to act immediately or gather more information first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose the agent does not know whether saving a workflow also activates it.&lt;/p&gt;

&lt;p&gt;It could proceed based on an assumption, inspect the current configuration, or test the behavior in an isolated environment.&lt;/p&gt;

&lt;p&gt;Investigation has a cost, but it can reduce the risk of an incorrect change.&lt;/p&gt;

&lt;p&gt;This connects the approach to ideas such as value of information, exploration versus exploitation, and planning under partial observability.&lt;/p&gt;

&lt;p&gt;I do not assume that every implementation needs a mathematical optimizer or a POMDP solver. Dependency graphs, policy checks, heuristic scoring, and risk-based replanning are often more practical starting points.&lt;/p&gt;

&lt;p&gt;The important design principle is to separate responsibilities:&lt;/p&gt;

&lt;p&gt;The LLM interprets goals and reasons about unfamiliar situations. The EOM supplies application-specific knowledge. Planning logic selects feasible strategies, while policies enforce hard constraints.&lt;/p&gt;

&lt;p&gt;This makes action selection more explicit and easier to evaluate.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Runtime Engineering: Handling Uncertain Execution
&lt;/h2&gt;

&lt;p&gt;Even a well-planned operation can fail.&lt;/p&gt;

&lt;p&gt;GUI interfaces are often asynchronous, stateful, and difficult to control precisely.&lt;/p&gt;

&lt;p&gt;Consider a simple example.&lt;/p&gt;

&lt;p&gt;The agent updates an approval rule and clicks Save. The application times out.&lt;/p&gt;

&lt;p&gt;At that moment, the agent does not know whether the change failed, succeeded, or partially completed.&lt;/p&gt;

&lt;p&gt;Blindly repeating the operation may be unsafe.&lt;/p&gt;

&lt;p&gt;This illustrates a fundamental distinction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Action completed ≠ State changed ≠ Business goal achieved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A reliable runtime needs to handle these as separate conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Execution state and checkpoints
&lt;/h3&gt;

&lt;p&gt;The runtime should record the intended action, application state before execution, observed result, and subsequent verification.&lt;/p&gt;

&lt;p&gt;If execution is interrupted, the agent should be able to determine what has already happened before continuing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Effect reconciliation
&lt;/h3&gt;

&lt;p&gt;When an operation produces an uncertain result, the runtime should inspect the actual application state before retrying.&lt;/p&gt;

&lt;p&gt;For example, after a save timeout, it may reopen the workflow configuration and compare the stored values against the intended changes.&lt;/p&gt;

&lt;p&gt;The principle is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observe the actual state before repeating an uncertain operation.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovery and compensation
&lt;/h3&gt;

&lt;p&gt;GUI-driven changes may not support atomic transactions or reliable rollback.&lt;/p&gt;

&lt;p&gt;Recovery may require compensating operations, such as restoring a previous configuration through the supported interface.&lt;/p&gt;

&lt;p&gt;Such recovery must also be verified, since compensation is not necessarily equivalent to reverting a database transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approval boundaries
&lt;/h3&gt;

&lt;p&gt;Not every operation should be fully autonomous.&lt;/p&gt;

&lt;p&gt;Read-only inspection and sandbox exploration may require little supervision. Production configuration changes, destructive operations, or irreversible actions may require explicit human approval.&lt;/p&gt;

&lt;p&gt;The runtime must enforce these boundaries rather than relying on the LLM to remember them.&lt;/p&gt;

&lt;p&gt;Together, these mechanisms provide the reliability needed for application engineering through existing interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. A Practical Example: Extending a Low-Code Application
&lt;/h2&gt;

&lt;p&gt;To see how the components fit together, consider adding a new approval workflow to an existing order-management application.&lt;/p&gt;

&lt;p&gt;This is an illustrative scenario, not a claim of measured experimental results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Define the goal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The new workflow must allow authorized users to submit orders for approval, apply routing rules, preserve approval history, and avoid breaking existing order processing.&lt;/p&gt;

&lt;p&gt;These become explicit acceptance criteria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Discover the application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The agent inspects the existing forms, data objects, workflow designer, and approval settings.&lt;/p&gt;

&lt;p&gt;Through controlled operations, it identifies relevant dependencies and discovers that workflows must be unlocked before editing and separately activated after saving.&lt;/p&gt;

&lt;p&gt;These findings are recorded with their validation status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Update the EOM and harness&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The discovered operations become reusable procedures.&lt;/p&gt;

&lt;p&gt;The harness records editing prerequisites, expected configuration changes, validation steps, and recovery options.&lt;/p&gt;

&lt;p&gt;It also provides tools to inspect the current workflow state and compare configurations before and after modification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Plan and execute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The agent selects a modification sequence based on dependencies, known procedures, and operational constraints.&lt;/p&gt;

&lt;p&gt;It uses the low-code designer to create or update the required workflow.&lt;/p&gt;

&lt;p&gt;After each significant change, the runtime checks whether the expected state was reached.&lt;/p&gt;

&lt;p&gt;If an operation fails or produces an uncertain result, the agent reconciles the actual state before retrying or replanning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Evaluate the business outcome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The evaluator checks whether approval routing works, permissions are enforced, approval history is retained, and existing order-processing tests still pass.&lt;/p&gt;

&lt;p&gt;If a test fails, the agent investigates the difference between expected and observed behavior.&lt;/p&gt;

&lt;p&gt;Newly discovered constraints or successful recovery procedures can then be proposed as improvements to the harness.&lt;/p&gt;

&lt;p&gt;The artifacts produced at each step are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Engineering artifact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Goal Definition&lt;/td&gt;
&lt;td&gt;Business acceptance criteria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reverse Engineering&lt;/td&gt;
&lt;td&gt;Observations, state knowledge, dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Harness Construction&lt;/td&gt;
&lt;td&gt;Operational model, Skills, policies, evaluators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution&lt;/td&gt;
&lt;td&gt;Action history, state evidence, recovery records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation&lt;/td&gt;
&lt;td&gt;Test results and validated improvement candidates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is what makes the approach more than GUI automation.&lt;/p&gt;

&lt;p&gt;The agent is not following a fixed script. It is performing application engineering using accumulated operational knowledge, feedback, and explicit verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Continuous Improvement of the Harness
&lt;/h2&gt;

&lt;p&gt;Reverse engineering does not end when the initial harness is built.&lt;/p&gt;

&lt;p&gt;Every execution can reveal new information.&lt;/p&gt;

&lt;p&gt;A failed operation may expose an unknown precondition. An unexpected configuration state may reveal a missing dependency. A more reliable procedure may emerge from repeated execution.&lt;/p&gt;

&lt;p&gt;These findings can improve the EOM, Skills, evaluators, and recovery logic.&lt;/p&gt;

&lt;p&gt;However, learning must be controlled.&lt;/p&gt;

&lt;p&gt;An observed behavior should not automatically become a business rule. A successful workaround should not immediately replace a validated procedure.&lt;/p&gt;

&lt;p&gt;Changes to operational knowledge need evidence, validation, versioning, and appropriate review.&lt;/p&gt;

&lt;p&gt;This is particularly important when the harness supports application modifications rather than read-only operations.&lt;/p&gt;

&lt;p&gt;The central idea is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The harness is not merely built from reverse engineering. It becomes the mechanism through which reverse engineering continues.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Over time, this can make application-specific knowledge reusable across tasks and agent sessions instead of requiring the agent to rediscover everything from the GUI.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Scope, Limitations, and Evaluation
&lt;/h2&gt;

&lt;p&gt;The framework primarily targets three kinds of work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Operation:&lt;/strong&gt; Using existing application functions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration:&lt;/strong&gt; Modifying supported settings and workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extension:&lt;/strong&gt; Building new functionality through existing design interfaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does not require rewriting the application's implementation. However, it cannot create functionality that the underlying platform does not support.&lt;/p&gt;

&lt;p&gt;Several limitations remain.&lt;/p&gt;

&lt;p&gt;GUI observation provides only a partial view of application behavior. Interface changes can invalidate previously discovered procedures. Some operations are difficult to make idempotent, and business correctness may require domain experts or independent test systems.&lt;/p&gt;

&lt;p&gt;The approach also introduces an initial engineering cost: discovering application behavior, defining operational knowledge, building tools, and implementing evaluators.&lt;/p&gt;

&lt;p&gt;Whether this investment produces a net benefit depends on how frequently the harness is reused and how effectively it improves execution.&lt;/p&gt;

&lt;p&gt;A useful evaluation would compare three configurations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A general-purpose GUI agent.&lt;/li&gt;
&lt;li&gt;A GUI agent with manually defined Skills.&lt;/li&gt;
&lt;li&gt;An agent using discovered operational knowledge, constrained planning, and a reliability-oriented harness.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Relevant metrics include goal completion rate, acceptance-criteria coverage, recovery success, regression violations, execution cost, and adaptation effort after application changes.&lt;/p&gt;

&lt;p&gt;Such comparisons are needed to quantify the benefits. The architecture itself does not establish performance improvements.&lt;/p&gt;

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

&lt;p&gt;AI-driven modernization does not always need to begin with rewriting existing code.&lt;/p&gt;

&lt;p&gt;For many applications, another useful direction is to build the knowledge and execution environment that allows AI agents to operate and extend them through supported interfaces.&lt;/p&gt;

&lt;p&gt;The approach I've been applying connects four engineering concerns:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reverse Engineering&lt;/strong&gt; discovers application behavior and constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Harness Engineering&lt;/strong&gt; converts that knowledge into reusable operational capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operations Research&lt;/strong&gt; supports decisions about which actions to take and when to gather more information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime Engineering&lt;/strong&gt; provides reliable execution, state verification, and recovery.&lt;/p&gt;

&lt;p&gt;The common foundation is an Executable Operational Model: a reusable representation of application states, operations, expected effects, constraints, and verification procedures.&lt;/p&gt;

&lt;p&gt;The most important change is not simply that an AI agent can interact with an existing application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is that knowledge discovered from the application becomes an engineering asset that can guide future operations, support application changes, and improve through verified execution.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That creates another path for evolving existing systems: not necessarily by replacing their implementation, but by engineering how AI agents can understand, develop, and operate them.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>legacy</category>
    </item>
    <item>
      <title>Code as a Model of the Current Spec: Declarative Models, IRs, and Graphs for AI Coding</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Fri, 09 Oct 2026 09:45:09 +0000</pubDate>
      <link>https://dev.to/gyu07/code-as-a-model-of-the-current-spec-declarative-models-irs-and-graphs-for-ai-coding-4ego</link>
      <guid>https://dev.to/gyu07/code-as-a-model-of-the-current-spec-declarative-models-irs-and-graphs-for-ai-coding-4ego</guid>
      <description>&lt;p&gt;I am putting this design direction into practice and evaluating it in medium-sized and larger repositories.&lt;/p&gt;

&lt;p&gt;Database and infrastructure models, along with verification mechanisms, are already implemented in our tooling. UI/API models and cross-domain composition of migration phases are the next direction.&lt;/p&gt;

&lt;p&gt;I currently use a custom harness for development, including database changes. I also use Drizzle in some projects. Across both approaches, I keep coming back to the same friction: a coding agent can produce a locally reasonable change without giving enough attention to the shape of the system as a whole. Accumulating migrations is one place where that becomes visible.&lt;/p&gt;

&lt;p&gt;My impression is that newer agents are much better at this than they were a year ago. But the architectural question remains.&lt;/p&gt;

&lt;p&gt;How do we make the repository express the system well enough that an agent can understand what a change must preserve?&lt;/p&gt;

&lt;p&gt;My target is simple to state:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make code the best available model of the current specification. Derive intermediate representations from it so changes can be analyzed, rather than judged from text alone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That applies to UI, API, workflow, database, and infrastructure together. Consider a rule as simple as “after account deactivation, no new billing operation may begin.” Preserving it during a schema change can require agreement across all five domains. I will use that example throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repository should explain the system as it is
&lt;/h2&gt;

&lt;p&gt;When an agent opens a repository, it should be able to discover the current business concepts, responsibilities, constraints, and dependencies from its structure.&lt;/p&gt;

&lt;p&gt;A billing decision hidden inside a generic utility function is harder to understand than a named policy at the billing boundary. A workflow assembled from scattered callbacks is harder to inspect than explicit states and transitions. A permission enforced inconsistently across handlers is harder to reason about than a clear authorization boundary.&lt;/p&gt;

&lt;p&gt;The ideal is not to maintain another specification document alongside the implementation. It is to make the implementation's structure carry as much of the specification as possible.&lt;/p&gt;

&lt;p&gt;Names, types, module boundaries, contracts, constraints, and transitions all contribute. Comments should explain the reasons that those structures cannot express: why a boundary exists, why an exception is necessary, or which external assumption a decision relies on.&lt;/p&gt;

&lt;p&gt;This does not mean code can recover every human intention. It means we should reduce the amount of intention that an agent has to guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current state and change history have different jobs
&lt;/h2&gt;

&lt;p&gt;Drizzle already combines a declarative schema with incremental migrations. Its &lt;code&gt;generate&lt;/code&gt; command builds a schema snapshot and compares it with the previous snapshot to generate SQL. Declarative state and migrations are therefore compatible, not competing approaches. See the &lt;a href="https://orm.drizzle.team/docs/drizzle-kit-generate" rel="noopener noreferrer"&gt;Drizzle documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The current schema tells us what structure we want. A change also needs to explain how existing data should reach that structure.&lt;/p&gt;

&lt;p&gt;Two snapshots cannot fully determine that meaning. A removed column and an added column might represent a rename, a replacement, or a change in the underlying concept. Drizzle’s documented generation flow prompts the developer for renames when necessary. The prompt supplies information the structural diff cannot decide. A backfill similarly requires a rule for interpreting existing rows.&lt;/p&gt;

&lt;p&gt;I call this &lt;strong&gt;change meaning&lt;/strong&gt;: information that cannot be recovered from the final state, including rename intent, backfill rules, and cutover conditions. It belongs in the change artifact—the migration or saved plan—while current behavior belongs in the source code.&lt;/p&gt;

&lt;p&gt;The repository should make the current specification legible, while the change should retain the meaning that cannot be reconstructed from the final state.&lt;/p&gt;

&lt;p&gt;History still matters. It should not be the only way to understand the present.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declare the system across its boundaries
&lt;/h2&gt;

&lt;p&gt;Declarative code makes important relationships available for inspection. Each domain has different things to declare.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;What to express&lt;/th&gt;
&lt;th&gt;What should become legible&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;View states, input rules, available actions&lt;/td&gt;
&lt;td&gt;What users can understand and do&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;Inputs, outputs, authorization, errors&lt;/td&gt;
&lt;td&gt;The contract an operation offers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow&lt;/td&gt;
&lt;td&gt;States, events, guards, retries, compensation&lt;/td&gt;
&lt;td&gt;Allowed execution and recovery paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Schema, constraints, access rules&lt;/td&gt;
&lt;td&gt;Stored facts and rejected inconsistencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;Resources, permissions, connections&lt;/td&gt;
&lt;td&gt;The execution environment and its boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These declarations must agree. A disabled button does not enforce authorization. An API response does not prove a queued operation has completed. A database constraint does not establish that an external payment request was never sent.&lt;/p&gt;

&lt;p&gt;The architectural value comes from expressing the relationships between these boundaries clearly enough to inspect them.&lt;/p&gt;

&lt;h2&gt;
  
  
  IR makes the declarations analyzable
&lt;/h2&gt;

&lt;p&gt;Readable source helps an agent understand the system. An intermediate representation, or IR, helps tools compute properties of that system.&lt;/p&gt;

&lt;p&gt;For this design, I would derive domain-specific IRs from the source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A schema IR for database objects and constraints.&lt;/li&gt;
&lt;li&gt;A configuration IR for infrastructure resources and dependencies.&lt;/li&gt;
&lt;li&gt;A machine IR for workflow states and transitions.&lt;/li&gt;
&lt;li&gt;Contract and view models for API and UI relationships.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would keep each domain's semantics intact. Database locks, infrastructure replacement, and workflow reachability need different analyses. Flattening them into one universal schema risks losing the details that make those analyses useful.&lt;/p&gt;

&lt;p&gt;Cross-domain analysis can follow contracts, references, and dependencies already expressed in code. Where a relationship cannot be derived, it needs an explicit representation close to the relevant code. It does not require a separate specification registry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An IR is not the state space itself. It is a representation from which we can describe and analyze states, constraints, and transitions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The business rule needs an explicit expression in code as well. For billing, that might be a named eligibility policy, a guard that invokes it, and a property test defining what deactivation means for pending work. An analyzer can then check whether relevant execution paths use that policy and whether a change invalidates its dependencies. An independent structural oracle checks fidelity to the database; the executable rule and its tests provide a different criterion for business behavior. Neither establishes that the chosen rule matches human intent: its initial definition and substantive changes still require domain judgment. &lt;/p&gt;

&lt;p&gt;Terraform provides an existing example of machine-readable change information: &lt;a href="https://developer.hashicorp.com/terraform/internals/json-format" rel="noopener noreferrer"&gt;plan and state JSON&lt;/a&gt;. It also supports &lt;a href="https://developer.hashicorp.com/terraform/language/validate" rel="noopener noreferrer"&gt;validation conditions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphs expose dependencies; DAGs constrain change order
&lt;/h2&gt;

&lt;p&gt;In a database, a schema IR can support a dependency graph: which views, constraints, or other objects depend on which definitions?&lt;/p&gt;

&lt;p&gt;A migration planner can also construct a directed acyclic graph of operations. Adding a column may precede a backfill; the backfill may precede validation; validation may precede switching readers.&lt;/p&gt;

&lt;p&gt;These are different graphs. Database dependencies can contain cycles, such as two tables with foreign keys referencing each other. An executable operation DAG represents precedence constraints, and a valid ordering still does not prove that the migration preserves business meaning.&lt;/p&gt;

&lt;p&gt;The useful progression is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Representation&lt;/th&gt;
&lt;th&gt;Question it helps answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Declarative source&lt;/td&gt;
&lt;td&gt;What should exist, and what rules are visible?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain IR&lt;/td&gt;
&lt;td&gt;What structure and semantics can tools inspect?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency graph&lt;/td&gt;
&lt;td&gt;What depends on this change?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operation DAG&lt;/td&gt;
&lt;td&gt;What must happen before what?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checks and observations&lt;/td&gt;
&lt;td&gt;Which properties were actually tested or enforced?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This gives an agent more than a sequence of SQL statements. It gives the agent a basis for explaining and checking a plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  The difficult case is the transition
&lt;/h2&gt;

&lt;p&gt;Return to the billing rule: after an account is deactivated, no new billing operation may begin.&lt;/p&gt;

&lt;p&gt;For this example, &lt;strong&gt;begin means committing a durable authorization to perform a particular billing operation in the database&lt;/strong&gt;. Deactivation means committing the account's disabled state. An operation authorized before deactivation may still be sent to the payment provider afterward. That is a deliberate rule, not a guarantee that no external request occurs after deactivation.&lt;/p&gt;

&lt;p&gt;A guard alone is insufficient. A worker can read an enabled account, another transaction can deactivate it, and the worker can then send a payment request. A normal PostgreSQL Read Committed &lt;code&gt;SELECT&lt;/code&gt; does not protect that interval; see the &lt;a href="https://www.postgresql.org/docs/current/transaction-iso.html" rel="noopener noreferrer"&gt;transaction isolation documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A possible protocol serializes both operations on the same account row. In a billing transaction, acquire the row lock, read eligibility, and insert a durable authorization with a unique operation key before committing. The deactivation transaction takes the same lock before changing eligibility. All authorization paths must follow this protocol. A retry with an existing operation key resumes the committed authorization through a separate path, without creating a new one or reapplying the new-authorization eligibility condition. It must not create a fresh authorization after deactivation. External dispatch occurs only for committed authorizations and needs its own retry and idempotency contract.&lt;/p&gt;

&lt;p&gt;This identifies the properties an analyzer would need to model:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Preconditions&lt;/th&gt;
&lt;th&gt;Conditions maintained during execution&lt;/th&gt;
&lt;th&gt;Postconditions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create a new billing authorization&lt;/td&gt;
&lt;td&gt;Account lock acquired; account enabled&lt;/td&gt;
&lt;td&gt;Lock held through eligibility check and authorization commit&lt;/td&gt;
&lt;td&gt;Durable authorization exists for this operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deactivate account&lt;/td&gt;
&lt;td&gt;Same account lock acquired&lt;/td&gt;
&lt;td&gt;Lock held through disabling commit&lt;/td&gt;
&lt;td&gt;No later authorization may be created while disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dispatch payment&lt;/td&gt;
&lt;td&gt;Committed authorization exists&lt;/td&gt;
&lt;td&gt;Retry identifies the same operation&lt;/td&gt;
&lt;td&gt;External result recorded, or outcome remains unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A trace checker can look for an authorization commit after a deactivation commit, while the account remains disabled. It needs records that reliably reconstruct order for that account, not merely application-log timestamps; its finding applies to observed executions, not all possible executions. Static analysis can flag an authorization path that bypasses the shared protocol.&lt;/p&gt;

&lt;p&gt;Now migrate the boolean &lt;code&gt;is_deactivated&lt;/code&gt; to a representation that separates account status from deactivation time: &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;deactivated_at&lt;/code&gt;. A true legacy value becomes &lt;code&gt;status = disabled&lt;/code&gt; with &lt;code&gt;deactivated_at = null&lt;/code&gt;, meaning disabled with an unknown historical time. A false value becomes &lt;code&gt;status = enabled&lt;/code&gt; with no deactivation time. New deactivations record a timestamp. Eligibility depends on status; treating a null timestamp as enabled would incorrectly re-enable legacy accounts. These backfill rules belong in the change artifact.&lt;/p&gt;

&lt;p&gt;During the transition, an old application may write only &lt;code&gt;is_deactivated&lt;/code&gt; while a new billing worker reads only &lt;code&gt;status&lt;/code&gt;. Both versions can be individually plausible, yet their combination can bill a deactivated account.&lt;/p&gt;

&lt;p&gt;Later, removing the old column may break old jobs still waiting in the queue. Depending on error handling, they might fail safely or interpret missing information incorrectly. Sending a payment request introduces an external side effect that cannot be undone merely by rolling back the schema.&lt;/p&gt;

&lt;p&gt;The plan therefore needs to consider application versions, workflow versions, schema phases, and queued work together.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Example condition to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Expand&lt;/td&gt;
&lt;td&gt;Existing readers and writers remain compatible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backfill and synchronization&lt;/td&gt;
&lt;td&gt;Both representations preserve the intended meaning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cutover&lt;/td&gt;
&lt;td&gt;New readers receive correct data, including concurrent updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drain or upgrade old work&lt;/td&gt;
&lt;td&gt;Queued jobs retain valid execution semantics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contract&lt;/td&gt;
&lt;td&gt;No remaining supported execution requires the removed structure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The exact mechanism might be dual writes, a trigger, compatibility code, or another protocol. The important point is to make its assumptions and ordering visible.&lt;/p&gt;

&lt;p&gt;Existing tools address parts of this problem. &lt;a href="https://github.com/xataio/pgroll" rel="noopener noreferrer"&gt;pgroll&lt;/a&gt; uses versioned schema views and triggers to support concurrent schema versions during PostgreSQL migrations. &lt;a href="https://docs.temporal.io/production-deployment/worker-deployments/worker-versioning" rel="noopener noreferrer"&gt;Temporal Worker Versioning&lt;/a&gt; addresses the relationship between workflow executions and worker versions. &lt;a href="https://atlasgo.io/versioned/lint" rel="noopener noreferrer"&gt;Atlas migration lint&lt;/a&gt; analyzes migration safety. These are useful precedents; connecting the obligations across domains remains the architectural task.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete architecture: domain compilers and a thin linking layer
&lt;/h2&gt;

&lt;p&gt;The architecture follows two paths: compile declarations into domain models, then connect those models through relationships already expressed in code.&lt;/p&gt;

&lt;p&gt;Each domain adapter parses and resolves its declarations into a typed IR. IR nodes retain source locations so a diagnostic can point back to the code an agent needs to change. References resolve to program symbols and artifacts.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    U["View and Contract IR: deactivateAccount"] --&amp;gt; D["Deactivate: lock account, update status, commit"]
    N["Machine IR: create new authorization"] --&amp;gt; C["Eligibility check under the same account lock"]
    C --&amp;gt; A["Schema IR: committed billing authorization"]
    D --&amp;gt; S["Schema IR: account status and deactivation time"]
    S --&amp;gt;|read under lock| C
    A --&amp;gt; P["Machine IR: dispatch committed authorization"]
    R["Retry: existing operation key"] --&amp;gt;|resume existing authorization| P
    F["Config IR: worker and queue"] --&amp;gt;|hosts| P
    P -.-&amp;gt; X["External payment service"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The graph connects domain-owned models while making the protocol visible: new authorization checks eligibility under the same account lock used by deactivation, and dispatch consumes a committed authorization. A retry resumes that authorization rather than creating another. These edges identify obligations for the analyzers; drawing them does not prove they are enforced. The dotted payment edge requires an external-effect contract.&lt;/p&gt;

&lt;p&gt;Reference resolution distinguishes definite edges, conservative sets of possible targets, explicit library contracts, and unresolved references. Possible edges are useful for conservative analysis but must not be presented as confirmed calls. Missing information is not evidence of safety.&lt;/p&gt;

&lt;p&gt;The graph supports impact analysis. Temporal correctness needs an additional contract layer, close to the relevant code: transaction boundaries, commit points, synchronization resources, and the ordering of external effects.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Domain adapter&lt;/td&gt;
&lt;td&gt;Preserve domain semantics, source locations, and analysis limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linker&lt;/td&gt;
&lt;td&gt;Resolve references and artifact versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain analyzer&lt;/td&gt;
&lt;td&gt;Evaluate local properties and report the assumptions they require&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composer&lt;/td&gt;
&lt;td&gt;Connect guarantees to assumptions and check interference between operations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For billing, the composer must establish that both paths use the same account lock, that eligibility is read under that lock, and that authorization commits before external dispatch. If another path can change eligibility or create authorization outside the protocol, the local guarantee does not compose. Where the available model cannot establish these facts, the result is unknown. Thin reference linking remains thin; concurrency analysis is a separate responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  From IRs to a change plan and runtime evidence
&lt;/h2&gt;

&lt;p&gt;Planning needs three distinct inputs: the candidate model, models of old artifacts still supported, and evidence or deployment contracts identifying what can run or resume. Retain generated IRs and manifests for supported builds, including workflow versions. Deleting an old worker from the current checkout does not erase its dependencies while that artifact can still execute.&lt;/p&gt;

&lt;p&gt;Observations remain separate from declarations and carry their origin and acquisition time. These generated models retain the semantics of supported builds.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    P["Plan: operation DAG and phase conditions"] --&amp;gt; V["Verify: compatibility, ordering and gaps"]
    V --&amp;gt; G["Gate: bind evidence to plan and recheck prerequisites"]
    G --&amp;gt; E["Execute: domain operations"]
    E --&amp;gt; O["Observe: actual state and execution traces"]
    O --&amp;gt; A["Adjudicate: repair, accept or bound an exception"]
    A -.-&amp;gt; P&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The composer adds cross-domain precedence and interference conditions to local plans. Before removing the old field, two conditions must hold: no new work requiring it can be admitted, and no accepted work can execute or resume with that dependency. Depending on the runtime, this includes running jobs, delayed jobs, retries, dead-letter replay, and suspended workflows.&lt;/p&gt;

&lt;p&gt;One proposed protocol installs a durable version-admission fence, stops old producers, and retires or upgrades every old dependent execution. Scheduling, replay, and resume paths must obey the same fence. The fence remains in force through contract and prevents old artifacts from returning afterward. A gate checks the fence and retirement evidence before removal; rechecking queue depth alone cannot close the race. If the runtime cannot enforce this protocol, the prerequisite remains unknown.&lt;/p&gt;

&lt;p&gt;Evidence needs a reproducible verification identity: the exact plan, source revision, input-model digests, and verification conditions, including the analyzer version. A fingerprint over that bundle binds a result to what was actually checked. It does not freeze the environment: observations also carry their acquisition time, and execution gates recheck relevant runtime assumptions. Observations feed verification and adjudication; they do not automatically rewrite the authoritative source.&lt;/p&gt;

&lt;p&gt;An agent-facing interface would expose affected source locations, dependency paths, candidate operations, failed conditions, and unknowns. That gives the agent actionable evidence for a code change without asking it to reconstruct the entire architecture from logs.&lt;/p&gt;

&lt;p&gt;For example, a declaration change that removes &lt;code&gt;accounts.is_deactivated&lt;/code&gt; would remove that field from the candidate Schema IR. Resolving the retained IR of the supported v1 worker against the candidate schema would produce a missing dependency—even if its source was deleted from the checkout. The contract-phase check separately needs evidence for admission fencing and retirement of old dependent executions.&lt;/p&gt;

&lt;p&gt;An illustrative diagnostic can be presented as a table. This is a proposed result, not captured output from the harness.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Proposed operation&lt;/th&gt;
&lt;th&gt;Evidence or condition&lt;/th&gt;
&lt;th&gt;Analysis result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remove &lt;code&gt;accounts.is_deactivated&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Retained &lt;code&gt;billing-worker:v1&lt;/code&gt; model reads the field at &lt;code&gt;src/workers/billing-v1.ts:42&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Violated: incompatible supported reader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enter contract phase&lt;/td&gt;
&lt;td&gt;New admission of old dependent work is fenced&lt;/td&gt;
&lt;td&gt;Unknown: enforcement evidence missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enter contract phase&lt;/td&gt;
&lt;td&gt;Accepted old dependent work cannot execute or resume&lt;/td&gt;
&lt;td&gt;Unknown: retirement evidence missing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Execution decision: block removal.&lt;/strong&gt; The analysis distinguishes violations from missing evidence; the destructive-operation policy determines the decision. An exception would be an explicit policy decision, not a verified result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification needs a scope
&lt;/h2&gt;

&lt;p&gt;A database constraint, a workflow guard, a test, and an alert do different jobs.&lt;/p&gt;

&lt;p&gt;A constraint rejects invalid states within its scope. A guard controls operations that pass through it. Tests check the cases they execute. Monitoring detects what its instrumentation can observe.&lt;/p&gt;

&lt;p&gt;Calling all of these “verified” hides important differences. A result should state what property was checked, against which evidence, under which assumptions, and for which plan or code version.&lt;/p&gt;

&lt;p&gt;An IR also cannot serve as its own sole oracle. If generation and validation share the same lossy transformation, they can agree while omitting the same behavior.&lt;/p&gt;

&lt;p&gt;We encountered this in the database harness: a convergence check could report agreement when generation and verification symmetrically dropped information. A separate PostgreSQL-backed structural oracle helped reduce that blind spot. The lesson was specific: agreement after a shared transformation was weaker evidence than it appeared.&lt;/p&gt;

&lt;p&gt;We also found declarations that existed in configuration but were not wired into enforcement. A declared policy can give an agent false confidence when its implementation does nothing. Checks for declaration-to-enforcement mismatches, together with deliberately faulty implementations, test whether the mechanism is actually connected. Neither an impressive declaration nor a linked test is enough on its own.&lt;/p&gt;

&lt;p&gt;When actual behavior diverges from the declared model, the response requires judgment: restore the intended behavior, accept a corrected design, or record a bounded exception. A production hotfix may be valid, but observed behavior should not silently redefine the specification.&lt;/p&gt;

&lt;h2&gt;
  
  
  The claim about AI is still a hypothesis
&lt;/h2&gt;

&lt;p&gt;The database and infrastructure models, scoped verification, and plan-bound evidence have concrete implementations in our tooling. The full architecture above—including UI/API models and cross-domain phase composition—is the direction I am working toward. Existing mechanisms and operational lessons do not yet establish a general benefit for AI coding.&lt;/p&gt;

&lt;p&gt;My hypothesis is that code with explicit semantics, combined with derived analysis, reduces the context an agent must reconstruct and the assumptions it must invent.&lt;/p&gt;

&lt;p&gt;Use matched change tasks with seeded violations, compatibility traps, and cross-domain dependencies. Compare a strong baseline—source, type checking, lint, tests, and existing migration analysis—with the same setup plus derived cross-domain analysis. Keep the model and budget fixed, repeat runs, and use held-out repositories and tasks. Separate changes to declaration structure from added tooling; this evaluates the analysis system, not IR in isolation.&lt;/p&gt;

&lt;p&gt;Measure detection, false positives, correct implementations, repair iterations, and maintenance cost. Judge both groups against independent expected outcomes, rather than the analyzer's own finding count.&lt;/p&gt;

&lt;p&gt;Counting declarations alone would miss the point. The model must help an agent understand and preserve behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make the current specification readable in code. Make its structure analyzable through IRs and graphs. Then use that analysis to check both the destination and the path of a change.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the design direction I want for large systems built with coding agents.&lt;/p&gt;

</description>
      <category>harnessengineering</category>
      <category>agenticai</category>
      <category>dsl</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Where Agent Runtime Engineering Ends, Domain Runtime Engineering Begins</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Wed, 30 Sep 2026 04:38:34 +0000</pubDate>
      <link>https://dev.to/gyu07/where-agent-runtime-engineering-ends-domain-runtime-engineering-begins-55m0</link>
      <guid>https://dev.to/gyu07/where-agent-runtime-engineering-ends-domain-runtime-engineering-begins-55m0</guid>
      <description>&lt;p&gt;Claude Code, Codex, and other agent runtimes are becoming capable enough that we increasingly don't need to build the agent loop ourselves.&lt;/p&gt;

&lt;p&gt;Yet in client work, the engineering hasn't disappeared. It has moved toward MCP servers, APIs, DSLs, domain tools, state management, authorization, execution guarantees, and the systems agents operate.&lt;/p&gt;

&lt;p&gt;This made me rethink what we are actually building.&lt;/p&gt;

&lt;p&gt;I find it useful to separate two responsibilities: &lt;strong&gt;Agent Runtime Engineering&lt;/strong&gt; and what I'll call &lt;strong&gt;Domain Runtime Engineering&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Agent Runtime manages how the agent pursues a goal.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The Domain Runtime gives its operations precise meaning and enforceable guarantees.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Domain Runtime" is not a standardized industry term here.&lt;/p&gt;

&lt;p&gt;I'm using it as a convenient name for the application services, workflow engines, compilers, validators, rules, calculations, and transaction logic that execute operations according to domain semantics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two runtimes, two responsibilities
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;Agent Runtime&lt;/strong&gt; enables an AI agent to continue working toward a goal.&lt;/p&gt;

&lt;p&gt;It manages model calls, context, tool selection, observations, execution progress, interruption, resumption, and sometimes runtime-level approvals.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Domain Runtime&lt;/strong&gt; executes operations according to domain semantics.&lt;/p&gt;

&lt;p&gt;It determines whether inputs are valid, how specialized calculations behave, which invariants apply, and—where applicable—whether an operation may produce an authoritative state change.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Agent Runtime&lt;/th&gt;
&lt;th&gt;Domain Runtime&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Central question&lt;/td&gt;
&lt;td&gt;What should I do next to achieve the goal?&lt;/td&gt;
&lt;td&gt;What does this operation mean, and how should it execute?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical state&lt;/td&gt;
&lt;td&gt;Conversation, plans, observations, run progress&lt;/td&gt;
&lt;td&gt;Domain data, versions, approvals, operation results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Success&lt;/td&gt;
&lt;td&gt;The requested task is satisfied&lt;/td&gt;
&lt;td&gt;Domain postconditions hold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure handling&lt;/td&gt;
&lt;td&gt;Replan, investigate, try another path&lt;/td&gt;
&lt;td&gt;Validation, rollback, idempotency, compensation, reconciliation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changes when&lt;/td&gt;
&lt;td&gt;Models, prompts, tools, harnesses change&lt;/td&gt;
&lt;td&gt;Domain rules, contracts, algorithms, operating requirements change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I would not draw this boundary as &lt;strong&gt;probabilistic versus deterministic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Agent runtimes contain deterministic control logic, and domain processing may itself use AI. The stronger distinction is &lt;strong&gt;who owns domain semantics, invariants, and authoritative outcomes&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain Runtime does not only mean state changes
&lt;/h2&gt;

&lt;p&gt;Consider a facility analytics system.&lt;/p&gt;

&lt;p&gt;The user asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare occupancy rates across these buildings and investigate the outliers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Agent Runtime decides what data to inspect, which analysis to run, whether the result is sufficient, and what additional question to investigate.&lt;/p&gt;

&lt;p&gt;The Domain Runtime resolves &lt;code&gt;occupancy_rate&lt;/code&gt; against an accepted domain definition and executes it according to that definition.&lt;/p&gt;

&lt;p&gt;That definition might ultimately evaluate something like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;but the formula alone is not the domain meaning.&lt;/p&gt;

&lt;p&gt;The definition may also specify aggregation granularity, missing-value behavior, unit conversion, eligibility rules, and what happens when &lt;code&gt;leasable_area&lt;/code&gt; is zero.&lt;/p&gt;

&lt;p&gt;No database mutation is required.&lt;/p&gt;

&lt;p&gt;The Domain Runtime's job is to produce a valid result according to accepted domain semantics. The Agent Runtime uses that result to decide what to do next.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Runtime
    │
    │ "calculate occupancy by building"
    ▼
Domain Runtime
    │
    │ resolves and applies
    │ versioned domain semantics
    ▼
Valid domain result
    │
    ▼
Agent Runtime
    │
    └─ decides what to investigate next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those domain definitions do not necessarily have to be handwritten by developers.&lt;/p&gt;

&lt;p&gt;An agent may propose a new metric or modify an existing definition, but that proposal does not automatically make it authoritative. Validation, review, activation, and execution remain governed application responsibilities.&lt;/p&gt;

&lt;p&gt;The runtime can validate and execute an explicit domain definition.&lt;/p&gt;

&lt;p&gt;That alone does not establish that the definition correctly represents the real business.&lt;/p&gt;

&lt;p&gt;This distinction matters because an LLM can calculate a ratio itself.&lt;/p&gt;

&lt;p&gt;What makes the calculation part of the application is not arithmetic. It is the contract around what the calculation means.&lt;/p&gt;

&lt;h2&gt;
  
  
  State changes make the boundary even clearer
&lt;/h2&gt;

&lt;p&gt;Now suppose the user says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Analyze this dataset and publish the result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Agent Runtime can inspect the data, run analysis tools, identify problems, revise its approach, and eventually determine that it is ready to publish.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;publish&lt;/code&gt; is not merely another reasoning step.&lt;/p&gt;

&lt;p&gt;The domain may need to determine which version is being published, whether it is valid, whether the caller is authorized, whether business approval exists, and whether the same version has already been published.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User / Product
       │
       ▼
┌────────────────────┐
│   Agent Runtime    │
│                    │
│ goal               │
│ context            │
│ planning           │
│ tool selection     │
│ work continuation  │
└─────────┬──────────┘
          │
          │ MCP / API / CLI
          ▼
┌────────────────────┐
│   Domain Runtime   │
│                    │
│ domain semantics   │
│ authorization      │
│ validation         │
│ business approval  │
│ state transition   │
│ transaction logic  │
└─────────┬──────────┘
          │
          ▼
  Authoritative State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a logical responsibility boundary.&lt;/p&gt;

&lt;p&gt;Both runtimes may live in one process. The Domain Runtime may simply be the backend application that existed years before anyone added an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The publish succeeded, but the response disappeared
&lt;/h2&gt;

&lt;p&gt;This is where the distinction becomes operationally important.&lt;/p&gt;

&lt;p&gt;Suppose the Agent Runtime requests publication of version 42. The Domain Runtime validates the request and commits the publication successfully.&lt;/p&gt;

&lt;p&gt;Then the connection fails before the response reaches the agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Runtime
     │
     │ publish(version=42)
     ▼
Domain Runtime
     │
     │ commit succeeds
     ▼
State: PUBLISHED

     X response lost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the Agent Runtime's perspective, the outcome is unknown.&lt;/p&gt;

&lt;p&gt;Retrying is a reasonable agent behavior, but safe retry is a contract between both sides. &lt;strong&gt;The domain defines the retry guarantees; the agent integration must preserve operation identity and follow that contract.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A robust contract might assign a stable operation identity to the approved publication request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User approves publish intent P
2. Operation O is durably bound to payload P
3. Domain Runtime executes O
4. Domain state is committed
5. Response is lost
6. Agent retries or queries operation O
7. Domain Runtime recognizes O
8. Existing outcome is returned
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retries preserve both the &lt;strong&gt;operation identity and the business payload&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The domain system durably records the outcome and detects duplicate execution.&lt;/p&gt;

&lt;p&gt;External effects may complete independently.&lt;/p&gt;

&lt;p&gt;Publishing a record and sending a notification, for example, can fail at different points. The system therefore needs to track which effects completed and which still require delivery or reconciliation.&lt;/p&gt;

&lt;p&gt;Not every recovery path has to transparently return the original success result.&lt;/p&gt;

&lt;p&gt;For some operations, preventing duplicate execution, querying durable state, and marking an unresolved attempt as interrupted may be the safer contract.&lt;/p&gt;

&lt;p&gt;This is not something conversation history can resolve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The agent's memory of the world is not the world.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime approval is not business approval
&lt;/h2&gt;

&lt;p&gt;Approval has a similar ambiguity.&lt;/p&gt;

&lt;p&gt;An Agent Runtime may ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Allow this shell command?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That controls whether the agent may perform an action in its execution environment.&lt;/p&gt;

&lt;p&gt;The business application may separately require:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Approve version 42 for publication to the production portal?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That approval has domain meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Runtime
    │
    ├─ Runtime approval
    │    "May the agent attempt this action?"
    │
    ▼
Domain Runtime
    │
    └─ Domain authorization / approval
         "May this domain operation take effect?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first approval cannot silently imply the second.&lt;/p&gt;

&lt;p&gt;Business policy needs an authoritative owner and consistent enforcement across UI, API, scheduled jobs, and agent paths. Runtime approvals complement domain authorization; they do not replace it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Runtime and Domain Runtime need a contract
&lt;/h2&gt;

&lt;p&gt;As existing Agent Runtimes improve, this boundary becomes one of the most important custom engineering surfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Runtime
      │
      │ chooses and requests operations
      ▼
┌─────────────────────────┐
│ Agent-facing Interface  │
│                         │
│ Tools                   │
│ MCP                     │
│ API                     │
│ CLI                     │
│ Schema / DSL            │
└────────────┬────────────┘
             │
             ▼
       Domain Runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A backend interface designed for a human-facing application is not automatically a good agent interface.&lt;/p&gt;

&lt;p&gt;A frontend can orchestrate many low-level endpoints because application code already knows the workflow. Giving those endpoints directly to an agent pushes that orchestration back into model reasoning.&lt;/p&gt;

&lt;p&gt;For example, this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create_revision(...)
update_rows(...)
set_status(...)
create_permission(...)
send_notification(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;may be a worse agent surface than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prepare_import_plan(...)
validate_import_plan(...)
publish_version(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deeper question is not only which protocol to use.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is the smallest, safest, and most legible operation we can expose to the agent?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  MCP is one way to expose that boundary
&lt;/h2&gt;

&lt;p&gt;MCP fits naturally into this architecture.&lt;/p&gt;

&lt;p&gt;It can expose domain capabilities to an Agent Runtime through a standard tool interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Runtime
      │
      │ MCP
      ▼
 Domain Tool
      │
      ▼
Domain Runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But MCP does not determine the business meaning behind the operation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;publish_report&lt;/code&gt; could be exposed through MCP, REST, an internal function, a dynamic tool, or a CLI. The same Domain Runtime should still enforce the invariants that must hold regardless of the caller.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MCP exposes a capability. The Domain Runtime determines its domain effect.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes the MCP server and Domain Runtime are implemented together.&lt;/p&gt;

&lt;p&gt;Sometimes MCP is only an adapter around an existing service. In other systems, the agent runtime may expose its own dynamic tool mechanism instead.&lt;/p&gt;

&lt;p&gt;The logical responsibility matters more than the transport.&lt;/p&gt;

&lt;h2&gt;
  
  
  DSLs are another way to design the boundary
&lt;/h2&gt;

&lt;p&gt;Some domains benefit from something more expressive than individual tool calls.&lt;/p&gt;

&lt;p&gt;Suppose an analysis can be represented as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;analysis Occupancy {
    source facilities
    metric occupancy_rate
    group_by building
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;occupancy_rate&lt;/code&gt; refers to a versioned domain definition rather than redefining the metric inside every agent-authored program.&lt;/p&gt;

&lt;p&gt;The Agent Runtime can read this program, propose one, modify one, or explain one. That does not mean the Agent Runtime determines what the referenced metric means.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Runtime
      │
      │ proposes DSL
      ▼
  Domain Program
      │
      ▼
Compiler / Validator
      │
      ▼
 Domain Runtime
      │
      ▼
 Valid result / state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A compiler may translate it. A validator may reject it. A workflow engine may evaluate it. Domain services may execute the resulting operations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The agent can propose a domain program. The Domain Runtime determines whether and how it takes effect.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An agent can also propose a &lt;em&gt;new&lt;/em&gt; metric definition.&lt;/p&gt;

&lt;p&gt;That is a different operation from using an existing metric. The proposed definition must be validated and separately accepted before other programs can rely on it as an authoritative domain definition.&lt;/p&gt;

&lt;p&gt;The same distinction applies to mandatory policy.&lt;/p&gt;

&lt;p&gt;An agent might generate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workflow PublishAnalysis {
    analyze
    review
    publish
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but a mandatory approval requirement cannot depend on whether the agent remembered to encode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;publish requires approval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If approval is a domain invariant, deleting such a line cannot remove the requirement.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent-authored programs cannot weaken mandatory domain policies. Policy changes are separately authorized and validated.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Domain Runtime therefore evaluates the proposal against constraints the proposal itself does not control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent-authored program
        │
        │ proposed intent
        ▼
Domain Runtime
        │
        ├─ resolves domain definitions
        ├─ validates program
        ├─ applies mandatory policy
        └─ executes if valid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not every system needs a DSL.&lt;/p&gt;

&lt;p&gt;Typed functions, JSON Schema, or an ordinary API may already express the domain clearly enough. The important property is the separation between &lt;strong&gt;proposing an operation&lt;/strong&gt; and &lt;strong&gt;determining its domain meaning and effect&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime control is a different boundary
&lt;/h2&gt;

&lt;p&gt;There is also an interface on the other side of the Agent Runtime.&lt;/p&gt;

&lt;p&gt;A product may need to start work, resume it, send new input, receive events, or participate in runtime-level approvals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product UI / IDE
       │
       │ runtime control
       ▼
  Agent Runtime
       │
       │ capability access
       ▼
  Domain Runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codex App Server is one concrete example of a control interface for integrating Codex into another product.&lt;/p&gt;

&lt;p&gt;It exposes an interface for rich clients to interact with Codex conversations, approvals, and streamed agent events. This is a logical boundary, not a requirement for a separate runtime service.&lt;/p&gt;

&lt;p&gt;That is a different concern from MCP.&lt;/p&gt;

&lt;p&gt;One interface controls &lt;strong&gt;the agent's execution&lt;/strong&gt;. The other gives the agent access to &lt;strong&gt;domain capabilities&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured errors become part of the contract
&lt;/h2&gt;

&lt;p&gt;An agent-facing Domain Runtime should make domain failures actionable.&lt;/p&gt;

&lt;p&gt;Compare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;400 Invalid configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with:&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;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STALE_VERSION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expected_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provided_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"recoverable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"suggested_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reload_and_revalidate"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second response does not tell the agent what its goal should be.&lt;/p&gt;

&lt;p&gt;It makes the domain state explicit enough for the Agent Runtime to choose its next action.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Domain Runtime should not decide what the agent wants to do next.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;It should make domain consequences and constraints explicit enough that the agent can decide.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Agent-native does not mean agent-owned
&lt;/h2&gt;

&lt;p&gt;Making a system easier for agents to use does not mean moving business logic into the agent.&lt;/p&gt;

&lt;p&gt;Often the opposite architecture is safer.&lt;/p&gt;

&lt;p&gt;An agent-facing interface should be optimized for model reasoning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clear operations
typed inputs
structured outputs
stable identifiers
explicit preconditions
actionable failures
idempotent mutations
queryable operation status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the meaning behind those operations should remain authoritative regardless of whether the caller is Claude Code, Codex, a custom agent, a human UI, a scheduled job, or another service.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent-native interfaces should make the domain easier to reason about, not make the agent the owner of the domain.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Better Agent Runtimes move the build boundary
&lt;/h2&gt;

&lt;p&gt;This changes how I think about build versus buy.&lt;/p&gt;

&lt;p&gt;If Claude Code, Codex, an Agents SDK, or another runtime already gives us a capable agent loop, context management, tool execution, resumption, and sandbox integration, rebuilding those pieces may create little value.&lt;/p&gt;

&lt;p&gt;Instead, I increasingly ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are the domain operations well defined?&lt;/li&gt;
&lt;li&gt;Can the agent invoke them at the right abstraction level?&lt;/li&gt;
&lt;li&gt;Are domain definitions versioned and governed?&lt;/li&gt;
&lt;li&gt;Are mandatory policies independent of agent-authored programs?&lt;/li&gt;
&lt;li&gt;Are authorization and business approvals authoritative?&lt;/li&gt;
&lt;li&gt;Are operations safely retryable?&lt;/li&gt;
&lt;li&gt;Can uncertain outcomes be reconciled?&lt;/li&gt;
&lt;li&gt;Are errors structured enough for the agent to recover?&lt;/li&gt;
&lt;li&gt;Can agents and conventional application paths share the same semantics?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where much of our custom engineering now lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering the boundary
&lt;/h2&gt;

&lt;p&gt;This started for me as a naming problem.&lt;/p&gt;

&lt;p&gt;We were building MCP servers, DSLs, APIs, CLI tools, domain services, sandboxes, databases, and agent integrations, and none of those labels described the whole job.&lt;/p&gt;

&lt;p&gt;The more useful realization is that many of these components exist to engineer one boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 User / Product
                       │
                       ▼
                Agent Runtime
         goal / context / next action
                       │
          MCP / API / CLI / DSL
                       ▼
                Domain Runtime
       semantics / guarantees / results
                       │
                       ▼
            Data / External Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Agent Runtime should be free to explore, replan, retry, and choose different paths toward a goal.&lt;/p&gt;

&lt;p&gt;The Domain Runtime should make domain operations precise, enforce what must be enforced, and produce results the rest of the system can trust.&lt;/p&gt;

&lt;p&gt;Existing Agent Runtimes will keep getting better, reducing how much harness infrastructure we need to build ourselves.&lt;/p&gt;

&lt;p&gt;But someone still has to define what &lt;code&gt;occupancy_rate&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; mean, which guarantees apply, and which invariants can never be delegated to model reasoning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Agent Runtime manages how the agent pursues a goal.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The Domain Runtime gives its operations precise meaning and enforceable guarantees.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me, the interesting engineering is increasingly &lt;strong&gt;the boundary between the two&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Agent Runtime / Domain Runtime&lt;/strong&gt; distinction in this article is my own responsibility model. The following official documentation is referenced for the products and protocols discussed above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/agents" rel="noopener noreferrer"&gt;OpenAI — Agents: choose and compare agent runtime options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/agents-api/architecture" rel="noopener noreferrer"&gt;OpenAI — Agents API architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/app-server" rel="noopener noreferrer"&gt;OpenAI — Codex App Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/agents/running-agents" rel="noopener noreferrer"&gt;OpenAI — Running agents with the Agents SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ts.sdk.modelcontextprotocol.io/v2/" rel="noopener noreferrer"&gt;Model Context Protocol — TypeScript SDK overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/" rel="noopener noreferrer"&gt;Anthropic — Claude Platform documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>runtime</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Why agent-browser and Playwright Work So Well Together</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Tue, 15 Sep 2026 03:12:19 +0000</pubDate>
      <link>https://dev.to/gyu07/why-agent-browser-and-playwright-work-so-well-together-17c0</link>
      <guid>https://dev.to/gyu07/why-agent-browser-and-playwright-work-so-well-together-17c0</guid>
      <description>&lt;p&gt;We recently added &lt;strong&gt;&lt;a href="https://github.com/vercel-labs/agent-browser" rel="noopener noreferrer"&gt;agent-browser&lt;/a&gt;&lt;/strong&gt; to our UI evaluation workflow.&lt;/p&gt;

&lt;p&gt;The motivation was simple.&lt;/p&gt;

&lt;p&gt;A normal E2E test is great when we already know the path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But sometimes I want to ask a different question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can a user find Settings and open it?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't necessarily care which valid route the agent takes.&lt;/p&gt;

&lt;p&gt;I care whether the product makes the goal achievable.&lt;/p&gt;

&lt;p&gt;That is where agent-browser became useful.&lt;/p&gt;

&lt;p&gt;The interesting part, though, was not simply letting an AI control a browser.&lt;/p&gt;

&lt;p&gt;It was deciding &lt;strong&gt;where the agent's responsibility should end&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First: agent-browser and Computer Use are different paths
&lt;/h2&gt;

&lt;p&gt;Before getting into the architecture, one distinction is important.&lt;/p&gt;

&lt;p&gt;In our setup, &lt;strong&gt;agent-browser is part of the development-side evaluation harness&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Codex / Claude
      ↓
agent-browser
      ↓
our application
      ↓
independent assertion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;agent-browser gives coding agents a browser-oriented interface. Its snapshot workflow exposes an accessibility representation with element references, allowing the agent to inspect the current UI, act, inspect again, and continue toward a goal.&lt;/p&gt;

&lt;p&gt;OpenAI &lt;strong&gt;Computer Use&lt;/strong&gt; is a separate execution path.&lt;/p&gt;

&lt;p&gt;The current ChatGPT desktop app includes Chat and Work under ChatGPT, alongside Codex. Work can use local files and desktop applications with permission.&lt;/p&gt;

&lt;p&gt;When I refer to &lt;strong&gt;Computer Use&lt;/strong&gt; in this article, however, I mean the capability exposed to &lt;strong&gt;Codex&lt;/strong&gt; for interacting with desktop applications.&lt;/p&gt;

&lt;p&gt;For native application evaluation, where available, our path is closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ChatGPT desktop app
        ↓
      Codex
        ↓
   Computer Use
        ↓
native application
        ↓
independent verification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are not handing an agent-browser session over to Computer Use.&lt;/p&gt;

&lt;p&gt;We are also not claiming that agent-browser is our native desktop automation engine.&lt;/p&gt;

&lt;p&gt;And Computer Use should not be read as "the Office editing API." For example, Excel also has a dedicated ChatGPT for Excel add-in workflow; Computer Use may help Codex reach that environment, but it is not the editing model itself.&lt;/p&gt;

&lt;p&gt;These are different interaction mechanisms.&lt;/p&gt;

&lt;p&gt;The common principle is only this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The system performing the action does not have to be the system deciding whether the result is correct.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rest of this article focuses mainly on the agent-browser side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agent-browser fits exploratory QA
&lt;/h2&gt;

&lt;p&gt;agent-browser works well when the task is expressed as an intent rather than a click script.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Click button A.
Then click menu item B.
Then expect dialog C.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can give the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open Settings.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find the customer and open the information relevant to their latest issue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent can inspect the current accessible UI through agent-browser and decide how to proceed.&lt;/p&gt;

&lt;p&gt;That is useful for flows where we care about whether a goal is discoverable and achievable, rather than whether one exact sequence of selectors still works.&lt;/p&gt;

&lt;p&gt;I think of this as &lt;strong&gt;exploratory QA&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not random exploration.&lt;/p&gt;

&lt;p&gt;Not a replacement for our normal E2E suite.&lt;/p&gt;

&lt;p&gt;A separate lane for asking higher-level questions about the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent does not grade its own homework
&lt;/h2&gt;

&lt;p&gt;This was the most important design decision.&lt;/p&gt;

&lt;p&gt;Suppose the task is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the Settings dialog.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent uses agent-browser and eventually reports something equivalent to:&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;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We do not treat that as a passing test.&lt;/p&gt;

&lt;p&gt;After the agent finishes, Playwright checks the resulting application state independently.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent:
"completed"

    AND

Playwright:
Settings dialog is visible

    ↓

PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assertion can be very small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two signals mean different things.&lt;/p&gt;

&lt;p&gt;The agent says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I believe I completed the goal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The assertion says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The application reached the state we care about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That separation is what makes the combination useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playwright gives the agent more freedom
&lt;/h2&gt;

&lt;p&gt;Initially I thought of Playwright as a safety net around agent-browser.&lt;/p&gt;

&lt;p&gt;I now think the opposite framing is more useful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An independent oracle lets the agent be more exploratory.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent using agent-browser can focus on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can I accomplish the user's goal?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while Playwright focuses on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Did the application actually reach the expected state?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The architecture is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          goal-oriented
           exploration
               │
               ▼
      ┌─────────────────┐
      │ Codex / Claude  │
      │        +        │
      │  agent-browser  │
      └────────┬────────┘
               │
               ▼
          application
               │
               ▼
      ┌─────────────────┐
      │   Playwright    │
      │    assertion    │
      └────────┬────────┘
               │
               ▼
           pass / fail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why I don't see agent-browser and Playwright as competitors.&lt;/p&gt;

&lt;p&gt;They are useful precisely because they can own different responsibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  This pattern is not new
&lt;/h2&gt;

&lt;p&gt;I don't think the individual ideas here are novel.&lt;/p&gt;

&lt;p&gt;The broader agent-evaluation ecosystem is already converging on similar principles.&lt;/p&gt;

&lt;p&gt;Anthropic describes agent evaluation in terms of tasks, outcomes, and graders, and recommends code-based graders where possible instead of over-constraining the exact trajectory an agent must follow.&lt;/p&gt;

&lt;p&gt;WebArena has used a similar shape for years: an agent receives a natural-language web task, while evaluation checks whether the task was functionally completed.&lt;/p&gt;

&lt;p&gt;Playwright itself now has Test Agents. A planner explores the application, a generator turns plans into executable tests, and a healer works on failing tests.&lt;/p&gt;

&lt;p&gt;There are also projects much closer to this exact browser-QA pattern.&lt;/p&gt;

&lt;p&gt;The public &lt;code&gt;qa-skills&lt;/code&gt; repository describes an agentic browser-testing workflow where the browser agent receives a natural-language goal, an external oracle determines success, and stable flows can graduate to scripted Playwright tests.&lt;/p&gt;

&lt;p&gt;SightCI similarly documents AI exploration followed by promotion of selected runs into Playwright specs.&lt;/p&gt;

&lt;p&gt;So the interesting question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did we invent agentic browser testing?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We didn't.&lt;/p&gt;

&lt;p&gt;The useful question for us became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where should the boundary sit once this pattern meets a real application with UI, API, authentication, and native document workflows?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where our implementation became more interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real bug changed our original rule
&lt;/h2&gt;

&lt;p&gt;Our first mental model was straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent-browser-assisted exploration finds a failure
                    ↓
             we understand it
                    ↓
        add a Playwright regression test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we encountered a failure in a real authenticated environment.&lt;/p&gt;

&lt;p&gt;A cloud instruction was rejected.&lt;/p&gt;

&lt;p&gt;After comparing API behavior under the same authentication context, we traced the issue to an &lt;strong&gt;organization-resolution mismatch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The failure was visible through the product.&lt;/p&gt;

&lt;p&gt;But the contract that actually broke was not a UI contract.&lt;/p&gt;

&lt;p&gt;Adding another browser regression would therefore have put the check too far away from the failure.&lt;/p&gt;

&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;real environment exposes failure
            ↓
compare API behavior
            ↓
identify organization-resolution mismatch
            ↓
fix implementation
            ↓
add model-free Hosted E2E coverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That changed the rule.&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every problem discovered through exploration should become a Playwright test.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Move an understood failure to the lowest-cost assertion-based layer that still reproduces the contract that failed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That last part matters.&lt;/p&gt;

&lt;p&gt;I don't mean "always turn an integration failure into a tiny unit test."&lt;/p&gt;

&lt;p&gt;Some failures only exist across an integration boundary.&lt;/p&gt;

&lt;p&gt;The regression still needs to reproduce the contract that actually broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promote failures to the right layer
&lt;/h2&gt;

&lt;p&gt;In practice, that gives us a rule of thumb like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure&lt;/th&gt;
&lt;th&gt;Likely regression layer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI navigation, visibility, dialogs&lt;/td&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication, organization resolution, API contracts&lt;/td&gt;
&lt;td&gt;API / Hosted E2E&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Word, Excel, or PowerPoint output&lt;/td&gt;
&lt;td&gt;Artifact-level verification&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A UI failure may graduate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent exploration
      ↓
UI root cause
      ↓
Playwright regression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An authentication or backend failure may graduate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;failure discovered
      ↓
API/auth root cause
      ↓
Hosted E2E / API regression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a native document workflow can use a different oracle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;desktop interaction
      ↓
edit a safe working copy
      ↓
save
      ↓
artifact / structure / reopen verification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution mechanism is secondary.&lt;/p&gt;

&lt;p&gt;The important question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where can we observe the failed contract most directly and cheaply without losing the behavior that matters?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Known failures should leave the agent loop
&lt;/h2&gt;

&lt;p&gt;This leads to the part of the design I like most.&lt;/p&gt;

&lt;p&gt;Imagine an agent using agent-browser discovers a navigation problem today.&lt;/p&gt;

&lt;p&gt;We investigate it.&lt;/p&gt;

&lt;p&gt;We identify the contract that failed.&lt;/p&gt;

&lt;p&gt;We add an assertion-based regression at the correct layer.&lt;/p&gt;

&lt;p&gt;What should happen tomorrow?&lt;/p&gt;

&lt;p&gt;Ideally, that exact failure should no longer require an AI agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI exploration
      ↓
new failure
      ↓
root cause becomes known
      ↓
assertion-based regression
      ↓
future CI catches it without AI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means the goal is &lt;strong&gt;not&lt;/strong&gt; to make more and more of the regression suite depend on AI.&lt;/p&gt;

&lt;p&gt;It is almost the opposite.&lt;/p&gt;

&lt;p&gt;Use the agent where uncertainty still exists.&lt;/p&gt;

&lt;p&gt;Once the failure becomes knowledge, compile that knowledge into a cheaper check.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI should have to discover a bug once. It should not have to rediscover the same bug on every pull request.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Restrict the capability, not only the prompt
&lt;/h2&gt;

&lt;p&gt;There is another practical issue with giving an agent a browser.&lt;/p&gt;

&lt;p&gt;A prompt can say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not upload files.
Do not download files.
Do not leave the test environment.
Do not execute arbitrary JavaScript.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But those are instructions to the model.&lt;/p&gt;

&lt;p&gt;Where possible, we also want the environment to enforce the boundary.&lt;/p&gt;

&lt;p&gt;agent-browser provides controls such as domain restrictions, content boundaries, action policies, confirmations, and output limits.&lt;/p&gt;

&lt;p&gt;One detail matters:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Those security controls are opt-in.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A plain agent-browser session should not be assumed to be restricted automatically.&lt;/p&gt;

&lt;p&gt;Our evaluation harness therefore treats restrictions as part of the harness configuration rather than relying only on the prompt.&lt;/p&gt;

&lt;p&gt;The principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prompt boundaries are behavioral. Tool boundaries are architectural.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We also avoid treating one action-policy file as a complete security boundary.&lt;/p&gt;

&lt;p&gt;At the time of writing, there is an open agent-browser issue describing a mismatch between documented action-policy categories and how individual actions are matched.&lt;/p&gt;

&lt;p&gt;So effective permissions should be verified, not merely inferred from policy names.&lt;/p&gt;

&lt;p&gt;For us, tool policy is only one layer alongside ephemeral execution, secret minimization, bounded runtime, and disposable browser state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass evidence, not magical state
&lt;/h2&gt;

&lt;p&gt;Another design question is what happens after an exploratory run fails.&lt;/p&gt;

&lt;p&gt;One option would be to keep the browser alive and pass the same mutable session through several agents.&lt;/p&gt;

&lt;p&gt;Sometimes that is useful.&lt;/p&gt;

&lt;p&gt;But I don't want a live session to become the primary interface between evaluation stages.&lt;/p&gt;

&lt;p&gt;Our current harness already records structured evidence such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scenario
scenario version
agent
target build
prompt hash
latency
coverage
failure domain
violation detail
cleanup state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The direction I want to take this is a richer diagnostic bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final URL
failed step
accessibility snapshot
screenshot
console errors
trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent exploration through agent-browser
          ↓
inspectable evidence
          ↓
developer / Codex diagnosis
          ↓
regression candidate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not an argument against traces, storage state, network logs, or screenshots.&lt;/p&gt;

&lt;p&gt;Those are exactly the kinds of evidence we may want.&lt;/p&gt;

&lt;p&gt;The distinction is between &lt;strong&gt;preserving evidence about state&lt;/strong&gt; and making a hidden, mutable browser session the contract between components.&lt;/p&gt;

&lt;p&gt;Evidence is easier to inspect, store, compare, and review.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we have today
&lt;/h2&gt;

&lt;p&gt;This is not a fully autonomous QA pipeline.&lt;/p&gt;

&lt;p&gt;Today, the important pieces are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ agent-browser exploration lane
✓ independent Codex / Claude evaluations
✓ restricted browser capabilities
✓ Playwright assertions outside the agent
✓ structured evaluation evidence
✓ assertion-based tests remain the release source of truth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we do not yet have is the full promotion loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;□ complete screenshot / trace diagnostic bundles
□ automatic regression-candidate generation
□ evidence → regression linkage
□ reviewed promotion records
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I would describe the current system as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A shadow exploration layer around assertion-based QA, not an autonomous replacement for it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;I started this work because agent-browser looked like a good way to let coding agents interact with our application more like a user.&lt;/p&gt;

&lt;p&gt;It is.&lt;/p&gt;

&lt;p&gt;But the interesting lesson was not "AI can click buttons now."&lt;/p&gt;

&lt;p&gt;The useful architecture emerged from deciding what the agent should &lt;strong&gt;not&lt;/strong&gt; own.&lt;/p&gt;

&lt;p&gt;An agent using agent-browser is good at asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can I achieve this user goal from the UI in front of me?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Playwright, API checks, and artifact verification are good at asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this contract actually satisfied?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those ideas are not new individually.&lt;/p&gt;

&lt;p&gt;What surprised me was how well they fit together once we applied them across a real application instead of only a browser benchmark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let the agent explore what you don't know yet.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let assertion-based tests remember what you already learned.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And once a failure becomes understood, move it out of the expensive exploratory loop and into the cheapest test that still protects the contract.&lt;/p&gt;

&lt;p&gt;AI should have to discover a bug once.&lt;/p&gt;

&lt;p&gt;It should not have to rediscover the same bug on every pull request.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>playwright</category>
      <category>agentbrowser</category>
    </item>
    <item>
      <title>Codex Computer Use Changed the Agent Integration Boundary</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Wed, 09 Sep 2026 06:53:20 +0000</pubDate>
      <link>https://dev.to/gyu07/codex-computer-use-changed-the-agent-integration-boundary-1a68</link>
      <guid>https://dev.to/gyu07/codex-computer-use-changed-the-agent-integration-boundary-1a68</guid>
      <description>&lt;p&gt;For a long time, I assumed serious agent integration required a structured interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API, CLI, SDK, then MCP.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Codex Computer Use changed that assumption.&lt;/p&gt;

&lt;p&gt;An agent can now look at the same interface as a user, operate it, observe the resulting state, and continue.&lt;/p&gt;

&lt;p&gt;GPT-5.6 Sol was already strong enough for us to start using this seriously. GPT-6 Astra raised the baseline further.&lt;/p&gt;

&lt;p&gt;OpenAI reports Astra at &lt;strong&gt;72.6% vs. 65.7% for Sol on OSWorld 2.0&lt;/strong&gt; — specifically v2026.08.08, offline set, partial score — and &lt;strong&gt;92.7% vs. 76.9% on ScreenSpot-Pro&lt;/strong&gt;, under the no-tools setting.&lt;/p&gt;

&lt;p&gt;These are benchmark results, not end-to-end success rates for arbitrary enterprise workflows, but the improvement is substantial.&lt;/p&gt;

&lt;p&gt;More importantly, OpenAI now explicitly describes frontend QA, installing and testing software, and troubleshooting visible problems as Computer Use workloads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openai.com/index/gpt-6-astra/" rel="noopener noreferrer"&gt;GPT-6 Astra: A new generation of intelligence — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/computer-use" rel="noopener noreferrer"&gt;Computer Use — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important change is not that AI can click buttons.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The GUI has become a practical agent interface.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The integration path changed
&lt;/h2&gt;

&lt;p&gt;With MCP, the protocol itself is usually not the difficult part.&lt;/p&gt;

&lt;p&gt;The difficult part is designing what sits behind it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
    ↓
API / CLI
    ↓
agent-oriented operations
    ↓
MCP
    ↓
Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an agent to operate complex software reliably, we often have to design the right verbs, schemas, permissions, side effects, errors, and recovery behavior.&lt;/p&gt;

&lt;p&gt;That remains the right architecture for operations requiring determinism, throughput, explicit contracts, or strong auditability.&lt;/p&gt;

&lt;p&gt;Computer Use does not replace MCP.&lt;/p&gt;

&lt;p&gt;It changes how much of that integration surface has to exist &lt;strong&gt;before&lt;/strong&gt; an agent can do useful work.&lt;/p&gt;

&lt;p&gt;Another path is now practical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Existing GUI
    ↓
observe
    ↓
click / type / navigate
    ↓
observe again
    ↓
Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current Computer Use implementation can visually inspect and operate graphical applications, including workflows where CLI or structured integrations are not sufficient.&lt;/p&gt;

&lt;p&gt;In the Codex desktop environment, Computer Use is exposed through the plugin/tool system.&lt;/p&gt;

&lt;p&gt;So this is not really &lt;strong&gt;MCP versus Computer Use&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Computer Use reduces the need to design every domain-specific operation upfront.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; remove the need to engineer execution boundaries and verify outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The integration cost moved
&lt;/h2&gt;

&lt;p&gt;This is the part I find most interesting.&lt;/p&gt;

&lt;p&gt;Previously, much of the engineering cost looked 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;design API
design CLI
design agent verbs
wrap with MCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Computer Use moves part of that work toward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;control identity
control environment
control permissions
observe execution
verify outcomes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The integration cost did not disappear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It moved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a specialized desktop tool with a weak API, building twenty MCP operations may no longer be the best first step.&lt;/p&gt;

&lt;p&gt;We can let the agent operate the existing interface, observe the real workflow, and identify which operations are frequent, dangerous, slow, or difficult to verify.&lt;/p&gt;

&lt;p&gt;Then those operations can become structured tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GUI
 ↓
real usage
 ↓
identify critical operations
 ↓
API / CLI / MCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The GUI becomes a compatibility layer.&lt;/p&gt;

&lt;p&gt;Structured interfaces remain both an optimization layer and a place to enforce explicit contracts and policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GUI is not an authorization boundary
&lt;/h2&gt;

&lt;p&gt;This distinction becomes critical once the agent can operate the same interface as a human.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Computer Use changes how an agent reaches an operation. It does not define what authorizes that operation.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If an AI can see a human approval button, that does not mean the AI should be allowed to press it.&lt;/p&gt;

&lt;p&gt;If credentials, raw data, privileged controls, or connected accounts are visible in the environment, they may also become part of what the agent can observe or operate.&lt;/p&gt;

&lt;p&gt;This is not a sufficient security model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
GUI
  ↓
whatever the logged-in user can do
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For important actions, GUI operations and structured tool calls should converge on the same authorization, validation, approval, and audit boundaries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  ↓
controlled execution environment
  ↓
GUI / structured tools
  ↓
policy + validation
  ↓
system of record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A visual interface is an execution surface.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It should not become the source of authority.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  We use Computer Use for QA
&lt;/h2&gt;

&lt;p&gt;A lot of Computer Use demos naturally focus on video editing, design software, spreadsheets, and other professional tools.&lt;/p&gt;

&lt;p&gt;Our main use case is more mundane:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;software testing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We already use Playwright heavily.&lt;/p&gt;

&lt;p&gt;We also use agent-based evals, generated test data, and fuzzing to explore cases that are difficult to maintain as hand-written fixtures.&lt;/p&gt;

&lt;p&gt;Computer Use adds another execution path.&lt;/p&gt;

&lt;p&gt;I do not see these as a linear pipeline where every test eventually reaches Computer Use.&lt;/p&gt;

&lt;p&gt;They are different ways of exercising the same system, ideally converging on shared outcome checks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   scenario
                      │
          ┌───────────┼───────────┐
          │           │           │
     Playwright   Agent tools  Computer Use
          │           │           │
          └───────────┼───────────┘
                      │
               shared outcomes
               and invariants
                      │
              reproduce / reduce
                      │
                regression test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playwright remains better when we know exactly what contract we want to verify.&lt;/p&gt;

&lt;p&gt;Computer Use is useful when we want to exercise the product closer to how a user actually experiences it.&lt;/p&gt;

&lt;p&gt;Instead of encoding a fixed sequence of selectors and assertions, we can give the agent a task such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the application.

Complete onboarding.

Load this generated dataset.

Perform the primary workflow.

Investigate anything visibly wrong.

Preserve evidence of failures.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That exposes a different class of problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native dialogs&lt;/li&gt;
&lt;li&gt;broken focus&lt;/li&gt;
&lt;li&gt;hidden or overlapping controls&lt;/li&gt;
&lt;li&gt;unexpected application state&lt;/li&gt;
&lt;li&gt;simulator behavior&lt;/li&gt;
&lt;li&gt;cross-application workflows&lt;/li&gt;
&lt;li&gt;failures visible to a user but awkward to express as DOM assertions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenAI explicitly positions Computer Use for desktop application testing, GUI-only bugs, and applications that are not adequately covered by command-line or structured integrations.&lt;/p&gt;

&lt;p&gt;We also combine this with generated scenarios.&lt;/p&gt;

&lt;p&gt;Rich or unusual data can be produced automatically and then exercised through the actual application rather than only through APIs.&lt;/p&gt;

&lt;p&gt;But I do not want the model to become the oracle.&lt;/p&gt;

&lt;p&gt;If the requirement is that no duplicate object can be created, code should verify that.&lt;/p&gt;

&lt;p&gt;If a user must never gain a particular permission, the authorization layer should verify that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The agent explores.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Deterministic checks decide facts.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Humans decide where judgment is actually required.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Human review remains valuable for ambiguous product behavior, UX quality, and release decisions.&lt;/p&gt;

&lt;p&gt;It does not mean a human needs to inspect every successful run.&lt;/p&gt;

&lt;p&gt;In practice, Computer Use has reduced a significant amount of the work before human review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup&lt;/li&gt;
&lt;li&gt;navigation&lt;/li&gt;
&lt;li&gt;reproduction&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;exploration&lt;/li&gt;
&lt;li&gt;evidence collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is already useful to us today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codex App Server changes the product boundary
&lt;/h2&gt;

&lt;p&gt;The next interesting part is that the Codex harness itself is embeddable.&lt;/p&gt;

&lt;p&gt;Codex App Server exposes the Codex harness to external clients through a bidirectional JSON-RPC-style interface.&lt;/p&gt;

&lt;p&gt;The embedding application can manage threads and turns, receive agent events, handle approvals, and observe tool activity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openai.com/index/unlocking-the-codex-harness/" rel="noopener noreferrer"&gt;Unlocking the Codex harness: how we built the App Server — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/app-server" rel="noopener noreferrer"&gt;Codex App Server documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Our application
      │
      ▼
Codex App Server
      │
      ▼
Codex harness
      │
      ├── shell / files
      ├── MCP servers
      ├── skills
      └── agent loop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters because App Server exposes much more than raw model inference.&lt;/p&gt;

&lt;p&gt;Codex core manages threads and persistence, executes tools, wires MCP servers and skills into the agent loop, and can pause execution while the embedding client handles an approval request.&lt;/p&gt;

&lt;p&gt;But there is an important boundary here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;App Server is not a remote screenshot-and-click API for Computer Use.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the ChatGPT desktop app, Computer Use is installed as a plugin and exposes a Computer-use MCP server and a Computer Use skill that Codex can use. App Server separately exposes the surrounding Codex harness.&lt;/p&gt;

&lt;p&gt;App Server exposes the surrounding Codex harness.&lt;/p&gt;

&lt;p&gt;Those are related building blocks, but they are not the same thing.&lt;/p&gt;

&lt;p&gt;The existence of App Server plus the desktop Computer Use capability does not by itself guarantee that the official Computer Use implementation can be packaged and independently deployed inside every arbitrary App Server environment.&lt;/p&gt;

&lt;p&gt;For that reason, I separate three things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;officially exposed capability

        ↓

what we have connected and validated
inside controlled environments

        ↓

architectures that become possible
from those building blocks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are actively implementing the second category.&lt;/p&gt;

&lt;p&gt;The architectural pattern we care about is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Our product
     ↓
Codex / agent runtime
     ↓
controlled desktop environment
     ↓
application being operated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets computer operation become part of an application architecture rather than something that only happens on a developer's everyday desktop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandbox the desktop, not just the shell
&lt;/h2&gt;

&lt;p&gt;This becomes especially important for enterprise systems.&lt;/p&gt;

&lt;p&gt;The Codex harness already has strong concepts around sandboxed tool execution, permissions, MCP integrations, and approval flows.&lt;/p&gt;

&lt;p&gt;Computer Use expands the execution surface.&lt;/p&gt;

&lt;p&gt;OpenAI explicitly warns that Computer Use can affect application and system state outside the project workspace.&lt;/p&gt;

&lt;p&gt;So protecting the project directory is not enough.&lt;/p&gt;

&lt;p&gt;For the systems we are building, the isolation boundary needs to include the desktop environment itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;isolated environment
    │
    ├── dedicated OS/session identity
    ├── dedicated browser profile
    ├── restricted applications
    ├── restricted network egress
    ├── controlled filesystem
    ├── controlled clipboard
    ├── controlled shared folders
    ├── limited accounts
    └── disposable state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A VM alone is not a security model.&lt;/p&gt;

&lt;p&gt;If an isolated VM is logged into production with privileged credentials, production side effects are still possible.&lt;/p&gt;

&lt;p&gt;The screen must be isolated.&lt;/p&gt;

&lt;p&gt;The identity must be limited.&lt;/p&gt;

&lt;p&gt;The network must be constrained.&lt;/p&gt;

&lt;p&gt;The applications, browser sessions, connected accounts, shared folders, and credentials available inside the environment must all be intentional.&lt;/p&gt;

&lt;p&gt;Important side effects should still pass through explicit policy boundaries.&lt;/p&gt;

&lt;p&gt;This is what makes Computer Use interesting for enterprise deployment.&lt;/p&gt;

&lt;p&gt;Some organizations cannot deploy a general-purpose AI desktop application to employee endpoints.&lt;/p&gt;

&lt;p&gt;Others need dedicated identities, isolated networks, specific audit controls, or access to highly specialized software that only exists in a controlled environment.&lt;/p&gt;

&lt;p&gt;The useful model is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI controls employee laptop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI controls purpose-built environment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are implementing this pattern in our own application architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specialized software is where this gets interesting
&lt;/h2&gt;

&lt;p&gt;The long tail of enterprise software is full of difficult integrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;legacy desktop applications&lt;/li&gt;
&lt;li&gt;internal tools&lt;/li&gt;
&lt;li&gt;engineering software&lt;/li&gt;
&lt;li&gt;industry-specific applications&lt;/li&gt;
&lt;li&gt;vendor tools with incomplete APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Historically, making those systems agent-accessible meant building an adapter first.&lt;/p&gt;

&lt;p&gt;Computer Use changes the economics.&lt;/p&gt;

&lt;p&gt;If a human can operate the application visually, an agent can increasingly attempt the same workflow before a complete structured integration exists.&lt;/p&gt;

&lt;p&gt;That lets us validate the workflow first.&lt;/p&gt;

&lt;p&gt;Then we can progressively move important operations into deterministic tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computer Use:
open project
navigate UI
inspect state

MCP:
fetch structured data
perform validated mutation
commit privileged change

Computer Use:
verify rendered result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I expect this hybrid architecture to become increasingly common.&lt;/p&gt;

&lt;p&gt;The question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MCP or Computer Use?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which parts of this workflow deserve a structured contract?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The boundary changed
&lt;/h2&gt;

&lt;p&gt;I still want structured interfaces.&lt;/p&gt;

&lt;p&gt;For payments, production changes, privileged administration, bulk operations, and anything requiring strong transactional guarantees, explicit tool contracts matter.&lt;/p&gt;

&lt;p&gt;Computer Use does not make those requirements disappear.&lt;/p&gt;

&lt;p&gt;But I no longer think every application needs a complete agent-native integration before an agent can start doing useful work.&lt;/p&gt;

&lt;p&gt;That changes the development order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:

design integration
      ↓
expose tools
      ↓
agent can work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Now:

agent uses existing interface
      ↓
observe real workflow
      ↓
identify critical boundaries
      ↓
structure where necessary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For us, this is already changing software testing.&lt;/p&gt;

&lt;p&gt;It is also changing how we think about bringing agents into specialized enterprise software.&lt;/p&gt;

&lt;p&gt;The engineering work did not disappear.&lt;/p&gt;

&lt;p&gt;It moved from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do we expose every operation?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What environment can the agent operate, what is it authorized to do, and how do we prove the result?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a much more important shift than better mouse automation.&lt;/p&gt;

&lt;p&gt;I still think important APIs will increasingly be redesigned for agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I just no longer think agents have to wait for that redesign.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>computeruse</category>
      <category>agents</category>
      <category>codex</category>
    </item>
    <item>
      <title>Agentic Software Will Have More Test Code Than Product Code</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Thu, 03 Sep 2026 06:55:51 +0000</pubDate>
      <link>https://dev.to/gyu07/agentic-software-will-have-more-test-code-than-product-code-2d33</link>
      <guid>https://dev.to/gyu07/agentic-software-will-have-more-test-code-than-product-code-2d33</guid>
      <description>&lt;p&gt;In several products we are building, Codex App Server is no longer just a developer tool. The agent loop is part of the product.&lt;/p&gt;

&lt;p&gt;It can inspect state, choose tools, mutate persistent data, request approval, recover from failures, and reach the same valid outcome through different paths.&lt;/p&gt;

&lt;p&gt;As we increased that autonomy, I started noticing a strange imbalance.&lt;/p&gt;

&lt;p&gt;The product code was growing, of course. But the amount of code and machinery around verification was growing in a different way.&lt;/p&gt;

&lt;p&gt;Not just unit tests or E2E.&lt;/p&gt;

&lt;p&gt;We started accumulating evals, fuzzers, deterministic verifiers, independent oracles, capability definitions, traces, replay, policies, audit evidence, and release gates.&lt;/p&gt;

&lt;p&gt;At first I called all of this "test code." That stopped feeling accurate fairly quickly.&lt;/p&gt;

&lt;p&gt;The better name is &lt;strong&gt;verification infrastructure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I do not literally mean that every agentic application will end up with more test LOC than product LOC. The more interesting pattern is that a relatively small amount of implementation can now expose a surprisingly large amount of behavior.&lt;/p&gt;

&lt;p&gt;That changes what we have to verify.&lt;/p&gt;




&lt;h2&gt;
  
  
  A small agent runtime can create a large behavioral surface
&lt;/h2&gt;

&lt;p&gt;Traditional CRUD software usually has a fairly visible path from user action to system effect.&lt;/p&gt;

&lt;p&gt;A click maps to an endpoint. The endpoint validates something, updates state, and returns a result. The system can be complex, but there is usually a fairly direct relationship between implementation paths and behavior.&lt;/p&gt;

&lt;p&gt;Agentic software breaks that relationship.&lt;/p&gt;

&lt;p&gt;A user gives an intent. The agent may inspect state, choose one tool, observe the result, choose another tool, retry after a failure, pause for approval, or reach the same outcome through a different sequence altogether.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://openai.com/index/unlocking-the-codex-harness/" rel="noopener noreferrer"&gt;Codex App Server&lt;/a&gt; is a good example of the shift. It exposes the Codex harness as a long-lived bidirectional JSON-RPC process. A request can produce multiple events, tools can execute during the run, and the process can pause while waiting for approval.&lt;/p&gt;

&lt;p&gt;Once that runtime is embedded in a product, it is no longer useful to think of it as "an LLM call."&lt;/p&gt;

&lt;p&gt;I wrote about that earlier in &lt;a href="https://dev.to/gyu07/the-agent-runtime-got-heavy-rethinking-sandboxes-with-codex-app-server-5edf"&gt;The Agent Runtime Got Heavy: Rethinking Sandboxes with Codex App Server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The mental model I use now is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Behavioral Surface
≈ Intents × States × Tools × Permissions × Failures × Recovery Paths
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not as a real formula. Just as a reminder that the number of things an agent can do grows much faster than the amount of orchestration code required to expose those choices.&lt;/p&gt;

&lt;p&gt;This is the part I think is easy to underestimate.&lt;/p&gt;

&lt;p&gt;A read-only copilot is one thing. An agent that edits persistent state, calls external systems, changes permissions, or performs irreversible actions is another. The code difference between those products may not look huge. The verification burden does.&lt;/p&gt;

&lt;p&gt;That is why source LOC feels less useful to me as a proxy for complexity than it used to.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conventional tests still matter, but they no longer describe the whole contract
&lt;/h2&gt;

&lt;p&gt;I do not think the test pyramid is obsolete.&lt;/p&gt;

&lt;p&gt;If authentication breaks, I still want a deterministic test to fail. API contracts still need integration tests. Ordinary UI paths still need E2E.&lt;/p&gt;

&lt;p&gt;What changed for us is that those tests stopped answering all of the important questions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;What we tend to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Does deterministic logic work?&lt;/td&gt;
&lt;td&gt;Unit / Integration / E2E&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Do invariants survive unexpected input?&lt;/td&gt;
&lt;td&gt;Property testing / Fuzzing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can the agent accomplish the task?&lt;/td&gt;
&lt;td&gt;Eval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does it accomplish it reliably?&lt;/td&gt;
&lt;td&gt;Repeated eval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Did it stay inside a hard boundary?&lt;/td&gt;
&lt;td&gt;Deterministic verifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Was the execution path acceptable?&lt;/td&gt;
&lt;td&gt;Trace verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is a claimed result actually true?&lt;/td&gt;
&lt;td&gt;Independent oracle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does it survive dependency failures?&lt;/td&gt;
&lt;td&gt;Fault injection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents" rel="noopener noreferrer"&gt;Anthropic's agent-eval guidance&lt;/a&gt; describes the same basic problem: multi-turn agents use tools, modify environment state, and adapt to intermediate results. That makes the execution trace and the resulting environment state part of what needs to be evaluated.&lt;/p&gt;

&lt;p&gt;One concrete consequence is that a test case is not always a single run anymore.&lt;/p&gt;

&lt;p&gt;In some of our agent E2E work, a single Green result did not tell us enough. We needed repeated trials and had to distinguish product failures from environment failures and inconclusive runs.&lt;/p&gt;

&lt;p&gt;That starts to feel closer to reliability engineering than ordinary regression testing.&lt;/p&gt;

&lt;p&gt;I wrote more about that in &lt;a href="https://dev.to/gyu07/the-hard-part-of-agent-evals-is-deciding-what-counts-as-green-3a5f"&gt;The Hard Part of Agent Evals Is Deciding What Counts as Green&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Coverage also starts to mean something different.&lt;/p&gt;

&lt;p&gt;We cannot enumerate every prompt, every workspace state, every tool ordering, and every recovery path. So instead of trying to cover the entire behavior space directly, we end up encoding the risks we care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the agent must stay inside the permitted workspace;&lt;/li&gt;
&lt;li&gt;destructive operations require approval;&lt;/li&gt;
&lt;li&gt;cancellation must stop durable side effects;&lt;/li&gt;
&lt;li&gt;a claimed artifact must actually exist;&lt;/li&gt;
&lt;li&gt;recovery must not corrupt persistent state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point the eval suite stops looking like a collection of examples and starts looking like a machine-readable description of the product boundary.&lt;/p&gt;

&lt;p&gt;I am still not sure where the right abstraction is here.&lt;/p&gt;

&lt;p&gt;Some of these belong in tests. Some belong in policy. Some are better represented as deterministic verifiers. Some only make sense as production evidence.&lt;/p&gt;

&lt;p&gt;But that ambiguity is part of the point: the verification layer is becoming substantial enough that it needs its own architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where facts exist, I prefer facts
&lt;/h2&gt;

&lt;p&gt;A natural response to agent uncertainty is another LLM judge.&lt;/p&gt;

&lt;p&gt;Sometimes that is the right answer.&lt;/p&gt;

&lt;p&gt;If I need to evaluate whether a generated report is useful, whether an explanation is clear, or whether an artifact is semantically good, there may not be a deterministic oracle.&lt;/p&gt;

&lt;p&gt;But many agent claims are not subjective.&lt;/p&gt;

&lt;p&gt;If the agent says it created a file, inspect the filesystem.&lt;/p&gt;

&lt;p&gt;If it says it updated persistent state correctly, inspect that state.&lt;/p&gt;

&lt;p&gt;If it says it stayed inside a workspace boundary, inspect what it actually touched.&lt;/p&gt;

&lt;p&gt;This is the pattern I increasingly prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Probabilistic Agent
        ↓
Observed Execution
        ↓
Facts / Trace
        ↓
Deterministic Verification
        ↓
Policy Decision
        ↓
Evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also why fuzzing, evals, traces, and oracles keep showing up together in the same systems.&lt;/p&gt;

&lt;p&gt;They are doing different jobs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fuzzing explores what can happen.&lt;/li&gt;
&lt;li&gt;Eval asks whether the agent can succeed.&lt;/li&gt;
&lt;li&gt;Trace records what actually happened.&lt;/li&gt;
&lt;li&gt;Oracle decides whether the result is correct.&lt;/li&gt;
&lt;li&gt;Policy decides whether the behavior was allowed.&lt;/li&gt;
&lt;li&gt;Evidence makes that decision reproducible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ran into the same issue from another direction while working on fuzzing: &lt;a href="https://dev.to/gyu07/your-fuzzer-is-only-as-smart-as-its-oracle-4mbd"&gt;Your Fuzzer Is Only as Smart as Its Oracle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Generating more cases is cheap. Knowing whether they reveal a real failure is the hard part.&lt;/p&gt;

&lt;p&gt;There is also a distinction I did not appreciate enough at first: the final state and the trajectory are not always equivalent.&lt;/p&gt;

&lt;p&gt;If an agent can safely produce the same artifact through ten different tool sequences, I usually do not want to constrain it to one path.&lt;/p&gt;

&lt;p&gt;But if it reads sensitive data, sends it externally, and only then asks for approval, the final state does not rescue the trajectory.&lt;/p&gt;

&lt;p&gt;So the rule I use for now is simple:&lt;/p&gt;

&lt;p&gt;Constrain the path when the path itself has safety or policy meaning. Otherwise, prefer the outcome as the oracle.&lt;/p&gt;

&lt;p&gt;Production traces also start to matter here. Once they are structured and durable, failures can be replayed and converted into regression or eval cases.&lt;/p&gt;

&lt;p&gt;That creates a loop from production behavior back into verification.&lt;/p&gt;

&lt;p&gt;I wrote about the observability side of this in &lt;a href="https://dev.to/gyu07/installing-opentelemetry-wont-close-your-ai-agents-feedback-loop-11gf"&gt;Installing OpenTelemetry Won't Close Your AI Agent's Feedback Loop&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The other half of the story is economics
&lt;/h2&gt;

&lt;p&gt;So far, the argument is mostly about demand.&lt;/p&gt;

&lt;p&gt;More autonomous behavior creates more things we need to verify.&lt;/p&gt;

&lt;p&gt;But there is another change happening at the same time: the cost of building verification is falling.&lt;/p&gt;

&lt;p&gt;AI can generate not only product code, but also fixtures, fuzz harnesses, eval scenarios, graders, mocks, replay tooling, fault injection, and CI checks.&lt;/p&gt;

&lt;p&gt;OpenAI's &lt;a href="https://openai.com/index/harness-engineering/" rel="noopener noreferrer"&gt;Harness engineering&lt;/a&gt; is a useful public example. In that experiment, Codex generated application code together with tests, CI, documentation, observability, internal tooling, and evaluation harnesses.&lt;/p&gt;

&lt;p&gt;The part I find most interesting is not the amount of generated code.&lt;/p&gt;

&lt;p&gt;It is that once implementation throughput increased, human attention became the scarce resource.&lt;/p&gt;

&lt;p&gt;That changes the economics.&lt;/p&gt;

&lt;p&gt;Historically, many teams knew they could benefit from another simulator, another failure-replay tool, another invariant suite, or better fuzzing, but the engineering cost was hard to justify.&lt;/p&gt;

&lt;p&gt;Now some of that infrastructure is much cheaper to produce.&lt;/p&gt;

&lt;p&gt;So two things are happening at once:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent autonomy increases verification demand.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-assisted engineering lowers the cost of verification supply.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That combination is probably more important than either trend alone.&lt;/p&gt;

&lt;p&gt;It also means we can easily overshoot.&lt;/p&gt;

&lt;p&gt;Verification infrastructure has its own failure modes: stale tests, noisy evals, conflicting policies, expensive traces, slow suites, and huge amounts of low-value generated coverage.&lt;/p&gt;

&lt;p&gt;So "more verification" is not the goal.&lt;/p&gt;

&lt;p&gt;What I actually want is more trusted behavioral coverage for less human attention.&lt;/p&gt;

&lt;p&gt;A good invariant can be worth more than hundreds of generated tests. A real production trace can be worth more than many synthetic scenarios. An independent oracle can be more useful than another probabilistic judge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verification is becoming part of the product
&lt;/h2&gt;

&lt;p&gt;Verification-heavy software is not new.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.sqlite.org/testing.html" rel="noopener noreferrer"&gt;SQLite is an extreme public example&lt;/a&gt;. For SQLite 3.42.0, the project reports roughly &lt;strong&gt;155.8 KSLOC&lt;/strong&gt; of library code and a test corpus roughly &lt;strong&gt;590 times larger&lt;/strong&gt;, including multiple independent harnesses, fuzzing, out-of-memory tests, I/O failures, crash and power-loss recovery, boundary tests, and mutation testing.&lt;/p&gt;

&lt;p&gt;I do not think ordinary agent SaaS will look like SQLite.&lt;/p&gt;

&lt;p&gt;The useful point is narrower: when the state space is large and incorrect behavior is expensive, verification can become much larger than the implementation it protects.&lt;/p&gt;

&lt;p&gt;Agents may bring some of that pressure into much more ordinary products.&lt;/p&gt;

&lt;p&gt;A UI can still expose one simple instruction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Update these records from this document."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Behind it, the system may interpret data, inspect state, choose tools, call external systems, mutate records, recover from failures, and decide when approval is required.&lt;/p&gt;

&lt;p&gt;The user-facing surface remains simple. The behavioral surface does not.&lt;/p&gt;

&lt;p&gt;That is why I no longer think "test code" is the right description.&lt;/p&gt;

&lt;p&gt;What grows around an agentic product is a mixture of tests, evals, graders, oracles, fuzzers, policies, traces, replay, audit data, and evidence.&lt;/p&gt;

&lt;p&gt;That is closer to &lt;strong&gt;verification infrastructure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For most of my career, I thought of tests as support code around the product.&lt;/p&gt;

&lt;p&gt;That model feels incomplete once the product itself can decide how to act.&lt;/p&gt;

&lt;p&gt;An agentic product is also defined by answers to questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What may it do?&lt;/li&gt;
&lt;li&gt;What must it never do?&lt;/li&gt;
&lt;li&gt;What counts as success?&lt;/li&gt;
&lt;li&gt;How reliable must success be?&lt;/li&gt;
&lt;li&gt;When is approval required?&lt;/li&gt;
&lt;li&gt;What evidence must exist before we trust the result?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I do not know whether most agentic applications will literally contain more test LOC than product LOC.&lt;/p&gt;

&lt;p&gt;That is not really the prediction.&lt;/p&gt;

&lt;p&gt;The prediction is that implementation will continue to compress relative to the behavior it enables, while executable evidence expands around that behavior.&lt;/p&gt;

&lt;p&gt;We did not just add an agent to the application.&lt;/p&gt;

&lt;p&gt;We had to build a verification system around it that increasingly feels like part of the product itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI is making behavior cheap. Verification is becoming the product boundary.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>evals</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Hard Part of Agent Evals Is Deciding What Counts as Green</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Tue, 25 Aug 2026 11:00:59 +0000</pubDate>
      <link>https://dev.to/gyu07/the-hard-part-of-agent-evals-is-deciding-what-counts-as-green-3a5f</link>
      <guid>https://dev.to/gyu07/the-hard-part-of-agent-evals-is-deciding-what-counts-as-green-3a5f</guid>
      <description>&lt;p&gt;AI agent products still need conventional E2E tests. The UI should open, APIs should behave as expected, permissions should hold, and persistence should not break.&lt;/p&gt;

&lt;p&gt;If deterministic software breaks, I want a deterministic test to turn red.&lt;/p&gt;

&lt;p&gt;But when you build an agent product, you increasingly want another lane next to that: an eval lane that runs the real model and runtime and evaluates the agent itself.&lt;/p&gt;

&lt;p&gt;This is no longer a niche concern. &lt;a href="https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents" rel="noopener noreferrer"&gt;Anthropic describes automated evals as especially useful for pre-launch validation and CI/CD&lt;/a&gt;, and notes that Claude Code has added evals for things like concision, file edits, and over-engineering. The same article describes Descript separating quality benchmarking from regression testing, and Bolt combining static analysis, a browser agent, and LLM judges.&lt;/p&gt;

&lt;p&gt;But once you start building this kind of system, the hard part is not &lt;strong&gt;running&lt;/strong&gt; the eval.&lt;/p&gt;

&lt;p&gt;It is deciding &lt;strong&gt;what counts as Green&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I have been working through this recently while building a real-model agent eval lane. I do not think there is a universal answer yet for what should become a production gate.&lt;/p&gt;

&lt;p&gt;The question I keep coming back to is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which evaluations have earned the right to block a release?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent evals have too many things we could measure
&lt;/h2&gt;

&lt;p&gt;A traditional LLM eval has a relatively compact mental model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompt
  ↓
model / workflow
  ↓
response
  ↓
grader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Correctness, relevance, groundedness, formatting, LLM-as-a-Judge. Of course evals have long been more sophisticated than this, but agents expand the evaluation surface dramatically.&lt;/p&gt;

&lt;p&gt;Once a model can use tools, modify state, retain information, and operate across multiple steps, performance is no longer determined by the model alone. The environment and agent harness matter too.&lt;/p&gt;

&lt;p&gt;Now we can evaluate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final response
tool selection
tool arguments
trajectory
task completion
state mutation
artifact quality
safety
latency
cost
recovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of these can be useful. That is exactly why the problem gets harder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent evals increasingly suffer less from a lack of measurable things than from an excess of them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A production gate does not need more metrics. It needs a much smaller question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What failure are we unwilling to ship?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide the claim before the score
&lt;/h2&gt;

&lt;p&gt;Suppose an agent eval has a 72% pass rate. Is 72% good?&lt;/p&gt;

&lt;p&gt;The number alone cannot tell you. If this is a new capability and the same eval was at 40% last month, 72% may be excellent. If this is a regression suite protecting behavior users already depend on, 72% may be unacceptable.&lt;/p&gt;

&lt;p&gt;Maybe some failures came from the environment. Maybe the grader rejected valid solutions.&lt;/p&gt;

&lt;p&gt;Anthropic makes a useful distinction between capability evals and regression evals. Capability evals measure what an agent can currently do and may reasonably begin with a low pass rate, while regression evals protect behavior that is already expected to work and should usually be much closer to 100%.&lt;/p&gt;

&lt;p&gt;So I have stopped starting with the threshold. I prefer this order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;product claim
     ↓
   oracle
     ↓
   metric
     ↓
 threshold
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"95% means Green" is not a meaningful production gate unless the 95% is attached to a clearly defined claim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The claim and the oracle are what give the threshold meaning.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Look at the world before looking at the model's words
&lt;/h2&gt;

&lt;p&gt;In the eval lane I have been building, I use one rule almost mechanically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the environment already knows the answer, do not use the model's prose as the oracle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the agent says it created an artifact, check whether the artifact actually exists and whether it is valid. If something was supposed to remain unchanged, compare the state before and after.&lt;/p&gt;

&lt;p&gt;If the agent must stay inside a boundary, observe the actual side effects. If an operation should be reversible, roll it back and inspect what remains.&lt;/p&gt;

&lt;p&gt;The response text itself does not need to be the center of the pass/fail decision. For many agent tasks, the environment knows more than the transcript does.&lt;/p&gt;

&lt;p&gt;Anthropic describes a similar distinction between &lt;a href="https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents" rel="noopener noreferrer"&gt;transcript and outcome&lt;/a&gt;. An agent saying "I booked the flight" is a fact about the transcript; whether the reservation actually exists is a fact about the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arxiv.org/abs/2406.12045" rel="noopener noreferrer"&gt;$\tau$-bench&lt;/a&gt; takes a similar approach for tool-using agents by comparing the final database state with an annotated goal state.&lt;/p&gt;

&lt;p&gt;Once you start evaluating agents this way, something interesting happens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a large part of the eval starts looking like ordinary software verification.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But final state is not always enough.&lt;/p&gt;

&lt;p&gt;I ran into this earlier while fuzzing schema migrations. The final schema looked correct, so the test was Green.&lt;/p&gt;

&lt;p&gt;But the path was effectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DROP TABLE
CREATE TABLE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The destination was correct. Production data would still be gone.&lt;/p&gt;

&lt;p&gt;The lesson was:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;destination correctness and path safety are different claims.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same applies to agents. Some properties can be judged entirely from final state, while others cannot.&lt;/p&gt;

&lt;p&gt;If the contract requires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;authorization
    ↓
mutation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the ordering itself matters, and you need to inspect the path.&lt;/p&gt;

&lt;p&gt;So my current rule is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constrain the path only when the path itself has safety or policy meaning. Otherwise, prefer the outcome as the oracle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Agents may discover valid paths we did not anticipate. That is usually a feature, not a bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the cheapest honest judge
&lt;/h2&gt;

&lt;p&gt;Thinking in terms of product claims made it easier for me to separate judges by what they can actually answer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product claim&lt;/th&gt;
&lt;th&gt;Judge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deterministic product machinery works&lt;/td&gt;
&lt;td&gt;unit / integration / E2E&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent reaches a verifiable state&lt;/td&gt;
&lt;td&gt;deterministic outcome check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent never crosses a hard boundary&lt;/td&gt;
&lt;td&gt;deterministic invariant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent follows a required policy path&lt;/td&gt;
&lt;td&gt;trajectory / tool constraint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output is useful, natural, or elegant&lt;/td&gt;
&lt;td&gt;calibrated LLM / human judge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I think of this as the &lt;strong&gt;cheapest honest judge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cheaper is better, and faster is better, but only if that layer can actually answer the property. There is no reason to ask an LLM whether a file exists.&lt;/p&gt;

&lt;p&gt;At the same time, "Was this response genuinely useful for the user's intent?" may not be something a simple boolean function can answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use semantic judges for semantic properties. Use facts where facts exist.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent can be stochastic. The judge does not have to be.
&lt;/h2&gt;

&lt;p&gt;A real model makes the execution stochastic. The same task may produce different wording, tool ordering may change, and multiple solution paths may be valid.&lt;/p&gt;

&lt;p&gt;That makes a single Green/Red run a weak description of quality. In the lane I am building, I run the real model repeatedly and measure success across runs rather than treating one execution as definitive.&lt;/p&gt;

&lt;p&gt;But the component that maps observed facts to pass/fail does not also need to be stochastic.&lt;/p&gt;

&lt;p&gt;A useful separation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;real agent
    ↓
stochastic execution
    ↓
observable facts
    ↓
small deterministic judge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That deterministic judge can itself be exercised extensively with ordinary unit tests. In my setup, contract-violation logic is separated from the real-agent E2E path so I can test it without the model, network, or runtime.&lt;/p&gt;

&lt;p&gt;There is a slightly paradoxical lesson here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To make agent evals more reliable, I try to remove the agent from as much of the eval system as possible.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the real model where only the real model can produce the behavior you need to observe. Then get back to ordinary software as quickly as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not every run should be Green or Red
&lt;/h2&gt;

&lt;p&gt;Real-agent evals have another problem: the environment fails too.&lt;/p&gt;

&lt;p&gt;Rate limits, connection failures, remote service failures. Anthropic recently reported running Terminal-Bench 2.0 under different infrastructure configurations and seeing a six-percentage-point gap between the most and least resourced settings. In some configurations, infrastructure errors unrelated to model capability were themselves around 6%.&lt;/p&gt;

&lt;p&gt;If every one of those runs becomes a product failure, your pass rate stops meaning what you think it means.&lt;/p&gt;

&lt;p&gt;I have found three verdicts more useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pass
fail
inconclusive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;inconclusive&lt;/code&gt; means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;this run did not produce enough evidence to evaluate the product claim.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But that does not mean all evidence should be discarded.&lt;/p&gt;

&lt;p&gt;Suppose the model connection dies halfway through a turn, but before that happens the agent has already crossed a boundary it was never allowed to cross. Task completion is inconclusive; the boundary violation is not.&lt;/p&gt;

&lt;p&gt;An environment failure should not erase an independently observed contract violation.&lt;/p&gt;

&lt;p&gt;The rule I take from this is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"The run did not finish" and "nothing bad happened" are not the same statement.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run status and observed invariant violations should be tracked separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to trust Green, break the judge first
&lt;/h2&gt;

&lt;p&gt;There is one more uncomfortable part of evals: the grader itself can be wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://openai.com/index/separating-signal-from-noise-coding-evaluations/" rel="noopener noreferrer"&gt;OpenAI audited SWE-Bench Pro in July 2026 and estimated that roughly 30% of the public tasks had breaking issues&lt;/a&gt;. Problems included tests enforcing implementation details that were not required by the prompt, hidden underspecified requirements, and weak tests that allowed incomplete fixes to pass.&lt;/p&gt;

&lt;p&gt;A sophisticated agent, a sophisticated harness, and a large eval suite can still fail in a much simpler place:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a bad oracle can measure the wrong thing very precisely.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I want to test the judge itself. Feed it known bad states and make sure they actually turn Red.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;known bad state
      ↓
    judge
      ↓
 does it fail?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A state that should have remained unchanged was mutated. A forbidden side effect occurred. A result that should exist once was duplicated.&lt;/p&gt;

&lt;p&gt;If the judge cannot reliably catch violations I already know about, I have little reason to trust its Green results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The judge is part of the system under test too.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to trust Green, deliberately break something first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not every eval deserves to block a release
&lt;/h2&gt;

&lt;p&gt;None of this means every agent eval should go into blocking CI. Real-model runs cost money, they are slower, they depend on remote infrastructure, and they are stochastic by design.&lt;/p&gt;

&lt;p&gt;More importantly, evals have different jobs. Some explore capability, some calibrate new behavior, some compare quality, and some protect an existing product contract against regression.&lt;/p&gt;

&lt;p&gt;Those should not all share the same threshold or release policy.&lt;/p&gt;

&lt;p&gt;The real-agent eval lane I am building today is still separate from conventional deterministic E2E and is not itself a blocking release gate. It runs the real model repeatedly and accumulates evidence.&lt;/p&gt;

&lt;p&gt;The question is not how many evals we can add.&lt;/p&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which evals are mature enough to justify saying, "If this regresses, do not ship"?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For me, an eval probably needs something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clear product claim
    ↓
explainable oracle
    ↓
grader itself is tested
    ↓
environment noise is separated
    ↓
stability is measured across repeated runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply having an eval score is not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I believe for now
&lt;/h2&gt;

&lt;p&gt;The three principles I keep coming back to are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decide the claim before the score&lt;/li&gt;
&lt;li&gt;Use the cheapest honest judge&lt;/li&gt;
&lt;li&gt;Only mature evals earn the right to block a release&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conventional E2E answers: &lt;strong&gt;Is the deterministic software machinery still correct?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Agent evals answer: &lt;strong&gt;How reliably does the stochastic agent stay inside the product contract?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And the oracle answers: &lt;strong&gt;What does "inside the contract" actually mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The agent's execution can be stochastic. That is exactly why I want the product contract and the judge to be as boring and deterministic as possible.&lt;/p&gt;

&lt;p&gt;AI has made generating behavior much cheaper, and running more evals will probably keep getting cheaper too.&lt;/p&gt;

&lt;p&gt;But the hard part has barely changed: &lt;strong&gt;deciding what deserves to be called Green.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>e2e</category>
      <category>eval</category>
    </item>
    <item>
      <title>AIC: Packages Need an Interface for Coding Agents</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Mon, 10 Aug 2026 06:57:18 +0000</pubDate>
      <link>https://dev.to/gyu07/aic-packages-need-an-interface-for-coding-agents-562o</link>
      <guid>https://dev.to/gyu07/aic-packages-need-an-interface-for-coding-agents-562o</guid>
      <description>&lt;p&gt;I develop several tightly related repositories at the same time.&lt;/p&gt;

&lt;p&gt;Some are reusable SDKs for declarative schemas, infrastructure, stateful workflows, and other domain abstractions. Others are applications that consume several of those SDKs together.&lt;/p&gt;

&lt;p&gt;The development loop constantly crosses package boundaries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; SDK A ──────┐
             │
 SDK B ──────┼──▶ application
             │        │
 SDK C ──────┘        │
    ▲                 │
    └──── feedback ───┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've already written about why I don't think this requires a monorepo, and why I prefer the repository itself to carry the current source of truth:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/gyu07/ai-agents-dont-need-a-monorepo-they-need-a-readable-codebase-4c6f"&gt;AI Agents Don't Need a Monorepo. They Need a Readable Codebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/gyu07/the-repo-is-the-context-why-agents-dont-need-history-4ien"&gt;The Repo Is the Context: Why Agents Don't Need History&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won't repeat those arguments here.&lt;/p&gt;

&lt;p&gt;This post starts one layer later.&lt;/p&gt;

&lt;p&gt;As these SDKs became more agent-aware, each package started needing to tell coding agents how it should be used.&lt;/p&gt;

&lt;p&gt;I was already using project-local surfaces such as &lt;code&gt;.claude/&lt;/code&gt;, &lt;code&gt;.codex/&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;, and package-specific skills. They are useful. Explicit project-local context works.&lt;/p&gt;

&lt;p&gt;The maintenance was the awkward part.&lt;/p&gt;

&lt;p&gt;When an SDK changed, I would tell the agent to update the corresponding instructions, rules, or skills in the consuming repository.&lt;/p&gt;

&lt;p&gt;That worked too.&lt;/p&gt;

&lt;p&gt;But after doing it repeatedly across several packages and repositories, I noticed something:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;My repeated update instructions had quietly become an undocumented protocol.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which files should change?&lt;/p&gt;

&lt;p&gt;Which source is canonical?&lt;/p&gt;

&lt;p&gt;What should be copied?&lt;/p&gt;

&lt;p&gt;What should only be referenced?&lt;/p&gt;

&lt;p&gt;What belongs to the package, and what belongs to the consuming repository?&lt;/p&gt;

&lt;p&gt;How should different coding-agent harnesses receive the same package knowledge without creating independent copies?&lt;/p&gt;

&lt;p&gt;I initially thought I needed a better synchronizer.&lt;/p&gt;

&lt;p&gt;I now think the problem is one layer higher.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Packages already have an interface for programs. They increasingly need an interface for coding agents.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've been calling the protocol I'm using for that interface &lt;strong&gt;AIC — Agent Index Convention&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is still a draft from my own development environment. The exact mechanics will change.&lt;/p&gt;

&lt;p&gt;The boundary it describes feels much more stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The missing package interface
&lt;/h2&gt;

&lt;p&gt;Packages already know how to introduce themselves to programs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package name
version
API
types
schemas
config
CLI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A coding agent needs another set of facts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;where is the current manual?
which rules matter?
which skills are available?
which files are generated?
which commands are safe?
which host-specific configuration applies?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think of this as the package's &lt;strong&gt;agent-facing interface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The problem appears when several packages expose that interface inside the same host repository.&lt;/p&gt;

&lt;p&gt;Without a shared convention, each package tends to solve the problem independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package A ──▶ AGENTS.md
package B ──▶ CLAUDE.md
package C ──▶ .claude/skills/
package D ──▶ .codex/...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each integration can be perfectly reasonable in isolation.&lt;/p&gt;

&lt;p&gt;Composition introduces a different set of problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Failure mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ownership&lt;/td&gt;
&lt;td&gt;one package overwrites human or provider-owned context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freshness&lt;/td&gt;
&lt;td&gt;copied instructions drift from the installed package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discovery&lt;/td&gt;
&lt;td&gt;harnesses load different files and directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composition&lt;/td&gt;
&lt;td&gt;every package assumes it owns the shared surface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This stopped looking like documentation management.&lt;/p&gt;

&lt;p&gt;It started looking like package composition.&lt;/p&gt;

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

&lt;p&gt;AIC separates three actors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Provider package
      │
      │ declares agent-facing assets
      ▼
Host repository
      │
      │ exposes them through actual harness loading paths
      ▼
Coding agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;Provider&lt;/strong&gt; is a package that supplies agent-facing context.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Host&lt;/strong&gt; is the repository consuming that package.&lt;/p&gt;

&lt;p&gt;The provider ships its agent-facing source with the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider-package/
├── agent-index.json
├── AGENTS.md
└── skills/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal manifest might look like:&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;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"agent-index/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"package"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@scope/schema-sdk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.14.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Declarative schema toolkit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manual"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AGENTS.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"schema-design"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"skills/schema-design"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instanceConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"declarative"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"readFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"schema.config.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"runtime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validation"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;agent-index.json&lt;/code&gt; is not another manual.&lt;/p&gt;

&lt;p&gt;It declares:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;identity
version
canonical manual
discoverable assets
host-resolved facts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useful change for me is that the maintenance contract becomes declarative.&lt;/p&gt;

&lt;p&gt;Instead of repeatedly telling an agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Update the Claude and Codex instructions
to match the latest SDK behavior.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it can inspect a structure closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider
  ├── canonical manual
  ├── skills
  ├── resolved host config
  └── target loading semantics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The update no longer depends on how well I happened to describe the maintenance task that day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inject, reference, or materialize
&lt;/h2&gt;

&lt;p&gt;This distinction has probably been the most useful part of AIC in actual use.&lt;/p&gt;

&lt;p&gt;Not all agent-facing assets should cross the package boundary in the same way.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Index&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;identity, version, pointers, resolved config&lt;/td&gt;
&lt;td&gt;inject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Referenced&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;manuals, detailed rules&lt;/td&gt;
&lt;td&gt;keep with provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Materialized&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;harness-discovered skills&lt;/td&gt;
&lt;td&gt;copy deterministically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  ┌── Index  ─────▶ inject
Provider package ─┼── Manual ─────▶ reference
                  └── Skill  ─────▶ materialize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I originally wanted one mechanism for all three.&lt;/p&gt;

&lt;p&gt;Actual loading semantics made that abstraction wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference what can remain version-bound
&lt;/h3&gt;

&lt;p&gt;Copying a manual into the host creates two independently changing truths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;installed package   v0.14
copied manual       v0.13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've hit enough package version-skew problems elsewhere that I don't want to recreate the same class of bug in the agent-context layer.&lt;/p&gt;

&lt;p&gt;Here it is worse than ordinary stale documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A stale instruction consumed by an agent that can edit code and run commands is executable misinformation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The agent may not be hallucinating at all.&lt;/p&gt;

&lt;p&gt;It may be behaving perfectly according to the wrong version.&lt;/p&gt;

&lt;p&gt;So the canonical manual stays with the installed package.&lt;/p&gt;

&lt;p&gt;The host stores a pointer, not another copy.&lt;/p&gt;

&lt;p&gt;In practice, this has been one of the more durable AIC decisions: upgrading the package does not require another manual copy to somehow remain synchronized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Materialize what discovery requires
&lt;/h3&gt;

&lt;p&gt;Skills are different.&lt;/p&gt;

&lt;p&gt;If a harness discovers a skill only by scanning a particular directory, mentioning its package path is not equivalent to putting it where the harness looks.&lt;/p&gt;

&lt;p&gt;The asset needs physical presence.&lt;/p&gt;

&lt;p&gt;So the rule I use is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reference when read access is enough. Materialize when discovery requires presence.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is more useful than either "copy everything" or "never copy."&lt;/p&gt;

&lt;p&gt;Context placement should follow actual loading semantics, not an aesthetically uniform abstraction.&lt;/p&gt;

&lt;p&gt;Of the AIC decisions I've been testing, this asymmetry is one of the ones I currently trust most.&lt;/p&gt;

&lt;h2&gt;
  
  
  One host index, many providers
&lt;/h2&gt;

&lt;p&gt;Each provider contributes a small namespaced block to the host index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Agent index: `@scope/schema-sdk` v0.14.0&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Manual: read &lt;span class="sb"&gt;`node_modules/@scope/schema-sdk/AGENTS.md`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Skills: managed under the harness discovery path
&lt;span class="p"&gt;-&lt;/span&gt; Host config: validation=strict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Several providers can coexist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md
│
├── human-owned content
├── @scope/package-a
├── @scope/package-b
└── @scope/package-c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The central invariant is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A provider owns its namespace, not &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Updating package B may update B's block.&lt;/p&gt;

&lt;p&gt;It may not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rewrite human content
move package A
modify package C
regenerate the whole file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Materialized assets follow the same rule: each provider gets its own collision-safe namespace.&lt;/p&gt;

&lt;p&gt;This is also something I've been able to test rather than only describe.&lt;/p&gt;

&lt;p&gt;In the implementations I'm using, foreign provider blocks are preserved rather than normalized into the current provider's representation. Repeating a sync with the same input is tested as a no-op. Providers can also share lock state without one provider flattening another provider's private fields.&lt;/p&gt;

&lt;p&gt;Those details are intentionally boring.&lt;/p&gt;

&lt;p&gt;But they are the difference between saying "multiple providers can coexist" and actually letting them coexist.&lt;/p&gt;

&lt;p&gt;The packages do not need pairwise integrations.&lt;/p&gt;

&lt;p&gt;Package A does not need to know package B exists.&lt;/p&gt;

&lt;p&gt;Package B does not need a plugin for package C.&lt;/p&gt;

&lt;p&gt;They compose because they share an ownership rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coordination is expensive. Namespaces are cheap.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the point where AIC stopped feeling like a synchronizer to me.&lt;/p&gt;

&lt;p&gt;It started feeling like a package protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Harness-specific files are derived surfaces
&lt;/h2&gt;

&lt;p&gt;AIC is not an argument against &lt;code&gt;.claude/&lt;/code&gt;, &lt;code&gt;.codex/&lt;/code&gt;, or other harness-specific locations.&lt;/p&gt;

&lt;p&gt;I use them because they are useful.&lt;/p&gt;

&lt;p&gt;The problem was maintaining them independently.&lt;/p&gt;

&lt;p&gt;I want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                       ┌── AGENTS.md
                       │
provider source ───────┼── Claude adapter
                       ├── Codex adapter
                       ├── skill discovery adapter
                       └── other thin adapters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;manual
├── Claude copy
├── Codex copy
├── Cursor copy
└── another copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Harness-specific files are &lt;strong&gt;derived surfaces&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The canonical package knowledge remains singular.&lt;/p&gt;

&lt;p&gt;This also gives the design an escape hatch.&lt;/p&gt;

&lt;p&gt;If a harness eventually provides a better native mechanism for consuming package-owned instructions or skills, the adapter should disappear.&lt;/p&gt;

&lt;p&gt;The package boundary does not have to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The adapter layer is expendable. The boundary declaration is not.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction matters because harness behavior will probably change faster than package contracts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sync should be boring
&lt;/h2&gt;

&lt;p&gt;AIC currently has lifecycle operations roughly like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agent-index &lt;span class="nb"&gt;sync
&lt;/span&gt;agent-index check
agent-index remove
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important property is idempotence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;same provider
same version
same source
same managed host state
       │
       ▼
     no-op
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;sync&lt;/code&gt; twice with identical inputs should not produce a second write, timestamp churn, or Git diff.&lt;/p&gt;

&lt;p&gt;For materialized assets, AIC tracks both sides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider source ── hash ──▶ sourceHash
host copy       ── hash ──▶ destHash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinguishes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider upgraded
host copy locally edited
nothing changed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those states should not all result in "copy again."&lt;/p&gt;

&lt;p&gt;The original asset is materialized byte-for-byte. Provenance sits beside it rather than being injected into skill frontmatter, scripts, or templates.&lt;/p&gt;

&lt;p&gt;I don't want sophisticated reconciliation here.&lt;/p&gt;

&lt;p&gt;I want deterministic ownership with boring failure modes.&lt;/p&gt;

&lt;p&gt;There is another reason I care about determinism:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;agents are maintainers too.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A human can often infer that two slightly different layouts represent roughly the same convention.&lt;/p&gt;

&lt;p&gt;An agent benefits more from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;one format
one ownership rule
one lifecycle
one source of truth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The easier the maintenance structure is to inspect mechanically, the less the next agent session has to reconstruct from prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Determinism does not eliminate drift
&lt;/h2&gt;

&lt;p&gt;This is one place where implementation made the tradeoff clearer.&lt;/p&gt;

&lt;p&gt;A protocol can define what should be synchronized without guaranteeing that every synchronization happens immediately.&lt;/p&gt;

&lt;p&gt;I've had cases where a package version and its managed agent state temporarily diverged because a manual step was missed.&lt;/p&gt;

&lt;p&gt;That is exactly the class of problem AIC is intended to make detectable.&lt;/p&gt;

&lt;p&gt;It is also evidence that declaring the protocol does not magically remove its maintenance cost.&lt;/p&gt;

&lt;p&gt;The current split is deliberate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preflight&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cheap version-staleness repair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;full version and integrity verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sync&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;explicit verification and regeneration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The common path stays cheap.&lt;/p&gt;

&lt;p&gt;The stronger path stays explicit.&lt;/p&gt;

&lt;p&gt;I prefer that to turning every CLI startup into a full filesystem integrity scan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generated agent state belongs in Git
&lt;/h2&gt;

&lt;p&gt;I commit the generated index, materialized skills, and lock/provenance state.&lt;/p&gt;

&lt;p&gt;A change like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- ### Agent index: `@scope/schema-sdk` v0.13.0
&lt;/span&gt;&lt;span class="gi"&gt;+ ### Agent index: `@scope/schema-sdk` v0.14.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;changes what the agent can discover.&lt;/p&gt;

&lt;p&gt;A changed materialized skill can change what the agent can do.&lt;/p&gt;

&lt;p&gt;I want those changes visible beside the dependency update that caused them.&lt;/p&gt;

&lt;p&gt;So I think of AIC output more like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Artifact&lt;/th&gt;
&lt;th&gt;Reviewable state&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lockfile&lt;/td&gt;
&lt;td&gt;dependency resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;generated schema&lt;/td&gt;
&lt;td&gt;structural contract&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;migration plan&lt;/td&gt;
&lt;td&gt;intended transition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;agent index / skill&lt;/td&gt;
&lt;td&gt;agent operating context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Generation isn't the problem. Invisible generation is.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preflight repairs; it doesn't claim ownership
&lt;/h2&gt;

&lt;p&gt;Keeping generated state fresh naturally leads to automatic repair.&lt;/p&gt;

&lt;p&gt;This is where I've become deliberately conservative.&lt;/p&gt;

&lt;p&gt;I don't want dependency installation to silently rewrite host-owned files.&lt;/p&gt;

&lt;p&gt;I also don't want the first execution of an SDK CLI to decide by itself that the repository has opted into agent integration.&lt;/p&gt;

&lt;p&gt;So AIC distinguishes adoption from maintenance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;first encounter
    └──▶ warn / explicit sync

existing provider + stale version
    └──▶ repair own namespace

managed content locally edited
    └──▶ preserve + warn

CI / read-only filesystem
    └──▶ don't mutate

removed or disabled provider
    └──▶ stay removed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The invariant is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Automation may maintain established ownership. It should not invent ownership.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a tradeoff.&lt;/p&gt;

&lt;p&gt;Preflight needs an execution opportunity.&lt;/p&gt;

&lt;p&gt;If a dependency is upgraded but the relevant provider CLI has not run yet, materialized state can temporarily remain stale.&lt;/p&gt;

&lt;p&gt;I accept that window today.&lt;/p&gt;

&lt;p&gt;The alternative would be making package installation mutate the host automatically, which I currently consider the worse ownership boundary.&lt;/p&gt;

&lt;p&gt;Teams that need a stricter guarantee can run &lt;code&gt;check&lt;/code&gt; explicitly or in CI.&lt;/p&gt;

&lt;p&gt;So preflight does not eliminate drift.&lt;/p&gt;

&lt;p&gt;It makes the common repair path cheap while leaving full integrity verification explicit.&lt;/p&gt;

&lt;p&gt;This also removes another piece of my old workflow.&lt;/p&gt;

&lt;p&gt;I no longer want this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Please update the agent files after this SDK change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to be part of the development procedure.&lt;/p&gt;

&lt;p&gt;If the relationship is structural, the update rule should be structural too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this actually works today
&lt;/h2&gt;

&lt;p&gt;There is an important qualification.&lt;/p&gt;

&lt;p&gt;The providers I'm using AIC with today are part of the same development environment.&lt;/p&gt;

&lt;p&gt;I control both sides of the protocol.&lt;/p&gt;

&lt;p&gt;That gives me something useful: I can test whether independently versioned packages actually compose through the same rules.&lt;/p&gt;

&lt;p&gt;It does not yet prove that unrelated third-party package authors will adopt them.&lt;/p&gt;

&lt;p&gt;So today I would describe AIC as a &lt;strong&gt;working convention inside one ecosystem&lt;/strong&gt;, not an ecosystem-wide standard.&lt;/p&gt;

&lt;p&gt;The distinction matters because much of the eventual value of a protocol comes from network effects.&lt;/p&gt;

&lt;p&gt;That is the part I have not demonstrated yet.&lt;/p&gt;

&lt;p&gt;There are a few other current assumptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referenced assets require an installed package
&lt;/h3&gt;

&lt;p&gt;A manual that stays inside the installed package is only useful once the dependency is actually available.&lt;/p&gt;

&lt;p&gt;On a fresh clone before dependency installation, the pointer can temporarily lead nowhere.&lt;/p&gt;

&lt;p&gt;I currently accept that because the reference is meant to describe the installed package state.&lt;/p&gt;

&lt;p&gt;It does mean AIC is not a substitute for dependency availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  AIC does not invent universal discovery
&lt;/h3&gt;

&lt;p&gt;AIC relies on an entry point the harness already loads — for example &lt;code&gt;AGENTS.md&lt;/code&gt;, an import into it, or a harness-specific discovery directory.&lt;/p&gt;

&lt;p&gt;It does not solve "how does every possible coding agent discover AIC?" from first principles.&lt;/p&gt;

&lt;p&gt;That is intentional.&lt;/p&gt;

&lt;p&gt;I would rather adapt to real loading behavior than introduce another mandatory bootstrap mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  Materialized assets expand the trust boundary
&lt;/h3&gt;

&lt;p&gt;A referenced manual is information.&lt;/p&gt;

&lt;p&gt;A materialized skill can influence what an agent actually does.&lt;/p&gt;

&lt;p&gt;That makes third-party providers a different trust problem from packages I control myself.&lt;/p&gt;

&lt;p&gt;Content hashes tell me whether an asset changed.&lt;/p&gt;

&lt;p&gt;They do not answer who should be trusted to supply that asset.&lt;/p&gt;

&lt;p&gt;That is one of the areas I would want to make more explicit before treating &lt;code&gt;agent-index/v1&lt;/code&gt; as a third-party ecosystem contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I expect to survive
&lt;/h2&gt;

&lt;p&gt;Agent harnesses are moving quickly.&lt;/p&gt;

&lt;p&gt;Native packaging for instructions, skills, or package-owned agent context may eventually absorb some of what AIC adapters do today.&lt;/p&gt;

&lt;p&gt;If that happens, I don't want to defend the current synchronization machinery for its own sake.&lt;/p&gt;

&lt;p&gt;The parts I expect to survive are smaller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;declare the agent-facing package boundary

own only your namespace

keep canonical knowledge version-bound

separate reference from discovery-required materialization

make derived state deterministic and reviewable

respect prior host ownership decisions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The adapter layer is expendable.&lt;/p&gt;

&lt;p&gt;The boundary declaration is the interesting part.&lt;/p&gt;

&lt;p&gt;That is also why I don't want to freeze the schema too early.&lt;/p&gt;

&lt;p&gt;Before asking unrelated providers to adopt it, I would rather make the convention boring inside the repositories I already operate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fewer drift incidents
fewer manual repair instructions
fewer conventions that exist only in my head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that keeps working, the format has evidence behind it.&lt;/p&gt;

&lt;p&gt;If the ecosystem converges on a better native mechanism, AIC should become a thin adapter to that mechanism rather than compete with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is still draft
&lt;/h2&gt;

&lt;p&gt;The parts I currently think are structural:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;packages need an explicit agent-facing interface&lt;/li&gt;
&lt;li&gt;multiple providers need namespace ownership&lt;/li&gt;
&lt;li&gt;canonical manuals should remain version-bound to their packages&lt;/li&gt;
&lt;li&gt;referenced and discoverable assets need different persistence semantics&lt;/li&gt;
&lt;li&gt;harness-specific surfaces should be derived rather than independent sources of truth&lt;/li&gt;
&lt;li&gt;synchronization should be deterministic and reviewable&lt;/li&gt;
&lt;li&gt;maintenance structures should be easy for agents themselves to inspect&lt;/li&gt;
&lt;li&gt;automatic repair should respect established ownership&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The parts I expect to change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the exact &lt;code&gt;agent-index.json&lt;/code&gt; schema&lt;/li&gt;
&lt;li&gt;workspace and nested-repository scoping&lt;/li&gt;
&lt;li&gt;harness adapters&lt;/li&gt;
&lt;li&gt;skill discovery paths&lt;/li&gt;
&lt;li&gt;preflight policy&lt;/li&gt;
&lt;li&gt;integrity and trust rules for third-party providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a while, I thought I needed a better way to tell coding agents to keep &lt;code&gt;.claude/&lt;/code&gt;, &lt;code&gt;.codex/&lt;/code&gt;, manuals, and skills synchronized.&lt;/p&gt;

&lt;p&gt;Eventually I realized that the repeated instruction was itself the missing specification.&lt;/p&gt;

&lt;p&gt;Packages already know how to introduce themselves to programs.&lt;/p&gt;

&lt;p&gt;AIC is my attempt to give them a small, composable way to introduce themselves to coding agents.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>tooling</category>
      <category>agents</category>
    </item>
    <item>
      <title>Installing OpenTelemetry Won't Close Your AI Agent's Feedback Loop</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Tue, 04 Aug 2026 06:25:36 +0000</pubDate>
      <link>https://dev.to/gyu07/installing-opentelemetry-wont-close-your-ai-agents-feedback-loop-11gf</link>
      <guid>https://dev.to/gyu07/installing-opentelemetry-wont-close-your-ai-agents-feedback-loop-11gf</guid>
      <description>&lt;p&gt;I recently did a lightweight review of how OpenTelemetry (OTel) is being used across three repositories under development at my company:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AI agent application built primarily with Node.js and AWS Lambda&lt;/li&gt;
&lt;li&gt;An Electron-based desktop application&lt;/li&gt;
&lt;li&gt;A TypeScript SDK and compiler for developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three are works in progress. This article is a snapshot of the development environments and codebases at the time of the review, not an assessment of finished products. I used Claude Code to inspect dependencies, configuration, and selected execution paths, so the depth of the review also varied by repository.&lt;/p&gt;

&lt;p&gt;I focused on three questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are we actually using the OpenTelemetry mechanisms that exist in the codebase?&lt;br&gt;
What makes adoption or operation difficult?&lt;br&gt;
Can the resulting telemetry help Claude Code or Codex implement and verify changes?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The background: I have been experimenting with ways to make code, documentation, and runtime behavior easier for coding agents to understand, to get more reliable results from tools such as Claude Code and Codex. I understand OTel's value as a way to give telemetry from different services a shared meaning and a shared causal structure. What I have not yet developed is a confident sense of &lt;em&gt;when&lt;/em&gt; to introduce it and &lt;em&gt;how&lt;/em&gt; to wire it into the everyday development loop.&lt;/p&gt;

&lt;p&gt;My conclusion up front is simple:&lt;/p&gt;

&lt;p&gt;Installing OTel is not the goal. Telemetry becomes part of an AI-assisted development loop only when it is actually generated, accessible to the agent, correlated as one execution, and comparable before and after a change.&lt;/p&gt;

&lt;p&gt;Along the way, I will propose six conditions for agent-usable observability — standardization, propagation, discoverability, controllability, accessibility, and comparability — that I now find more useful than asking "do we have OTel?"&lt;/p&gt;

&lt;h2&gt;
  
  
  "It exists," "it emits," and "the agent can use it" are different states
&lt;/h2&gt;

&lt;p&gt;The three repositories were in very different states:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repository&lt;/th&gt;
&lt;th&gt;State at the time of review&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AI agent application&lt;/td&gt;
&lt;td&gt;No direct OTel usage; relies on structured logs, metrics, X-Ray, and audit records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop application&lt;/td&gt;
&lt;td&gt;A Collector and related environment variables exist, but the application emits little or no telemetry to them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SDK and compiler&lt;/td&gt;
&lt;td&gt;OTel integration is implemented as an opt-in feature, but internal usage is limited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The most useful distinction was between three separate states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An observability mechanism &lt;strong&gt;exists&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It actually &lt;strong&gt;produces telemetry&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;An AI agent can &lt;strong&gt;use that telemetry to make a decision&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A running Collector does not help if the application never emits spans. An integration API does not help if nothing calls it.&lt;/p&gt;

&lt;p&gt;One repository showed the shape of the problem clearly. A tracing middleware existed — typed, exported, and documented — but the application's middleware pipeline never included it. Everything about the module looked "done," yet the system produced zero trace data. A coding agent grepping the repo would find a plausible-looking observability layer, and nothing to read at runtime.&lt;/p&gt;

&lt;p&gt;This was not specific to OTel. A custom trace system in another repository had the same gap: trace types and debugging features existed, but the middleware was not connected to the runtime.&lt;/p&gt;

&lt;p&gt;The underlying failure mode: &lt;strong&gt;we treat the implementation of an observability mechanism as completion, without verifying that it produces evidence and that someone — or something — actually consumes it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenTelemetry's core value
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; is a vendor-neutral framework for generating, collecting, and exporting signals such as traces, metrics, and logs. The &lt;a href="https://opentelemetry.io/docs/collector/" rel="noopener noreferrer"&gt;OpenTelemetry Collector&lt;/a&gt; provides a common pipeline for receiving, processing, and forwarding telemetry to one or more backends.&lt;/p&gt;

&lt;p&gt;From the perspective of a coding agent, two parts are especially valuable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared meaning
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/specs/semconv/" rel="noopener noreferrer"&gt;Semantic Conventions&lt;/a&gt; standardize not only attribute names, but also their types, meanings, and units across common domains such as HTTP, databases, RPC, and messaging. When the same concept is represented by the same attribute across repositories, Claude Code or Codex has less project-specific naming to infer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared causality
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/concepts/context-propagation/" rel="noopener noreferrer"&gt;Context propagation&lt;/a&gt; carries trace context across process and network boundaries so that distributed operations can be connected as one causal chain. Individual logs may be searchable, but if an API request, an async job, a worker execution, and an audit event cannot be associated with the same operation, it is hard to establish what actually caused a failure.&lt;/p&gt;

&lt;p&gt;To me, the core value of OTel is not that it creates more telemetry. It gives telemetry from different execution environments a shared vocabulary and a common correlation key.&lt;/p&gt;

&lt;h2&gt;
  
  
  An agent can read a system without OTel
&lt;/h2&gt;

&lt;p&gt;The first repository did not use OTel at all — yet it was the easiest for the agent to inspect.&lt;/p&gt;

&lt;p&gt;It had structured logs, cloud metrics, X-Ray traces, audit records, and a data pipeline that allowed operational data to be re-queried with SQL. Some of the available datasets and analysis procedures were described as repository-level contracts.&lt;/p&gt;

&lt;p&gt;In that kind of system, a coding agent can inspect runtime behavior just fine.&lt;/p&gt;

&lt;p&gt;So in the repositories I reviewed, OTel was &lt;strong&gt;neither a necessary nor a sufficient condition&lt;/strong&gt; for AI-readable observability. The real requirement was that telemetry be structured, actually generated, reachable by the agent, and joinable as one execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI readability depends on where the data appears
&lt;/h2&gt;

&lt;p&gt;The review also revealed a much more basic requirement:&lt;/p&gt;

&lt;p&gt;Can Claude Code or Codex reach the data with the tools already available in the session — Read, Grep, and a shell?&lt;/p&gt;

&lt;p&gt;In one repository, a lightweight trace written into the workspace as JSON and Markdown was the easiest runtime artifact for the agent to use. A richer trace existed in cloud storage, but reaching it required authentication, environment setup, network access, and waiting. That made it far less likely to be used in a loop measured in seconds.&lt;/p&gt;

&lt;p&gt;For the development loops I reviewed, accessibility looked roughly 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;Local files and stdout
  &amp;gt; Read-only MCP, CLI, or SQL access
  &amp;gt; An authenticated cloud UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a universal ranking — cloud telemetry is essential for production incidents. But when an agent edits and validates in a tight loop, immediate local access wins.&lt;/p&gt;

&lt;p&gt;Fortunately, OTel makes the local path cheap. OTel SDKs commonly provide development exporters that write telemetry to the console or stdout — the &lt;a href="https://opentelemetry.io/docs/languages/python/exporters/" rel="noopener noreferrer"&gt;Python SDK&lt;/a&gt;, for example. The Collector's &lt;a href="https://opentelemetry.io/docs/collector/configuration/" rel="noopener noreferrer"&gt;debug exporter&lt;/a&gt; can print telemetry locally, while the Collector Contrib distribution also provides a file exporter. Third-party terminal viewers such as &lt;a href="https://github.com/ymtdzzz/otel-tui" rel="noopener noreferrer"&gt;otel-tui&lt;/a&gt; let you inspect OTLP locally without any backend. When introducing OTel, wiring up a dev-mode path to stdout or local files first — before any remote backend — gives the agent something to read on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six conditions for agent-usable observability
&lt;/h2&gt;

&lt;p&gt;This is the framework I now use instead of "is OTel installed?":&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standardization&lt;/td&gt;
&lt;td&gt;Are attribute meanings, types, and units defined?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Propagation&lt;/td&gt;
&lt;td&gt;Can the same execution be followed across HTTP and async boundaries?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discoverability&lt;/td&gt;
&lt;td&gt;Can the available attributes and datasets be enumerated programmatically?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controllability&lt;/td&gt;
&lt;td&gt;Can time ranges, result limits, and permissions be safely constrained?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accessibility&lt;/td&gt;
&lt;td&gt;Can the agent read the data within its implementation loop?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comparability&lt;/td&gt;
&lt;td&gt;Can the state before and after a change be evaluated under the same conditions?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Different layers of the stack serve different conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTel is particularly strong at &lt;strong&gt;standardization&lt;/strong&gt; and &lt;strong&gt;propagation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Collectors and backends support processing, storage, and &lt;strong&gt;controllability&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;MCP servers, CLIs, SQL interfaces, and local files support &lt;strong&gt;discoverability&lt;/strong&gt; and &lt;strong&gt;accessibility&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Queries, tests, and analytical models that evaluate changes support &lt;strong&gt;comparability&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No single layer closes the development loop by itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  OTel does not define domain meaning
&lt;/h2&gt;

&lt;p&gt;Semantic Conventions primarily standardize infrastructure concerns. They do not fully express domain-specific events from an AI agent system, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A guard rejected an operation&lt;/li&gt;
&lt;li&gt;A hazardous action required approval&lt;/li&gt;
&lt;li&gt;The system returned a correctable error&lt;/li&gt;
&lt;li&gt;A particular next action became available&lt;/li&gt;
&lt;li&gt;A decision was based on a specific piece of evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adopting OTel does not remove the need for custom attributes and repository-level schema contracts. Work is continuing on GenAI-related conventions in the &lt;a href="https://github.com/open-telemetry/semantic-conventions" rel="noopener noreferrer"&gt;Semantic Conventions repository&lt;/a&gt;, including conventions for GenAI clients and MCP — but that still does not mean every agent- or workflow-specific concept can or should be standardized.&lt;/p&gt;

&lt;p&gt;A native execution trace may also carry richer information than an OTel span: correction codes, permitted next actions, references to evidence, state transitions, replay information. In such systems, OTel should not necessarily replace the native trace. A more natural separation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep domain-specific execution data in the native trace&lt;/li&gt;
&lt;li&gt;Project shared operational meaning and cross-system causality into OTel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The OTel representation may be a deliberately &lt;strong&gt;lossy projection&lt;/strong&gt; of the richer native trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not put internal IDs directly into &lt;code&gt;traceparent&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The SDK and compiler repository exposed a concrete integration problem.&lt;/p&gt;

&lt;p&gt;Suppose the system uses human-readable internal identifiers such as:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Those values cannot be placed directly into the Trace ID or Parent ID fields of &lt;code&gt;traceparent&lt;/code&gt;. Under the &lt;a href="https://www.w3.org/TR/trace-context/" rel="noopener noreferrer"&gt;W3C Trace Context specification&lt;/a&gt;, the Trace ID must be 32 lowercase hex characters and the Parent ID 16, and all-zero values are invalid. A naive conversion produces something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00-0000000000000000000000trace_0001-run_abc000000000-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A compliant receiver must ignore the invalid &lt;code&gt;traceparent&lt;/code&gt;, so the downstream operation may start a new trace or remain uncorrelated — propagation silently fails.&lt;/p&gt;

&lt;p&gt;The cleaner design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let the tracer generate valid OTel Trace IDs and Span IDs&lt;/li&gt;
&lt;li&gt;Preserve the internal execution ID as a span attribute&lt;/li&gt;
&lt;li&gt;Make the two identifiers joinable at query time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And note: the existence of a propagation helper does not prove propagation works. Test it across a real service boundary and confirm the resulting spans land in the same trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  OTel and audit evidence serve different purposes
&lt;/h2&gt;

&lt;p&gt;Introducing OTel does not mean replacing existing logs, audit records, or native traces:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;Primary purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Spans&lt;/td&gt;
&lt;td&gt;Latency, errors, and distributed causal analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metrics&lt;/td&gt;
&lt;td&gt;Aggregation, trends, and alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs&lt;/td&gt;
&lt;td&gt;Detailed event and exception search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit records&lt;/td&gt;
&lt;td&gt;Accountability, critical actions, and tamper evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native traces&lt;/td&gt;
&lt;td&gt;State transitions, corrections, and deterministic replay&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Audit records that require tamper detection or deterministic replay should not be moved into sampled OTel spans. OTel is a common observability layer, not an audit ledger.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP can become the agent-facing query layer
&lt;/h2&gt;

&lt;p&gt;Standardized telemetry is not enough; the agent also needs a safe interface for querying it.&lt;/p&gt;

&lt;p&gt;At the time of writing, Grafana provides an &lt;a href="https://grafana.com/docs/grafana/latest/developer-resources/mcp/" rel="noopener noreferrer"&gt;official MCP server&lt;/a&gt; and documents connecting Claude Code and Codex CLI to observability data. Sentry provides an &lt;a href="https://docs.sentry.io/product/sentry-mcp/" rel="noopener noreferrer"&gt;official MCP integration&lt;/a&gt; for exposing issue and error data to coding agents.&lt;/p&gt;

&lt;p&gt;A useful division of responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OTel provides shared meaning and causality&lt;/li&gt;
&lt;li&gt;MCP, CLI, and SQL interfaces provide the agent-facing query surface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But a query interface is not automatically safe or useful. It still needs read-only access, controllable time ranges and result limits, discoverable attributes, repeatable queries, and before-and-after comparison — the six conditions again, viewed from the interface side.&lt;/p&gt;

&lt;h2&gt;
  
  
  The coding agent is also a telemetry source
&lt;/h2&gt;

&lt;p&gt;One more angle worth noting for readers using Claude Code: the agent is not only a reader of telemetry.&lt;/p&gt;

&lt;p&gt;Claude Code supports OTel export of its own metrics and events — sessions, token usage, tool executions — enabled via environment variables such as &lt;code&gt;CLAUDE_CODE_ENABLE_TELEMETRY=1&lt;/code&gt; and &lt;code&gt;OTEL_METRICS_EXPORTER&lt;/code&gt; / &lt;code&gt;OTEL_LOGS_EXPORTER&lt;/code&gt; (with &lt;code&gt;console&lt;/code&gt; available as an exporter for local debugging). Events emitted while processing a single user prompt share a &lt;code&gt;prompt.id&lt;/code&gt; attribute, so a prompt's API calls and tool executions can be correlated in the backend. See the &lt;a href="https://code.claude.com/docs/en/monitoring-usage" rel="noopener noreferrer"&gt;official monitoring documentation&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;This closes an interesting circle: the same standardization and propagation that make your system readable to the agent can also make the agent's behavior readable to your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part is often the data boundary, not instrumentation
&lt;/h2&gt;

&lt;p&gt;When introducing OTel, configuring an SDK or Collector may not be the hardest part. The harder question is what should be recorded and where it should be sent.&lt;/p&gt;

&lt;p&gt;URLs, SQL statements, exceptions, prompts, tool arguments, and user data can unintentionally appear in telemetry. The &lt;a href="https://opentelemetry.io/docs/security/handling-sensitive-data/" rel="noopener noreferrer"&gt;OpenTelemetry guidance on handling sensitive data&lt;/a&gt; recommends avoiding collection of sensitive information where possible, and describes removing or transforming data with Collector processors (attribute, filter, redaction, transform).&lt;/p&gt;

&lt;p&gt;However, moving all redaction responsibility into the Collector can make critical policy invisible from the application repository. Collector configuration should be versioned, reviewed, and tested alongside the application — or the application should at least maintain a clear contract describing which attributes may be collected.&lt;/p&gt;

&lt;p&gt;OTLP export is also a new egress path. In environments with restricted networking, connectivity to a Collector or remote backend becomes part of the architecture and security design. Adding observability can mean adding a communication boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud telemetry introduces a time gap
&lt;/h2&gt;

&lt;p&gt;When an agent uses cloud telemetry to validate a change, there is an unavoidable sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Change
→ Build
→ Deploy
→ Execute
→ Export telemetry
→ Ingest into the backend
→ Query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the architecture, stable query results may take tens of seconds to several minutes. A local loop measured in seconds and a cloud loop measured in minutes are different feedback cycles, and a practical setup combines both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deterministic local tests&lt;/li&gt;
&lt;li&gt;Local trace files&lt;/li&gt;
&lt;li&gt;Smoke tests in a development environment&lt;/li&gt;
&lt;li&gt;Before-and-after comparisons using cloud telemetry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requiring the agent to deploy and wait for ingestion after every change makes the everyday loop unnecessarily heavy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The order I would use today
&lt;/h2&gt;

&lt;p&gt;Based on this review, I would approach agent-readable observability in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect instrumentation to a real execution path so telemetry is actually generated&lt;/li&gt;
&lt;li&gt;Make development output readable through local files or stdout&lt;/li&gt;
&lt;li&gt;Propagate trace context across HTTP, queues, and workers&lt;/li&gt;
&lt;li&gt;Keep business and execution IDs as separate attributes, not inside standard trace IDs&lt;/li&gt;
&lt;li&gt;Define Semantic Conventions and custom attributes as repository-level contracts&lt;/li&gt;
&lt;li&gt;Establish policies for sensitive data, cardinality, and sampling&lt;/li&gt;
&lt;li&gt;Provide read-only access through MCP, CLI, or SQL&lt;/li&gt;
&lt;li&gt;Make before-and-after comparisons repeatable under the same conditions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would not begin with comprehensive auto-instrumentation. It is easier to evaluate OTel by picking one important path and completing the entire chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate → Propagate → Store → Query → Compare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An AI agent does not need to stare at a large number of spans. It needs to determine what changed because of its own modification, and verify that conclusion again under the same conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  OTel is a common language, not the finished system
&lt;/h2&gt;

&lt;p&gt;The three repositories in this review are still under development, and their implementations will change. Even so, one distinction became much clearer: having OTel, generating telemetry, and making that telemetry usable by an agent are three different stages — and only the last one closes the loop.&lt;/p&gt;

&lt;p&gt;Turning telemetry into part of an AI-assisted development loop requires more than instrumentation: it also requires access paths, domain schemas, data boundaries, and repeatable before-and-after evaluation. The right starting point is therefore not comprehensive instrumentation, but one minimal path where telemetry is reliably generated, accessible to the agent, and comparable across a change.&lt;/p&gt;

&lt;p&gt;OTel is not the finished form of observability for coding agents.&lt;/p&gt;

&lt;p&gt;It is one of the strongest common languages available for building telemetry that is structured, correlated, and reproducible enough for them to use.&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>observability</category>
      <category>ai</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>Why My Local Coding Agent Could Act but Couldn't Finish</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Wed, 29 Jul 2026 07:53:24 +0000</pubDate>
      <link>https://dev.to/gyu07/why-my-local-coding-agent-could-act-but-couldnt-finish-81d</link>
      <guid>https://dev.to/gyu07/why-my-local-coding-agent-could-act-but-couldnt-finish-81d</guid>
      <description>&lt;p&gt;There was a month where I blew through my token budget without noticing. Claude Code and Codex, running most of the day, on a codebase I was exploring more than editing. The ceiling I'd set turned out to be a number I'd passed weeks earlier, and I found out by getting the bill.&lt;/p&gt;

&lt;p&gt;So I did the thing I'd been putting off, and ran a coding agent on my own machine to see what happened.&lt;/p&gt;

&lt;p&gt;The short version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Qwen Code, driving a quantized Qwen against a local llama.cpp server, built the UI fine.&lt;/strong&gt; A video-site clone from scratch: header, sidebar, grid, watch page, all of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Then it couldn't work out why the thumbnails and video files weren't being served.&lt;/strong&gt; Almost every tool call executed cleanly. The investigation made no progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It was also slower than Claude Code or Codex, and my best guess for why is repeated prompt processing rather than generation speed.&lt;/strong&gt; I'll say what would actually settle that when I get there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this is a benchmark. These are notes on where my thinking has drifted, written down mostly so I can find out where it's wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where my framing was off
&lt;/h2&gt;

&lt;p&gt;The story I'd been telling myself was that token prices are going up. I can't really support that. Unit prices haven't broadly risen; my consumption did, and the shape of agentic coding is why. A turn in these loops can carry the system prompt, the tool definitions, the files already read, and the history along with it, so usage climbs with your setup as much as your effort.&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://medium.com/@takafumi.endo/token-allocation-the-new-capital-discipline-of-ai-native-companies-15a9183fe083" rel="noopener noreferrer"&gt;wrote on Medium&lt;/a&gt; that token spend only becomes an &lt;em&gt;asset&lt;/em&gt; when you redesign the work around it. My first response to the bill wasn't to switch models. It was to notice that most of the tokens went into &lt;em&gt;finding things&lt;/em&gt;, and to build a terminal emulator with tree-sitter and LSP folded in, so the agent could get deterministic answers to "who calls this." That became &lt;a href="https://dev.to/gyu07/rigor-compresses-why-ai-agents-need-graphs-not-more-context-5404"&gt;the graphs argument&lt;/a&gt;, and it comes back at the end meaning something I hadn't intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two reasons to go local, and I'd rather not mix them
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cost.&lt;/strong&gt; Frontier APIs charge per token; local open-weight inference doesn't. This is what got me looking, and on my hardware it doesn't hold: what I stop paying in dollars comes back as wall-clock and retries, which are scarcer than money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Locality.&lt;/strong&gt; Some work wants to be near the actor, being private, high-churn, latency-sensitive, or offline-capable, and that holds regardless of what a token costs. This one I believe, and it's the same &lt;a href="https://dev.to/gyu07/why-ai-agents-make-me-reach-for-sqlite-4dh0"&gt;state-gravity&lt;/a&gt; reasoning I keep landing on elsewhere.&lt;/p&gt;

&lt;p&gt;Same hardware, different conclusions. I'd rather not borrow the second to prop up the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I had wrong about Qwen
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://qwen.ai/blog?id=qwen3-coder-next" rel="noopener noreferrer"&gt;Qwen3-Coder-Next&lt;/a&gt; is described by its team as being for coding agents and &lt;em&gt;local development&lt;/em&gt;, with emphasis on long-horizon runs, tool use, and recovering from failed execution. That last item is a loop property rather than a generation property, and a telling thing to optimise for. Apache 2.0 throughout, which for anything pointed at a real codebase is a gate that comes before capability.&lt;/p&gt;

&lt;p&gt;I'd also been repeating that &lt;a href="https://github.com/QwenLM/qwen-code" rel="noopener noreferrer"&gt;Qwen Code&lt;/a&gt; is a Gemini CLI fork. It did start as one, and in lineage terms still is, but it stopped syncing upstream early and has grown its own subagents, hooks, and MCP support. What matters here is that it's backend-agnostic: the same harness points either at a local endpoint or a commercial API, which is as close to a controlled comparison as I get on one laptop. Qwen also describes it as reaching feature parity with Claude Code, which is worth holding loosely, since feature parity and outcome parity are separate claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;3B active&lt;/code&gt; is a compute number, not a memory number
&lt;/h2&gt;

&lt;p&gt;The correction that most changed how I read model announcements. Activated parameters govern compute per token; total parameters govern the memory to hold the weights. Qwen3-Coder-Next activates around 3B and still has 80B in total, which at 4-bit is on the order of 40 GB for weights alone, before runtime overhead, KV cache, and the context you actually wanted. On a 64 GB machine that makes it a candidate rather than a comfortable one, and the margin thins exactly where I'd want it. It cuts the other way too: I'd filed myself under "small quantized models only," and the quantized 30B-odd class in fact runs with real headroom at this size.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Loading a model and running it comfortably over a long context are two different capabilities, and only the first appears in a requirements table.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which is why I care about this tier rather than the top of the range. What decides whether local inference becomes &lt;em&gt;normal&lt;/em&gt; is what runs on a machine a working developer already bought.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sessions
&lt;/h2&gt;

&lt;p&gt;Two sittings in April, an evening and then the following afternoon. They weren't the same task: the first picked up a half-finished short-video feed clone and carried on, the second built a video site from scratch. Different tasks, different days, different models, so nothing here is controlled. It's a log rather than an experiment.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Machine&lt;/td&gt;
&lt;td&gt;MacBook Pro · M2 Max · 64 GB unified memory · macOS 26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;llama-server&lt;/code&gt;, llama.cpp b8680, Metal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;Qwen Code 0.14.5, over the OpenAI-compatible endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Models&lt;/td&gt;
&lt;td&gt;Qwen3-Coder-Next (80B total, IQ4_XS) · Qwen3.6-35B-A3B (unsloth dynamic Q4_K_M GGUF, ~21 GB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;131,072, compaction at 50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flags&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--jinja -ngl 99 -c 131072 -b 512 -ub 256&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two notes on that. In this setup &lt;code&gt;--jinja&lt;/code&gt; was needed for Qwen Code's tool calls to work at all, and depending on GGUF metadata llama.cpp may also want an explicit tool-aware chat template. The prompt batch is small, 512 with a micro-batch of 256, because anything larger died with a Metal compute error. That one matters later: batching governs how fast context gets ingested, and I had throttled it before I started measuring.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Session&lt;/th&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;wall-clock&lt;/th&gt;
&lt;th&gt;tool calls&lt;/th&gt;
&lt;th&gt;reissued&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Evening, day 1&lt;/td&gt;
&lt;td&gt;feed clone, resuming&lt;/td&gt;
&lt;td&gt;~1h25m&lt;/td&gt;
&lt;td&gt;151&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 2, first&lt;/td&gt;
&lt;td&gt;video site, from scratch&lt;/td&gt;
&lt;td&gt;~3h20m&lt;/td&gt;
&lt;td&gt;154&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day 2, second&lt;/td&gt;
&lt;td&gt;same, continued&lt;/td&gt;
&lt;td&gt;~1h20m&lt;/td&gt;
&lt;td&gt;240&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Reissued" just means the agent sent the call again. The logs don't separate malformed arguments from non-zero exits from failing tests, and a command that fails and then gets fixed is arguably the harness working, so the column reads better as friction than as an error rate. Day one is muddier still, with dozens of server-side compute errors that belong to the runtime rather than the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part it couldn't finish
&lt;/h2&gt;

&lt;p&gt;The second session is the one I keep thinking about. The UI came out, and came out well: header, sidebar with the full nav, category chips, a video grid with channel names and view counts and duration badges, and a watch page with player, title, subscriber count, like and dislike, share, description. All of it correct.&lt;/p&gt;

&lt;p&gt;What never loaded was the contents of &lt;code&gt;public/&lt;/code&gt;. Every thumbnail in the grid was a broken-image icon with its alt text showing through, and the player sat on a black frame with a spinner reading &lt;code&gt;0:00 / 0:00&lt;/code&gt;. A complete site with nothing in the slots.&lt;/p&gt;

&lt;p&gt;The last hour or so of that session is the agent chasing that one 404, and the shape of it is the part worth looking at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;observed: thumbnails return 404
  │
  ├─▶ restart the dev server ....... call ok · 404 remains
  ├─▶ try a production build ....... call ok · 404 remains
  ├─▶ flatten the directory layout . call ok · 404 remains
  ├─▶ rewrite the database paths ... call ok · 404 remains
  └─▶ drop the SQL approach ........ call ok · 404 remains
                                     │
                                     └─ each call accepted and run,
                                        none of them establishing
                                        which path was being served
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much of that final session went into that loop. My last message in the log is a flat "this isn't working."&lt;/p&gt;

&lt;p&gt;So the pair of numbers I keep returning to is this: of 240 tool calls, 232 went through without needing to be reissued, and the bug was still there at the end. That's a per-call rate, not a measure of how finished anything was. It had the competence to reproduce a large, fiddly interface from scratch, then couldn't work out why a static file wasn't being served, a smaller and much more boring problem than the one it had just solved. It kept generating plausible fixes for the wrong layer.&lt;/p&gt;

&lt;p&gt;I'd call that a &lt;strong&gt;diagnosis&lt;/strong&gt; problem rather than a generation one: forming and discarding hypotheses about a system it built itself, with no cheap way to check any of them. Which is the honest answer to whether a quantized local coder can ship a non-trivial front end. It can produce a lot of good code and still not close the last inch.&lt;/p&gt;

&lt;p&gt;My prior experience makes me suspect Claude Code would have got out of that hole faster, and this run offers no evidence for that comparison: no matched run, nothing held constant, no recording, so there's no row for it in the table. It's a narrow suspicion anyway. Not about code quality, but about how quickly the loop notices it's fixing the wrong thing. I mention it because leaving it out would flatter the local run.&lt;/p&gt;

&lt;h2&gt;
  
  
  As for the time
&lt;/h2&gt;

&lt;p&gt;"It's slower" turned out to be doing no work at all. Any of these could be the culprit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;time to first response&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;prompt processing throughput&lt;/strong&gt;, meaning how fast it ingests context&lt;/li&gt;
&lt;li&gt;output token generation speed&lt;/li&gt;
&lt;li&gt;number of tool calls and reissues&lt;/li&gt;
&lt;li&gt;context length and compaction behaviour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Published write-ups on agentic coding point at the same place. In a loop like this, each turn can require the server to process the system prompt, the tool definitions, the retained file context, and the conversation so far all over again, so the same material gets worked through dozens of times in one task, and prompt processing can eventually dominate generation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;call 1   [ system · tools · files read · history ] ──▶ one short action
call 2   [ system · tools · files read · history ] ──▶ one short action
call 3   [ system · tools · files read · history ] ──▶ one short action
  ⋮               re-read in full, longer each time
×240

   writing   a few hundred tokens per call
   reading   the entire transcript, per call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
 Meanwhile decode speed on my hardware class keeps improving, going by &lt;a href="https://ollama.com/blog/mlx-performance" rel="noopener noreferrer"&gt;the numbers runtimes are publishing for Apple Silicon&lt;/a&gt;. The axis being optimised hardest is the one I'd already stopped waiting on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bottleneck may be less about the model writing than the model re-reading.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I want to be exact about that sentence's status. All I have is wall-clock, call counts, and reissues. What would settle it is cumulative prompt time against decode time, prompt tokens against tokens generated, and how much of each prompt came from cache, all of which &lt;code&gt;llama-server&lt;/code&gt; reports and none of which I collected. So: leading suspect, consistent with how these harnesses behave, not demonstrated here. If prompt time turns out to be a minority of the total, the explanation doesn't hold.&lt;/p&gt;

&lt;p&gt;If it does hold, the tooling detour means something I hadn't intended. Vague context is charged twice locally, once in tokens and once in wall-clock, every loop. Handing an agent short deterministic facts instead of files to re-read is a cost optimisation against a metered API; on hardware I own it becomes a latency optimisation, and I'm the one sitting there for it. The way that second session ended is the same argument from the other side: an agent that could cheaply ask which file was being served wouldn't have spent an hour fixing one that wasn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  I wanted to blame quantization
&lt;/h2&gt;

&lt;p&gt;Behaviour was less stable than I'm used to, with tool calls going sideways and loops not recovering cleanly, and my instinct was to file it under quantization. That instinct was mostly a wish for a tidy story.&lt;/p&gt;

&lt;p&gt;Quantization does affect quality, and published comparisons show that two schemes at the same bit width can behave measurably differently, which is why I named both of mine. But the candidates I can't separate go well past it. The base models' tool-use ability, chat-template fit, sampling settings, context bloat over a long run, the runtime, the throttled batch size, the quantization recipe. That's a list of things to check rather than a cause, and most of it I can change without swapping models.&lt;/p&gt;

&lt;p&gt;The same caution applies across the two sessions. Qwen3-Coder-Next is the model my own arithmetic said would fit but not comfortably, and it reissued roughly one call in five while throwing repeated Metal errors, where the smaller one ran much more cleanly. Memory pressure is my leading explanation, but it was a different model on a different task with a different 4-bit recipe, so I'd read it as suggestive. What survives is that bit width alone explains nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swappability is an investigation virtue, not a production one
&lt;/h2&gt;

&lt;p&gt;Fixing a local OpenAI-compatible server as the execution layer is what made this tractable: the runtime stays put and I recombine around it. It may also be why it broke.&lt;/p&gt;

&lt;p&gt;Look at those candidates again and notice how many are interface problems rather than capability problems. Template fit, tool-call formatting, sampling defaults, context compaction. Those are seams. A stack where one organisation post-trains the model and ships the agent doesn't have seams there, because the model was trained against that harness's tool loop, on its own tool schema, with its own recovery behaviour. The interface has been tested as one product.&lt;/p&gt;

&lt;p&gt;So the view I've drifted to, an impression from use rather than something measured, is that model and harness are better evaluated as a single unit, and that the OpenAI × Codex and Anthropic × Claude Code advantage may come not only from model quality but from having no seam to misfit.&lt;/p&gt;

&lt;p&gt;Cursor is the interesting exception, having stayed model-flexible while also training its own model against its own editor and tools. Notably it built that on someone else's open checkpoint, which suggests the load-bearing part is the co-design rather than owning the pretraining.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objections I'd raise myself
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Your bottleneck is the runtime, not the model."&lt;/strong&gt; Probably partly true, and I handed you the evidence: I was running a throttled prompt batch to stop Metal crashing, which sits directly in the path of the thing I'm complaining about. Whether it's the cause, I can't say without the prefill numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Your test flatters the local model."&lt;/strong&gt; Agreed. A front-end build is generous work, being well-specified and verifiable, and it still didn't finish. A long refactor across an unfamiliar repo is where this would compound worst.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Just rent a cloud GPU."&lt;/strong&gt; The option I'm least able to assess. It removes the memory ceiling and hands you ops, utilisation risk, and cost modelling in return. I notice I keep not choosing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"The gap is closing, so this post expires."&lt;/strong&gt; Probably. That's rather the point of re-running the test.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where this leaves me
&lt;/h2&gt;

&lt;p&gt;Either the open tier keeps compressing until a long local loop is comfortable, or the coupled stacks keep pulling ahead in ways a swappable arrangement can't track. I'd prefer the first, and I'm not confident enough to plan around it. Meanwhile the on-device direction is already being built into Apple's and Google's frameworks as a split rather than a migration, with private, low-latency work on the device and the heavy inference elsewhere, which makes the question &lt;em&gt;which parts route where&lt;/em&gt; rather than &lt;em&gt;local or hosted&lt;/em&gt;. Doing all of this by hand reads like the phase before that.&lt;/p&gt;

&lt;p&gt;So I keep reinstalling. Every few months, same test, same laptop, and I write down where it broke. It hasn't changed what I open on a Tuesday. It has changed what I think I'm buying when I do, which is less about tokens and more about something that can work out which file is actually being served. Next time I'll log the prompt timings, and then I'll know whether any of this is true.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>localllm</category>
      <category>qwen</category>
      <category>agents</category>
    </item>
    <item>
      <title>Why Legacy Rewrites Need a Judge, Not a Better Prompt</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Tue, 28 Jul 2026 07:59:03 +0000</pubDate>
      <link>https://dev.to/gyu07/why-legacy-rewrites-need-a-judge-not-a-better-prompt-50ea</link>
      <guid>https://dev.to/gyu07/why-legacy-rewrites-need-a-judge-not-a-better-prompt-50ea</guid>
      <description>&lt;p&gt;Lately I keep getting asked about legacy replacements.&lt;/p&gt;

&lt;p&gt;It's become one of the more common conversations I have, and the framing is almost always the same: &lt;em&gt;AI can rewrite this now, can't it?&lt;/em&gt; The demand is clearly rising, and I don't think the premise is wrong. A coding agent can rewrite a legacy application startlingly fast. Producing the new code has stopped being the bottleneck.&lt;/p&gt;

&lt;p&gt;What hasn't moved is the ability to say &lt;em&gt;the new system behaves like the old one&lt;/em&gt;. That turns out to be a claim nobody has the evidence to make — about either system.&lt;/p&gt;

&lt;p&gt;So when one of these comes up now, analyzing the old code is no longer where I'd start. That's not the obvious move: the default is to understand the old system first, then rebuild from that understanding. It's the order every plan I've seen begins in, and it's the order we tried, with a coding agent doing the analysis. The honest summary is that it didn't converge.&lt;/p&gt;

&lt;p&gt;The approach I've drifted into instead:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Record the old system's observable behavior as an executable suite, accept that suite as the specification for the migration scope, and let coding agents implement against it until it's green.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test-driven modernization, with the legacy system acting as the &lt;strong&gt;oracle&lt;/strong&gt; — not supplying the tests. The scenarios, the observation points, and the normalization rules are all still mine to design. What the old system supplies is the expected values.&lt;/p&gt;

&lt;p&gt;This isn't advice, and it isn't a claim that any of this is solved. It's the most practical hypothesis I've got after watching the obvious approach fail to converge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where I've landed for now (and expect to keep revising):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source analysis produces &lt;strong&gt;interpretations&lt;/strong&gt;. Execution produces &lt;strong&gt;comparable evidence&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For a declared scope, the coverage contract plus the recorded results plus the tests &lt;em&gt;are&lt;/em&gt; the specification — not because they're complete, but because they were accepted.&lt;/li&gt;
&lt;li&gt;The coding agent is the replaceable part. The &lt;strong&gt;harness&lt;/strong&gt; that judges it is the asset.&lt;/li&gt;
&lt;li&gt;The deliverable that matters isn't the new code. It's the evidence someone can sign a cutover against.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  First I tried just pointing the agent at it
&lt;/h2&gt;

&lt;p&gt;The version I built before this one had no harness in it at all.&lt;/p&gt;

&lt;p&gt;Claude Code, pointed straight at the legacy codebase. I put real effort into the scaffolding — skills for the recurring analysis moves, prompt structures that held up across sessions, work plans that decomposed the system into ordered units, and a loop: analyze a region of the old code, write the equivalent in the new stack, review, move on. Not a naive setup, and I still think it was the right thing to try first.&lt;/p&gt;

&lt;p&gt;It worked, partially. That's the awkward part — it produces something. You get a new implementation that is recognizably the same application, and on a good day a reviewer nods at it.&lt;/p&gt;

&lt;p&gt;What it didn't produce was a reason to believe it. Three things kept going wrong, and they turned out to be the same thing wearing different clothes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The token cost per unit of confirmed behavior was miserable.&lt;/strong&gt; The loop spent most of its budget re-reading code it had already read, re-deriving conclusions it had already reached, and writing long analysis prose so the &lt;em&gt;next&lt;/em&gt; step could consume it. Enormous input, and the output was a paragraph of interpretation — expensive tokens buying a plausible reading of a stored procedure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fidelity was something we checked by eye.&lt;/strong&gt; Two screens side by side, two sets of records lined up, a squint. "Looks right." There is no number in that sentence. Nobody could say which side effects were verified and which weren't, or whether yesterday's slice was still passing. And volume defeats attention long before it defeats the agent: nobody eyeballs the four hundredth order-status transition carefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nothing ratcheted.&lt;/strong&gt; A slice that had been reviewed and accepted could quietly regress while the next one was in progress, and we'd find out at integration, or later. Manual review doesn't leave anything behind that can re-run itself.&lt;/p&gt;

&lt;p&gt;The diagnosis I eventually landed on: I was trying to solve a &lt;em&gt;measurement&lt;/em&gt; problem with better prompts. Every iteration of skills and plans was an attempt to make the agent's interpretation more convincing. What I needed wasn't a more convincing interpretation. It was a mechanism that could disagree with the agent without a human squinting at two screens.&lt;/p&gt;

&lt;p&gt;So I stopped improving the analysis and started building the measurement. What follows isn't a design reasoned out in advance — it's what the failure of the first approach pointed at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behavior was never in one place
&lt;/h2&gt;

&lt;p&gt;The analysis-first approach doesn't converge, and it isn't because the agent reads badly. It's that the behavior isn't gathered anywhere.&lt;/p&gt;

&lt;p&gt;Some is in application code. The rest is in stored procedures, triggers, nightly batch jobs, a permissions table that three screens read differently, a scheduler entry nobody owns, an external service returning a shape the docs don't mention, and operational rules that live in a person. A &lt;code&gt;Java / JSP + Oracle + nightly batch + mail&lt;/code&gt; system doesn't have a specification; it has an accumulated set of effects. You can read all of it and still not know the ordering, or which branch fires in production, or that invoice rounding differs by one path.&lt;/p&gt;

&lt;p&gt;But you can &lt;em&gt;run&lt;/em&gt; it — drive a business scenario against the running system and record what comes out the other side. Recording alone doesn't make that authoritative, though. It needs provenance (which build, which data set, which run), stable semantics across repeated runs, and an accepted policy that lets that run serve as the baseline. Human judgment belongs at the scope, policy, and cutover boundaries, not on every field of every run — putting a person in the inner loop is how this stops scaling at exactly the volume where it starts to matter.&lt;/p&gt;

&lt;p&gt;A green suite also proves only the scenarios it contains, which is the obvious objection and deserves answering here rather than at the end. So the loop needs a second gate: evidence that the surfaces, journeys, data effects, error paths, and boundaries the scope requires are actually represented. Coverage here isn't a percentage, it's a contract about what had to be present. Which makes "the suite is the specification" a slogan; the accurate version is that for a declared scope, the coverage contract, the tests, and the attested legacy results together form the executable specification.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparator may normalize representation. It may not forgive behavior.
&lt;/h2&gt;

&lt;p&gt;The harness runs each scenario against both systems and compares. Which sounds obvious right up until you try to compare two systems that were &lt;em&gt;supposed&lt;/em&gt; to differ. IDs are new. Timestamps are new. Row ordering is unspecified. The new UI's implementation and DOM are deliberately different, even where the user-visible behavior has to stay equivalent.&lt;/p&gt;

&lt;p&gt;So a comparator that demands equality is useless. But the fix is not a comparator that forgives things — this is what I got wrong at first, and it's the distinction the whole apparatus rests on.&lt;/p&gt;

&lt;p&gt;Representation is generated IDs, request timestamps, encodings, the order of unordered collections, and metadata &lt;em&gt;proven&lt;/em&gt; to be non-semantic. Note the proven: "this field looked incidental" is how a business rule gets discarded. What the comparator cannot do is decide that a behavior may change or disappear. That decision exists and is frequent, but it's a migration-policy decision that moves part of the scope outside strict translation, recorded with what was decided and by whom.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it's allowed to decide&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Normalization&lt;/td&gt;
&lt;td&gt;representation only — the same behavior, differently expressed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration policy&lt;/td&gt;
&lt;td&gt;intentional change or removal, outside strict translation mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two rows, deliberately. A permissive mode can carry a narrowly scoped exception — but never as a normal path to green. The moment "ignore this difference" becomes routine vocabulary, a green result turns into something you can negotiate your way into, and the apparatus is just an expensive way to feel reassured.&lt;/p&gt;

&lt;h2&gt;
  
  
  One scenario, end to end
&lt;/h2&gt;

&lt;p&gt;Abstractly this all sounds tidy, so here's a single slice as it actually moves. Order creation, standard path, item in stock.&lt;/p&gt;

&lt;p&gt;The legacy run, recorded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scenario  order.create / standard / in-stock
legacy    build=legacy-2019.11  data=masked-set-3  run=8f2c

  screen      list refreshed, new row at top, status "pending approval"
  api         201  {order_no: "O-2024-000123", total: 150000}
  db          orders +1, order_lines +1, inventory_reservations +1 (qty 10)
  permission  approver check evaluated → allow
  events      OrderCreated
  batch       nightly invoice job picks it up (t+1)
  mail        order-received → customer address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new implementation, first pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS  screen, api status, orders, order_lines, permission, batch, mail
DIFF  api.order_no              expected O-2024-000123   actual O-2026-000001
DIFF  inventory_reservations    expected 1 (qty 10)      actual 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two diffs, and they are not the same kind of thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;order_no   generated id       → normalized (shape asserted: O-YYYY-NNNNNNN)
qty on     inventory reserve  → semantic; NOT normalizable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first resolves. The second is behavior, so it becomes a task rather than a rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected:  inventory reservation created: 1 (qty 10)
Actual:    inventory reservation created: 0
Repair:    Add inventory reservation to order creation.
           Preserve idempotency.
           Do not modify billing or shipping modules.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent implements, harness re-runs, and the slice closes with something a human can sign:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;order.create / standard / in-stock          PRESERVED
  evidence     legacy run 8f2c, new run c41a, 7 observed effects, 0 unresolved
  normalized   order_no, created_at, DOM structure
  policy       none applied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last block is the actual product of the exercise. Not the code — the row that says which run, how many effects, what was normalized away, and whether anyone changed the rules to get here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rigor compresses, again
&lt;/h2&gt;

&lt;p&gt;Note what the agent received: not a description of a system, but a diff and a scope constraint. In the first approach the equivalent input was paragraphs about how the legacy inventory module &lt;em&gt;probably&lt;/em&gt; works — long, hedged, expensively derived, partly wrong. Here it's two numbers: shorter, and grounded in an observed run.&lt;/p&gt;

&lt;p&gt;Same aphorism as &lt;a href="https://dev.to/gyu07/rigor-compresses-why-ai-agents-need-graphs-not-more-context-5404"&gt;the graph post&lt;/a&gt;, arriving from another direction. The more precisely the behavior was captured, the fewer tokens it takes to say what's broken. Capture costs up front and then stops costing on every iteration — the opposite of re-reading the codebase each round.&lt;/p&gt;

&lt;p&gt;Which leaves the loop itself unremarkable, and that's the point: red-green-refactor, except the green came from a system that already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent writes the code; the harness decides if it's right
&lt;/h2&gt;

&lt;p&gt;The discipline is a trust-boundary question: the agent must not be the thing that judges its own work.&lt;/p&gt;

&lt;p&gt;Claude Code, Codex, whatever comes next — interchangeable. The stable asset is everything around it: scenario definitions, execution adapters per stack, both runners, result normalization, behavior comparison, repair-task generation, evidence storage. Agents are strikingly good at producing a plausible "all tests pass," so the comparator, the normalization rules, and the evidence store are the pieces I want deliberately authored, small enough to review, and boring. The bespoke, agent-assisted part stays on the side where a mistake surfaces as a failing scenario rather than a silent pass — otherwise you've built an unsoundness that reads as safety.&lt;/p&gt;

&lt;p&gt;The capture layers are mostly plumbing: browser driving for screen behavior (Playwright), boundary capture for APIs, before/after snapshots for the database, tracing for execution paths and side effects, stubbed sinks for batch and mail and events, &lt;code&gt;JSONL&lt;/code&gt; and &lt;code&gt;Parquet&lt;/code&gt; for evidence, &lt;code&gt;SQLite&lt;/code&gt; and &lt;code&gt;DuckDB&lt;/code&gt; for working state and diff analysis. Swap any of it for your equivalent; the tools matter less than they look like they do. What matters is that the output is a normalized record that can be replayed and compared — and that, rather than the language or the stack, is what decides whether a system can be migrated this way.&lt;/p&gt;

&lt;p&gt;Two honest caveats there. A stubbed sink proves the system issued the right request at the boundary; it does not prove the mail arrived or the settlement cleared. And traces are not proofs of equivalence — internal routes &lt;em&gt;should&lt;/em&gt; change in a rewrite. What traces buy is explanation: why a diff happened, which observations were missing, which side effects nobody thought to record.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "complete" has to mean
&lt;/h2&gt;

&lt;p&gt;No suite proves everything a system can do, so "complete" isn't available in the honest sense. What's available is an operational definition: for &lt;em&gt;this&lt;/em&gt; scope, these surfaces and these effects had to be present, and the coverage contract says so explicitly. Everything else gets a bucket rather than silence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PRESERVED     verified equivalent
INTENTIONAL   changed by policy, recorded and attributed
REMOVED       withdrawn by policy, recorded and attributed
UNVERIFIED    known unknown, still open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The middle two are outcomes of policy decisions, not comparator settings — the same separation as before, arriving at the sign-off document. And &lt;code&gt;UNVERIFIED&lt;/code&gt; is the bucket that earns the whole scheme: a migration always has behavior nobody captured, and the difference between a good and a bad project is whether that list exists and gets looked at. It's also where faithfully-reproduced legacy bugs go to be argued about. You &lt;em&gt;will&lt;/em&gt; reproduce them; the answer is to move them into &lt;code&gt;INTENTIONAL&lt;/code&gt; deliberately rather than discover them later.&lt;/p&gt;

&lt;p&gt;This is also why the unit of work is a slice — customer registration, order creation, invoice generation — rather than the system. Two hundred red scenarios at once tell you nothing, and progress becomes a count of slices with evidence attached, which is a harder number to fool yourself with than percent-complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd defend
&lt;/h2&gt;

&lt;p&gt;AI made implementation cheap. It did not make correctness cheap, and it made &lt;em&gt;proving&lt;/em&gt; nothing easier at all. So the artifact I care about on these projects isn't the generated code. It's the executable specification that can reject the generated code — and the useful property is that nobody in the loop is judging their own output.&lt;/p&gt;

&lt;p&gt;I'd hold the specifics loosely. The first approach didn't fail because it was stupid; it was reasonable given what the tools did at the time, and the tools moved. That'll keep happening. If agents get materially better at holding a whole system's behavior in view, or capturing behavior gets cheaper than I think it can, parts of the structure above stop earning their keep and I'll be building something else. What I'd defend is narrower than the design: the correctness of a rewrite has to be decided by something other than the thing that wrote it.&lt;/p&gt;

&lt;p&gt;What I want is for a cutover to stop being a judgment call made on confidence and become something the evidence says — what was preserved, what changed by decision, and what nobody has checked yet.&lt;/p&gt;

&lt;p&gt;If the behavior is captured properly, you don't have to ask anyone to be brave about the release.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>architecture</category>
      <category>legacy</category>
    </item>
    <item>
      <title>Why Athena/Iceberg Tends to Make Code the Spec</title>
      <dc:creator>Takafumi Endo | ROUTE06</dc:creator>
      <pubDate>Tue, 21 Jul 2026 03:45:35 +0000</pubDate>
      <link>https://dev.to/gyu07/why-athenaiceberg-tends-to-make-code-the-spec-oon</link>
      <guid>https://dev.to/gyu07/why-athenaiceberg-tends-to-make-code-the-spec-oon</guid>
      <description>&lt;p&gt;Every time this comes up, someone credits the same setup: Athena on Iceberg is where "the code is the spec" — where you open Git and read the whole system, catalog to transforms to schema, without logging into anything. In my experience they're not wrong.&lt;/p&gt;

&lt;p&gt;What I want to argue is that they're right for mostly the wrong reason.&lt;/p&gt;

&lt;p&gt;The reason people reach for is the engine — serverless, open format, nothing to provision. But the thing that actually keeps code as the spec, when it does, is something you could have applied to almost any engine. And the thing that breaks it, when it breaks, has nothing to do with Iceberg at all.&lt;/p&gt;

&lt;p&gt;So here's the split I've landed on, for now: whether "code is the spec" holds is about &lt;strong&gt;90% discipline and 10% engine&lt;/strong&gt;. Athena/Iceberg earns that 10% honestly — but 10% is all it earns, and I keep watching people mistake it for the whole thing. (Just where my own tinkering has led — not advice.)&lt;/p&gt;

&lt;p&gt;I should say up front that I'm still in the middle of this. What the &lt;em&gt;best&lt;/em&gt; declarative setup for an agent actually looks like — how you turn a system into a spec it can read and act on without guessing — is something I'm actively testing, not something I've settled. Read what follows as a working idea at a particular moment, written down partly so I can find out where it's wrong.&lt;/p&gt;

&lt;p&gt;To see where the 10% actually lives, it helps to notice that a stateful system always keeps two copies of itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The spec has two copies
&lt;/h2&gt;

&lt;p&gt;One copy is &lt;strong&gt;declared&lt;/strong&gt;: the code you wrote, the schema you committed, the transforms in dbt, the catalog in Terraform. The other is &lt;strong&gt;realized&lt;/strong&gt;: the state the engine accumulates while running — statistics, physical layout, caches, maintenance history, tuning knobs someone set at 2am.&lt;/p&gt;

&lt;p&gt;"Code is the spec" is really a claim about the distance between those two. When the declared copy explains almost everything about the realized one, you can reason about the system by reading Git. When it doesn't, you can't.&lt;/p&gt;

&lt;p&gt;Some of that state is declarable — you can pin a distribution or sort strategy in DDL, dbt, or Terraform. But plenty of it isn't, or drifts away from what you declared: which strategy the engine is &lt;em&gt;actually&lt;/em&gt; using once automatic optimization kicks in, when the last vacuum finished, whether statistics are fresh, which materialized view is stale, whether that partition is really being pruned. To answer those you log in and ask the running system. Now your spec is half in the repo and half in someone's head.&lt;/p&gt;

&lt;p&gt;So the real question isn't "is my code readable." It's: &lt;strong&gt;how much of the truth escaped the code into runtime state I can't see?&lt;/strong&gt; I've started calling that the &lt;em&gt;hidden-state surface area&lt;/em&gt;. Shrink it and the code stays the spec. Let it grow and the code becomes a hopeful sketch.&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://dev.to/gyu07/rigor-compresses-why-ai-agents-need-graphs-not-more-context-5404"&gt;argued a while back that rigor compresses&lt;/a&gt; — the more precisely you can state a fact, the fewer tokens it takes to hand over. This is the same idea pointed at a platform instead of a function: the smaller the hidden-state surface, the shorter and truer the account of the system you can hand to anyone, human or agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is mostly discipline
&lt;/h2&gt;

&lt;p&gt;Here's the part I want to be honest about first, because it's the 90%: the engine doesn't make your system legible. &lt;strong&gt;Declarative rigor does.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A catalog expressed as data contracts, transforms as a single dbt DAG, infra as Terraform — that's what makes design intent followable in code. And it's almost entirely engine-agnostic. You can point all of it at Redshift and get something a newcomer can read top to bottom. You can also build an Iceberg-on-Athena setup that's an undocumented swamp of hand-run &lt;code&gt;ALTER&lt;/code&gt;s and orphaned partitions nobody dares touch.&lt;/p&gt;

&lt;p&gt;I've done both. The readable one wasn't readable because of the storage format. It was readable because the rules were declared, in one place, and enforced. "Iceberg, therefore legible" is a claim I'd push back on if someone else made it — so I should hold myself to the same standard.&lt;/p&gt;

&lt;p&gt;If you do nothing else, do this part. It's where the leverage is.&lt;/p&gt;

&lt;h2&gt;
  
  
  But the engine sets the difficulty
&lt;/h2&gt;

&lt;p&gt;Now the 10% — small, but not nothing. Given equal discipline, engines differ in how much state they &lt;em&gt;insist&lt;/em&gt; on keeping inside themselves versus how much they externalize where you can see it. That doesn't decide whether you &lt;em&gt;can&lt;/em&gt; make code the spec; it decides how much discipline it costs to keep it that way.&lt;/p&gt;

&lt;p&gt;Athena on Iceberg externalizes an unusual amount. The stuff that's normally locked inside a proprietary engine — snapshot history, the manifest of what files exist, the current schema, the partition spec — lives as open metadata that isn't confined to one vendor's internal system tables. You can read it through standard metadata tables (&lt;code&gt;$snapshots&lt;/code&gt;, &lt;code&gt;$manifests&lt;/code&gt;, &lt;code&gt;$history&lt;/code&gt;), through the catalog, or straight from object storage. It's still &lt;em&gt;state&lt;/em&gt;, and it still changes at runtime — but the format is open and portable, so the same facts stay reachable from more than one tool.&lt;/p&gt;

&lt;p&gt;Redshift keeps more of that truth behind its own interfaces. Materialized-view freshness, &lt;code&gt;VACUUM&lt;/code&gt;/&lt;code&gt;ANALYZE&lt;/code&gt; history, statistics, workload-management tuning, and — with automatic table optimization or &lt;code&gt;AUTO&lt;/code&gt; distribution — the &lt;em&gt;effective&lt;/em&gt; physical layout, which can shift with data volume regardless of what you declared. It's all observable; you just query the system views for it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Athena / Iceberg&lt;/th&gt;
&lt;th&gt;Redshift&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Visible in Git / code&lt;/td&gt;
&lt;td&gt;Terraform, dbt, contracts, SQL/YAML&lt;/td&gt;
&lt;td&gt;Terraform, dbt, DDL, contracts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime state lives...&lt;/td&gt;
&lt;td&gt;open metadata (snapshots, manifests, schema, partition spec)&lt;/td&gt;
&lt;td&gt;engine-internal: MV freshness, vacuum/analyze history, stats, effective dist/sort under &lt;code&gt;AUTO&lt;/code&gt;, tuning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;To inspect it you...&lt;/td&gt;
&lt;td&gt;read open metadata tables, the catalog, or object storage&lt;/td&gt;
&lt;td&gt;query the engine's system views&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute infra to manage?&lt;/td&gt;
&lt;td&gt;no dedicated warehouse compute&lt;/td&gt;
&lt;td&gt;provisioned: yes · serverless: mostly abstracted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hidden-state surface&lt;/td&gt;
&lt;td&gt;typically smaller, more externalized&lt;/td&gt;
&lt;td&gt;typically larger, more engine-bound&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest framing: it's not that one is readable and one isn't. Both expose their state — the difference is &lt;em&gt;how&lt;/em&gt;. One hands you facts in an open format that multiple compatible tools can inspect; the other hands them back through its own interfaces. Same level of legibility, less &lt;em&gt;engine-specific&lt;/em&gt; discipline required to preserve it — not necessarily less operational work overall. That's the whole 10%. (This is for the batch-oriented, per-tenant workload I keep describing; a giant, high-churn Iceberg estate grows its own large state surface — manifests, small files, snapshot sprawl, catalog commits, cross-engine compatibility — and the gap narrows.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I actually care: the guesser downstream
&lt;/h2&gt;

&lt;p&gt;Here's where it stops being an aesthetics argument for me.&lt;/p&gt;

&lt;p&gt;The real line isn't S3 versus a database. It's this: &lt;strong&gt;a fact exposed through an inspectable interface the agent can actually reach is &lt;code&gt;verified&lt;/code&gt;; a fact outside its observable context must be &lt;code&gt;estimated&lt;/code&gt;.&lt;/strong&gt; A Redshift &lt;code&gt;VACUUM&lt;/code&gt; history the agent is allowed to query is verified; an Iceberg snapshot it has no catalog access or tooling for is a guess. The engine doesn't decide it — reachable evidence does. What Iceberg tends to do is make that evidence &lt;em&gt;easier to expose safely and portably&lt;/em&gt;: open metadata is simple to grant read access to without also handing over the keys to a live warehouse.&lt;/p&gt;

&lt;p&gt;And the consumer of those facts, more and more, is an agent. These days I'm rarely the one reading the schema first — Claude Code or Codex is, running in the repo, editing a migration, rewriting a transform. What it can &lt;em&gt;see&lt;/em&gt; is the declared copy plus whatever interfaces I've wired it into; everything else it infers. The larger the hidden-state surface — or the harder its evidence is to reach — the more of my system the agent is quietly guessing about, and the more defensive lines I tack onto prompts: "check the effective sort strategy first," "don't assume the MV is fresh," "verify before you migrate." When the fact is reachable, it can state it flatly and move on; when it isn't, the best it can do is hedge — and hedging costs tokens &lt;em&gt;and&lt;/em&gt; trust.&lt;/p&gt;

&lt;p&gt;And this isn't OLAP-only. The agent touches both tiers — on OLTP it edits schema, writes migrations, reasons about a &lt;code&gt;tenant_id&lt;/code&gt; guard; on OLAP it changes a dbt model, reads a partition spec, checks whether a snapshot rolled forward. The same question decides it either way: &lt;em&gt;can it reach the evidence for what it's about to do?&lt;/em&gt; Legibility-for-agents is one property spanning the whole platform, not a warehouse feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's the same move I make everywhere else
&lt;/h2&gt;

&lt;p&gt;Once I saw "shrink the hidden-state surface" as the goal, I noticed I was already doing it at the architecture level, not just the table level.&lt;/p&gt;

&lt;p&gt;The platform I work on keeps three kinds of state deliberately apart — durable relational truth in Postgres, hot disposable state in DynamoDB, private local work in per-user SQLite — and the thing I'm most careful about isn't any one store. It's the &lt;em&gt;crossings between them&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OLTP  (write / update)                 OLAP  (read / aggregate)
┌───────────────────────────┐          ┌──────────────────────┐
│ control-db (Postgres)      │          │ Athena / Iceberg      │
│   durable, relational      │          │   S3 Tables (open     │
│ operational_state (Dynamo) │  ==3==&amp;gt;  │   metadata mart)      │
│   hot, TTL'd               │  bridges │ DuckDB (local)        │
│ metadata.db (SQLite)       │          │                       │
│   local, private           │          │                       │
└───────────────────────────┘          └──────────────────────┘
     the only sanctioned OLTP→OLAP paths are three named bridges,
     and Postgres reaches the lake through exactly one VPC Lambda.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The point of narrowing the crossings to a countable few — and letting Postgres reach the analytics lake through a &lt;em&gt;single&lt;/em&gt; path — is the same point as preferring open metadata. Every uncounted pathway is hidden state: a way the system can be true in production in a shape the code never described. Three named bridges I can hold in my head. Twenty accidental ones I cannot, and neither can an agent.&lt;/p&gt;

&lt;p&gt;Same principle at two scales: &lt;strong&gt;make the crossings and the state legible, so the code keeps describing the system.&lt;/strong&gt; That the pattern reappears from a single table up to the whole control-plane-to-lake boundary is, honestly, most of why I trust it — though that's a hunch I hold loosely, not a thesis I'd defend to the death.&lt;/p&gt;

&lt;p&gt;And this is where I've started spending real budget on purpose. Making OLTP and OLAP legible &lt;em&gt;to an agent&lt;/em&gt; — declared schemas, reachable metadata, counted crossings, a system view the agent is actually allowed to query — used to read as tidiness, a nice-to-have for when you had time. With Claude Code and Codex doing more of the actual editing, it's stopped feeling like tidiness and started feeling like the interface I hand the most productive worker on the team. An hour spent making a fact reachable is an hour I don't spend, over and over, writing "be careful, verify this" into prompts — and the payoff compounds every time the agent runs. So I treat agent-legibility as infrastructure worth building, the way you'd invest in tests or types, not polish applied at the end. Whether it fully pencils out depends on how much of your work the agents are really doing; for the amount they're doing in mine, it already has.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objections I'd raise myself
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"So you're saying Iceberg is more readable than Redshift."&lt;/strong&gt; No — I'm saying it externalizes more state, which lowers the discipline &lt;em&gt;cost&lt;/em&gt; of legibility. A disciplined Redshift shop beats a sloppy Iceberg one every time. The 90% dominates; the engine only sets the exchange rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Open metadata isn't zero hidden state."&lt;/strong&gt; Correct. Compaction, small-file cleanup, maintenance jobs — Iceberg has operational state too. It's smaller and observable-from-outside, not absent. If I implied "no hidden state," that's overreach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Athena/Iceberg has its own tax."&lt;/strong&gt; It does — and it's not about S3 consistency (object storage is strongly consistent now). It's concurrent-write conflicts, catalog commit semantics, small files, compaction, snapshot expiration, and orphan-file cleanup. Athena needs &lt;code&gt;OPTIMIZE&lt;/code&gt;/&lt;code&gt;VACUUM&lt;/code&gt; against Iceberg tables too. Legibility isn't free; I'm trading one set of runtime concerns for another, and I want that trade stated plainly, not smuggled in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"This is just a warehouse-vs-lakehouse take in disguise."&lt;/strong&gt; Partly. But the axis I care about isn't performance or cost — it's the size of the gap between declared and realized. Two separate arguments; I don't want to lean on the popular one to prop up mine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where this leaves me
&lt;/h2&gt;

&lt;p&gt;The design goal I keep circling back to is small: &lt;strong&gt;shrink the distance between what the code says and what's true at runtime&lt;/strong&gt; — because that distance is precisely where humans and agents are forced to guess.&lt;/p&gt;

&lt;p&gt;Most of the shrinking is discipline: declare the rules, put them in one place, enforce them — the 90%, and no engine does it for you. The last 10% is picking tools that don't quietly hoard state inside themselves, but hand you their truth as metadata you can read, crossings you can count, facts you can verify. Do the 90% and almost any engine can be the spec; do the 10% too and the code stays the spec with less of you holding it together by hand. That's the honest version of what people reach for when they credit Athena/Iceberg — not that the engine makes code the spec, but that it asks less of you to keep it that way.&lt;/p&gt;

&lt;p&gt;I want to be honest about how provisional this still is. I don't think anyone, me least of all, has settled what declarative management and code-as-spec should look like once the primary reader is an agent rather than a person. I'm running my own small experiments — which facts to externalize, which interfaces to expose, where the &lt;code&gt;verified&lt;/code&gt;/&lt;code&gt;estimated&lt;/code&gt; line should sit — and expect to be revising this for a while. The 90/10 is a heuristic I find useful today, not a law I'd stand behind tomorrow.&lt;/p&gt;

&lt;p&gt;That, for now, is the shape I'm designing toward — a little more on purpose, a little less out of habit, and still figuring out the edges.&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>iceberg</category>
      <category>athena</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
