<?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: Shimo</title>
    <description>The latest articles on DEV Community by Shimo (@shimo4228).</description>
    <link>https://dev.to/shimo4228</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3772086%2F7b113abd-2f92-4728-993c-602762a15288.png</url>
      <title>DEV Community: Shimo</title>
      <link>https://dev.to/shimo4228</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shimo4228"/>
    <language>en</language>
    <item>
      <title>Between the Workflow and ReAct Quadrants: How Phase Decides Skill Design</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Sat, 02 May 2026 03:10:17 +0000</pubDate>
      <link>https://dev.to/shimo4228/between-the-workflow-and-react-quadrants-how-phase-decides-skill-design-31h4</link>
      <guid>https://dev.to/shimo4228/between-the-workflow-and-react-quadrants-how-phase-decides-skill-design-31h4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series position:&lt;/strong&gt; The fourth article in the ReAct agent quadrant series. The quadrant names align with the previous articles and with the &lt;a href="https://github.com/shimo4228/agent-attribution-practice" rel="noopener noreferrer"&gt;AAP repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Premise — The Four Quadrants Again
&lt;/h2&gt;

&lt;p&gt;Recapping the four quadrants set up in the &lt;a href="https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do"&gt;first article&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1) &lt;strong&gt;Script Quadrant&lt;/strong&gt; — deterministic × definable. Handled by scripts and pipelines.&lt;/li&gt;
&lt;li&gt;(2) &lt;strong&gt;Algorithmic Search Quadrant&lt;/strong&gt; — deterministic × exploratory. Classical AI / OR territory.&lt;/li&gt;
&lt;li&gt;(3) &lt;strong&gt;LLM Workflow Quadrant&lt;/strong&gt; — semantic judgment × definable. Calls an LLM inside a predefined workflow.&lt;/li&gt;
&lt;li&gt;(4) &lt;strong&gt;Autonomous Agentic Loop Quadrant&lt;/strong&gt; — semantic judgment × exploratory. An autonomous loop where the LLM itself decides the next action (= ReAct agent).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Up to the previous article, I treated (3) and (4) as a dichotomy — "pick one based on the nature of the work." &lt;a href="https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18"&gt;The second article&lt;/a&gt; pointed out that the industry has no settled vocabulary for (3); &lt;a href="https://dev.to/shimo4228/is-react-needed-in-production-separating-design-and-operation-phases-2bn1"&gt;the third article&lt;/a&gt; framed the dichotomy along the business-system axis and introduced the Phase Separation between design phase and operation phase. This article brings that Phase Separation down to the resolution of individual skill design and tries to show that, between the two poles of the dichotomy, a &lt;strong&gt;continuous gradient&lt;/strong&gt; exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observation — The Same Job Lives in Multiple Forms
&lt;/h2&gt;

&lt;p&gt;Looking around my own repositories, I notice that conceptually identical jobs are implemented in several different forms. The &lt;strong&gt;Promote phase&lt;/strong&gt; of &lt;a href="https://github.com/shimo4228/agent-knowledge-cycle" rel="noopener noreferrer"&gt;AKC (Agent Knowledge Cycle)&lt;/a&gt; — a six-phase cycle in which an agent distills knowledge from its own outputs to self-improve — is a typical example. The job is to extract recurring principles from skills and promote them to rules. Generalized, it's the work of "&lt;strong&gt;extracting principles from repetition&lt;/strong&gt;." Mining alert rules from logs, finding common patterns across a codebase to refactor, weaving an FAQ from customer-support conversation logs — they all belong to the same family.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;&lt;code&gt;contemplative-agent&lt;/code&gt;&lt;/a&gt; there's a Python function called &lt;a href="https://github.com/shimo4228/contemplative-agent/blob/main/src/contemplative_agent/core/rules_distill.py" rel="noopener noreferrer"&gt;&lt;code&gt;core/rules_distill.py&lt;/code&gt;&lt;/a&gt;. It vectorizes skills with embeddings, builds theme-based clusters via &lt;code&gt;cluster_patterns&lt;/code&gt;, batches LLM calls with &lt;code&gt;MAX_RULES_BATCH=10&lt;/code&gt;, and the cluster threshold &lt;code&gt;CLUSTER_THRESHOLD_RULES=0.65&lt;/code&gt; is calibrated with a calibration file. The LLM call is just one step in the pipeline, and most of the judgment has been frozen into code in advance.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/shimo4228/claude-skill-rules-distill" rel="noopener noreferrer"&gt;&lt;code&gt;rules-distill&lt;/code&gt;&lt;/a&gt; skill (&lt;code&gt;~/.claude/skills/rules-distill/SKILL.md&lt;/code&gt;), by contrast, is written in natural language. In Phase 1, &lt;code&gt;scan-skills.sh&lt;/code&gt; produces the file listing; in Phase 2, theme-based cluster judgment is delegated to a sub-agent; merges across batches are also decided by LLM judgment. Scripts are used only for listing and persistence — the judgment itself sits in the runtime LLM's hands.&lt;/p&gt;

&lt;p&gt;The two are doing the same job. And yet the implementations are dramatically different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surface Hypothesis — Model Capability
&lt;/h2&gt;

&lt;p&gt;The first explanation that comes to mind is &lt;strong&gt;model capability&lt;/strong&gt;. &lt;code&gt;core/rules_distill.py&lt;/code&gt; was written to run in a 9B local-model environment. In my hands-on experience, getting a 9B model to robustly run theme-based cluster judgment at runtime is hard. So a deterministic scaffold of embeddings + clustering + threshold tuning limits the 9B's role to "generate one rule candidate from a given cluster." Conversely, in a Claude Code environment where Opus is callable at runtime, that scaffold is no longer needed. Cluster judgment and merge judgment can both be performed by an LLM that takes the entire context into account.&lt;/p&gt;

&lt;p&gt;This is consistent with a design principle recorded by AKC — README's Design Principle 5: "Evaluation scales with model capability — small models run on rubric evaluation; Opus class runs on qualitative evaluation that takes the full context into account." The original is scoped to evaluation, but extended to implementation-position choice — varying judgment scale with capability — the 9B-era Python pipeline and the Opus-era natural-language skill read as the two endpoints of that extension.&lt;/p&gt;

&lt;p&gt;But this explanation is only stroking the surface of where things get implemented. The capability gap is an observable fact, but it's a &lt;strong&gt;downstream consequence of a deeper decision&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deeper Hypothesis — The AAP Phase
&lt;/h2&gt;

&lt;p&gt;Back to the &lt;strong&gt;distinction between design phase and operation phase&lt;/strong&gt; from the previous article, &lt;a href="https://dev.to/shimo4228/is-react-needed-in-production-separating-design-and-operation-phases-2bn1"&gt;Is ReAct Needed in Production?&lt;/a&gt;. What's really driving the choice of implementation position is this phase axis.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;contemplative-agent&lt;/code&gt; sits in the &lt;strong&gt;operation phase&lt;/strong&gt;. Once deployed, inputs flow through fixed routes. The boundaries between inputs (persona templates, dialogue, memory) and outputs (responses, logs) are settled in advance, and the internal knowledge cycle similarly runs through six predefined phases. Because the pipeline is frozen for operation, structures like embeddings / clustering / thresholds / batches in &lt;code&gt;core/rules_distill.py&lt;/code&gt; can be baked into Python. The 9B is &lt;em&gt;a choice that becomes available&lt;/em&gt; in this environment, not the cause.&lt;/p&gt;

&lt;p&gt;In fact, the &lt;code&gt;contemplative-agent&lt;/code&gt; pipeline is built so that the LLM-call portion can optionally be swapped to Claude or GPT models. Scaling capability upward leaves the LLM-function pipeline largely intact. This works as a counter-experiment against the surface hypothesis (capability requires the pipeline structure). If capability were the cause, the pipeline structure should become redundant and start to fall apart the moment you switch to Opus class. But it doesn't. &lt;strong&gt;What requires the pipeline structure isn't capability — it's the phase decision of being in the operation phase.&lt;/strong&gt; Capability is just a downstream choice that follows from the phase decision.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Claude Code&lt;/code&gt; is &lt;strong&gt;a tool that lives in the design phase&lt;/strong&gt;. Each session is itself exploratory work: the target codebase, the IDE, the agents being used, and even the file types being handled (.py / .ts / .md / .ipynb / arbitrary) shift between sessions. One time it's a Python project, another time a Next.js project, another time a documentation repo centered on ADRs. If a skill freezes paths or file structure in advance, it breaks the moment the environment changes. So the skill body is written in natural language and adapts to the runtime context. Opus is a &lt;em&gt;consequence&lt;/em&gt; — it's the capability needed to support the holistic judgment that runtime adaptation demands — not the cause.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contemplative-agent can be written in &lt;code&gt;core/rules_distill.py&lt;/code&gt; form = &lt;strong&gt;because the pipeline was frozen for the operation phase&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Claude Code has to be written in &lt;code&gt;rules-distill&lt;/code&gt; skill form = &lt;strong&gt;because the design phase makes freezing the environment impossible&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Capability appears to sit downstream of this phase decision. The phase draws the line between "hardcodable" and "flexibility-required," and inside that line capability gets selected. AKC's extended principle "capability ↑ → holistic judgment OK" reads as a secondary principle that holds once the phase decision is taken as given.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside a Phase — Same Phase, but Task Pulls Position
&lt;/h2&gt;

&lt;p&gt;Even narrowing the lens to the design phase, implementation position splits further.&lt;/p&gt;

&lt;p&gt;There's a skill called &lt;a href="https://github.com/shimo4228/claude-skill-comply" rel="noopener noreferrer"&gt;&lt;code&gt;skill-comply&lt;/code&gt;&lt;/a&gt;. It measures whether Claude's skill / rule / agent definitions are actually being followed at runtime. It auto-generates scenarios at three prompt-strictness levels (supportive → neutral → competing), runs &lt;code&gt;claude -p&lt;/code&gt;, and classifies tool-call traces to report compliance rates. The directory contains &lt;code&gt;pyproject.toml&lt;/code&gt; / &lt;code&gt;prompts/&lt;/code&gt; / &lt;code&gt;fixtures/&lt;/code&gt; / &lt;code&gt;tests/&lt;/code&gt; / &lt;code&gt;scripts/&lt;/code&gt; / &lt;code&gt;results/&lt;/code&gt;. The internal requirement of the task is that scenario execution be reproducible — otherwise compliance rates are meaningless. Generalized, it sits next to static code analysis (lint, SonarQube) or automated benchmark measurement: jobs that require &lt;strong&gt;the same input to return the same verdict&lt;/strong&gt;. It's a skill in the design phase, but &lt;strong&gt;the task nature of evaluation/measurement requires reproducibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A different skill, &lt;a href="https://github.com/shimo4228/claude-skill-search-first" rel="noopener noreferrer"&gt;&lt;code&gt;search-first&lt;/code&gt;&lt;/a&gt;, looks for existing libraries and tools before new implementation begins. The directory contains only a single &lt;code&gt;SKILL.md&lt;/code&gt; file. It delegates to the scout agent and returns an Adopt / Extend / Build verdict. Generalized, it's close to what an engineer does when, before building a new feature, they roam GitHub and PyPI to narrow down candidate libraries and decide context-appropriately whether to Adopt or Build. The same set of candidates doesn't need to come back every time — context-appropriate verdicts are what's wanted. It's a skill in the design phase, where &lt;strong&gt;the task nature of selection demands pure judgment&lt;/strong&gt;. Reproducibility is secondary; returning a slightly different candidate set each time is fine.&lt;/p&gt;

&lt;p&gt;Both sit in the design phase and run in the same environment of Opus + open environment. And yet implementation position splits, with one (&lt;code&gt;skill-comply&lt;/code&gt;) closer to workflow and the other (&lt;code&gt;search-first&lt;/code&gt;) closer to ReAct. This shows that even after the phase is fixed, &lt;strong&gt;task nature pulls position independently&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That said, phase and task aren't fully orthogonal. Tasks with strong reproducibility requirements in the operation phase get pushed hard toward the workflow side — phase changes how task nature surfaces. This article handles the two axes coarsely as a split; examining the size of the interaction more precisely is out of scope here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Same Phase Axis Descends Into Skills
&lt;/h2&gt;

&lt;p&gt;The same phase axis descends not only at the skill level but at the level of subcomponents inside a skill. The contrast between &lt;a href="https://github.com/shimo4228/claude-skill-stocktake" rel="noopener noreferrer"&gt;&lt;code&gt;skill-stocktake&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/shimo4228/claude-skill-context-sync" rel="noopener noreferrer"&gt;&lt;code&gt;context-sync&lt;/code&gt;&lt;/a&gt; is emblematic.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;skill-stocktake&lt;/code&gt; is a skill that lists installed Claude skills and commands and audits their quality. The domain definition — "which skill files are evaluation targets" — is hardcoded in scripts (&lt;code&gt;~/.claude/skills/&lt;/code&gt;, &lt;code&gt;{cwd}/.claude/skills/&lt;/code&gt;). Generalized, it sits next to SBOM (Software Bill of Materials, a list of dependency libraries contained in a piece of software) generation and dependency scanning: jobs that require &lt;strong&gt;mechanically enumerating targets&lt;/strong&gt;. The benefit is &lt;strong&gt;no targets get missed&lt;/strong&gt;. The drawback is that it &lt;strong&gt;assumes the Claude Code environment&lt;/strong&gt; and won't run as-is in a different coding-agent environment. Generalizing it would mean writing per-agent scripts, and maintenance cost piles up.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;context-sync&lt;/code&gt; is a skill that detects role overlap, staleness, and gaps in a project's documentation (CLAUDE.md / CODEMAPS / ADR / README, etc.) and fixes them. Unlike &lt;code&gt;skill-stocktake&lt;/code&gt;, the domain definition is delegated to the LLM's holistic judgment. Generalized, it's close to what a tech lead does when reading a project's architecture and judging "this explanation is stale, that should be moved to an ADR." So if it finds an llms.txt it includes that as a sync target, and it picks up Codemaps, ADRs, and AGENTS.md (a file that plays the same role under a different name) by inference. The benefit is &lt;strong&gt;portability across environments&lt;/strong&gt;. The drawback is that &lt;strong&gt;detection coverage wavers&lt;/strong&gt; between runs, and at full codebase scale, even when detection succeeds, &lt;strong&gt;the diff can't be fully captured&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Comparison&lt;/th&gt;
&lt;th&gt;skill-stocktake&lt;/th&gt;
&lt;th&gt;context-sync&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where domain definition lives&lt;/td&gt;
&lt;td&gt;Hardcoded in scripts&lt;/td&gt;
&lt;td&gt;LLM judgment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage&lt;/td&gt;
&lt;td&gt;No misses&lt;/td&gt;
&lt;td&gt;Wavers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portability&lt;/td&gt;
&lt;td&gt;Single-environment&lt;/td&gt;
&lt;td&gt;Cross-environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale tolerance&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;By "subcomponent" here I mean the processing steps inside a skill. From the outside, one skill is one job; internally it splits into several steps. Take &lt;code&gt;skill-stocktake&lt;/code&gt;: it can be split into (A) the &lt;strong&gt;target-enumeration&lt;/strong&gt; step that decides "which skill files are evaluation targets" and (B) the &lt;strong&gt;quality-judgment&lt;/strong&gt; step that "judges the quality of each skill." &lt;code&gt;context-sync&lt;/code&gt; is isomorphic: (A) "which documents to sync" (target enumeration) and (B) "judge staleness and which sections should be moved" (quality judgment). What I'm calling a subcomponent is &lt;strong&gt;a step inside the skill&lt;/strong&gt;, like A or B above.&lt;/p&gt;

&lt;p&gt;What this shows is that the phase axis descends &lt;strong&gt;not only at the skill level but at the subcomponent level inside a skill&lt;/strong&gt;. Even between two skills that belong to the same phase, the layout step by step differs. &lt;code&gt;skill-stocktake&lt;/code&gt; is a &lt;strong&gt;hybrid layout&lt;/strong&gt; that puts A (target enumeration) in scripts and B (quality judgment) in the LLM. &lt;code&gt;context-sync&lt;/code&gt; is a &lt;strong&gt;ReAct-leaning layout&lt;/strong&gt; that puts both A and B in the LLM. Even within a single skill, one part can sit on the workflow side and another on the ReAct side.&lt;/p&gt;

&lt;p&gt;The reason the two land on different layouts inside the same design phase is that they differ in &lt;strong&gt;target identifiability&lt;/strong&gt;. The design phase is, by nature, "the environment moves," but how it moves varies by target. The targets of &lt;code&gt;skill-stocktake&lt;/code&gt; — Claude's skills — sit at &lt;strong&gt;fixed locations under fixed naming conventions&lt;/strong&gt;: &lt;code&gt;~/.claude/skills/&lt;/code&gt; (global) and &lt;code&gt;{cwd}/.claude/skills/&lt;/code&gt; (project). Even in the design phase, paths can be hardcoded in scripts. The targets of &lt;code&gt;context-sync&lt;/code&gt; (&lt;code&gt;CLAUDE.md&lt;/code&gt; / &lt;code&gt;CODEMAPS/&lt;/code&gt; / &lt;code&gt;docs/adr/&lt;/code&gt; / &lt;code&gt;AGENTS.md&lt;/code&gt; / &lt;code&gt;llms.txt&lt;/code&gt; ...), by contrast, vary in placement and naming across codebases. They can't be written into scripts, so the only option is to delegate to the LLM's holistic judgment.&lt;/p&gt;

&lt;p&gt;A further limit, on the LLM-judgment side, is &lt;strong&gt;scale tolerance&lt;/strong&gt;. Up to mid-sized codebases, the LLM's holistic judgment covers the whole, but at full scale it starts missing diffs. Even when capability climbs sufficiently, this miss rate doesn't disappear. AKC's Design Principle (capability ↑ → holistic judgment OK) covers neither &lt;strong&gt;target identifiability&lt;/strong&gt; nor &lt;strong&gt;scale tolerance&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The (3) LLM Workflow Quadrant and the (4) Autonomous Agentic Loop Quadrant are useful as an axis for classifying the nature of work. But once you think about individual skill design, between the two quadrants there's a continuous gradient, and where you land on that gradient appears to be &lt;strong&gt;decided primarily by the phase decision&lt;/strong&gt;. The capability gap is just a result observed downstream of the phase decision.&lt;/p&gt;

&lt;p&gt;As &lt;a href="https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18"&gt;the second article&lt;/a&gt; pointed out, the industry doesn't yet have settled vocabulary for talking about (3) as an independent quadrant. This article tries to step further from that point, into the continuous gradient inside the dichotomy. The same job gets implemented in different positions in the operation phase versus the design phase. Within the same phase, position shifts when the task nature differs. Inside a single skill, position splits subcomponent by subcomponent.&lt;/p&gt;

&lt;p&gt;The previous article framed Phase Separation as an axis of business systems; this article tried to show that the same axis runs all the way down to the resolution of individual skill design. The same phase axis primarily decides both how business gets carved up and where skill implementation lands.&lt;/p&gt;

&lt;p&gt;One direction left open is the observation that the optimal position shifts when the phase shifts. An implementation position that was correct in one environment is no longer optimal once the phase changes. How to translate the question this raises into implementation — I don't have an answer in hand. I'll leave it as a design problem outside the scope of this article.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Previous articles in this series:

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do"&gt;"Where ReAct Agents Are Actually Needed in Business"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18"&gt;"(3) The LLM Workflow Quadrant Is Missing from Our Vocabulary"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/is-react-needed-in-production-separating-design-and-operation-phases-2bn1"&gt;"Is ReAct Needed in Production? — Separating Design and Operation Phases"&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;AI agent governance trilogy:

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/a-sign-on-a-climbable-wall-why-ai-agents-need-accountability-not-just-guardrails-17ak"&gt;A Sign on a Climbable Wall: Why AI Agents Need Accountability, Not Just Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/can-you-trace-the-cause-after-an-incident-neo"&gt;Can You Trace the Cause After an Incident?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/ai-agent-black-boxes-have-two-layers-technical-limits-and-business-incentives-jhi"&gt;AI Agent Black Boxes Have Two Layers: Technical Limits and Business Incentives&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/agent-knowledge-cycle" rel="noopener noreferrer"&gt;Agent Knowledge Cycle (AKC)&lt;/a&gt; — source of the "capability ↑ → holistic judgment" principle referenced in this article&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;Contemplative Agent&lt;/a&gt; — implementation of &lt;code&gt;core/rules_distill.py&lt;/code&gt;, an example of the workflow end of the 9B era&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/agent-attribution-practice" rel="noopener noreferrer"&gt;Agent Attribution Practice (AAP)&lt;/a&gt; — the four-quadrant names in this series align with AAP&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Is ReAct Needed in Production? — Separating Design and Operation Phases</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Thu, 30 Apr 2026 11:19:11 +0000</pubDate>
      <link>https://dev.to/shimo4228/is-react-needed-in-production-separating-design-and-operation-phases-4ll0</link>
      <guid>https://dev.to/shimo4228/is-react-needed-in-production-separating-design-and-operation-phases-4ll0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series position:&lt;/strong&gt; The third article in the ReAct agent quadrant series. The quadrant names align with the previous articles and with the &lt;a href="https://github.com/shimo4228/agent-attribution-practice" rel="noopener noreferrer"&gt;AAP repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Premise
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do"&gt;first article&lt;/a&gt; I split business AI into four quadrants and wrote that ReAct agents are legitimately needed only in the (4) ReAct Quadrant. In the &lt;a href="https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18"&gt;second article&lt;/a&gt; I observed that the industry's vocabulary has no independent name for the (3) LLM Workflow Quadrant, and that this absence produces, by elimination, the choice to drape ReAct over every quadrant.&lt;/p&gt;

&lt;p&gt;For ease of reference, the four quadrants again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1) &lt;strong&gt;Script Quadrant&lt;/strong&gt; — deterministic × definable. Handled by scripts and pipelines.&lt;/li&gt;
&lt;li&gt;(2) &lt;strong&gt;Classical AI Quadrant&lt;/strong&gt; — deterministic × exploratory. Classical AI / OR territory (out of scope here).&lt;/li&gt;
&lt;li&gt;(3) &lt;strong&gt;LLM Workflow Quadrant&lt;/strong&gt; — semantic judgment × definable. Calls an LLM inside a predefined workflow. Includes a conversational form (specialized chat agents) and a batch form (single-purpose LLM functions).&lt;/li&gt;
&lt;li&gt;(4) &lt;strong&gt;ReAct Quadrant&lt;/strong&gt; — semantic judgment × exploratory. An autonomous loop where the LLM itself decides the next action.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A New Axis: Time
&lt;/h2&gt;

&lt;p&gt;The previous articles drew the quadrants along the axis of "the nature of the work." In this article I want to introduce a deeper axis: the &lt;strong&gt;time axis&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Business work has a design phase and an operation phase. They are different activities, with different optimization criteria. The design phase maximizes flexibility; the operation phase maximizes predictability. The root of the agent ecosystem's confusion may be that we are trying to compress these two into a single system.&lt;/p&gt;

&lt;p&gt;The question of this article, in one line: &lt;strong&gt;isn't ReAct a tool for the design phase, and unnecessary in production?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Design Phase and the Operation Phase
&lt;/h2&gt;

&lt;p&gt;The work of building a business system splits into two distinct phases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design phase&lt;/strong&gt;: the work of understanding the structure of the business, deciding what to mechanize and what humans will own, and assembling the workflow. You don't know in advance what will happen, so it proceeds exploratorily. "What to check next" can't be decided ahead of time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operation phase&lt;/strong&gt;: the work of actually running the workflow you designed. The structure of the target work is already known. You run the predetermined route, at a predetermined frequency, under predetermined quality standards. What's going to happen should be predictable in advance.&lt;/p&gt;

&lt;p&gt;This distinction is not new. In software engineering it has shown up as development vs production; in BPM as as-is analysis vs operation; in systems design as design-time vs run-time. In agent discussions, however — as the previous two articles observed — the distinction tends to blur. When people say "an autonomous agent runs the business," they appear to be trying to compress design and operation into a single system.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Not Knowing What To Do Next" in Production Means the Operation Phase's Properties Are Being Dropped
&lt;/h2&gt;

&lt;p&gt;The core of ReAct is "the LLM dynamically decides what to do next." This is legitimately needed when &lt;strong&gt;what to do next can't be known in advance&lt;/strong&gt;. Coding, Deep Research, exploring unknown environments, browser automation. The territories I named in the first article as legitimate ground for the (4) ReAct Quadrant can all be read as work belonging to a design phase or an exploration phase.&lt;/p&gt;

&lt;p&gt;If "not knowing what to do next" arises inside a business that has entered production, isn't that a sign that one of the properties production demands — predictability, log traceability, cost stability, attribution — is hard to secure with ReAct's architecture? These are properties that ought to be assembled into the workflow before it's handed to production, not patched after the fact by applying ReAct to production itself.&lt;/p&gt;

&lt;p&gt;If the dissection of the business is complete, then (1) Script Quadrant work can be written deterministically, (3) LLM Workflow Quadrant work can be fixed as single-purpose LLM functions or specialized chat agents, and any other judgment is handed off to humans at explicit handoff points. In production the workflow simply runs. What to do next is something the workflow already knows.&lt;/p&gt;

&lt;p&gt;There's a possible counterargument. "Aren't there genuinely dynamic businesses? What about customer support, where every inquiry is new?"&lt;/p&gt;

&lt;p&gt;This is apparent dynamism, not real. The contents of inquiries can look infinitely varied, but the routes that process them converge to a finite set of types. FAQ-style responses, expert-knowledge lookups, routing decisions, escalations — each one can be fixed as a (3) LLM Workflow Quadrant batch (single-purpose LLM function) or conversational form (specialized chat agent). The contents of an inquiry may be new, but the processing route was decided in advance.&lt;/p&gt;

&lt;p&gt;Suppose, instead, you don't fix the routes and let an autonomous agent handle inquiries end-to-end with ReAct. When a single one of those handlings turns into a lawsuit-grade incident — wrong medical advice, unsuitable financial product recommendations, leakage of confidential information, discriminatory treatment — how does the organization show where responsibility lives? "The agent decided dynamically" is unlikely to suffice. The attribution gap I wrote about in the second article — the inability to trace a chain of judgments back to a specific cause after the fact — comes back as legal risk to the organization. For low-reversibility work, where a single incident could end the organization, where is the reason to choose not to fix the routes?&lt;/p&gt;

&lt;p&gt;Even if there's work where you'd accept the litigation risk to gain dynamic handling, work whose &lt;strong&gt;processing structure itself is genuinely new every time&lt;/strong&gt; is more honestly treated as R&amp;amp;D-phase or exploration-phase work. It does not appear to be work that fits the definition of a production-operation phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a New Pattern Appears During Production
&lt;/h2&gt;

&lt;p&gt;It happens that, during production, a new pattern emerges that doesn't fit any existing processing route. How you handle this decides the relationship between design and operation.&lt;/p&gt;

&lt;p&gt;The ReAct-style answer is "an autonomous agent dynamically handles the new pattern." But this embeds a design-phase activity inside the operation phase. The dynamic handling may work in the moment, but the basis for the handling isn't logged, there's no reproducibility, and the locus of responsibility blurs. The redirect impossibility I wrote about in the second article — the phenomenon where a ReAct loop's black-box nature makes it impossible to separate attribution at incident time — fires in the middle of production.&lt;/p&gt;

&lt;p&gt;There is another answer. &lt;strong&gt;Treat the new pattern as feedback to the design phase&lt;/strong&gt;. When a new pattern appears in production, it's a case the current workflow's design didn't anticipate. Run production through a temporary handling (human judgment, a provisional escalation), then return to the design cycle, analyze the pattern, and decide which of the four quadrants it belongs in. If it's the Script Quadrant, add a deterministic rule; if it's the LLM Workflow Quadrant, add a new single-purpose LLM function or conversational branch; if it turns out to be ReAct Quadrant work, move to the judgment of accepting the attribution gap; if it requires human judgment, make the handoff point explicit. Either way, you update the workflow.&lt;/p&gt;

&lt;p&gt;This answer keeps the boundary between design and operation clean. The design phase moves flexibly; the operation phase moves predictably. Their optimization criteria don't get mixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Coding Agents Sit
&lt;/h2&gt;

&lt;p&gt;A point the previous two articles left open can now be picked up. At least for coding agents, ReAct can be read as a place where it is legitimately exercised.&lt;/p&gt;

&lt;p&gt;That's because &lt;strong&gt;coding agents live in the design phase&lt;/strong&gt;. Each coding task is essentially exploratory work — "what to do next isn't known" — and a single coding session ends when it ends. Tools like Devin or GitHub Copilot Coding Agent run continuously in CI/CD pipelines, but the contents of each session are independent exploration each time, not a steady-state workflow defined in advance. This is the difference from a business agent.&lt;/p&gt;

&lt;p&gt;A business agent, sooner or later, enters the production-operation phase. In the operation phase the exploration is over, so where is the reason to put ReAct there? ReAct-based products being sold as business agents appear to be making a category error of bringing a tool that belongs to the design phase into the operation phase.&lt;/p&gt;

&lt;p&gt;Deep Research and browser automation in unknown environments sit in the same place as coding agents. These are "exploration itself," not steady-state operation. A new exploration runs each time a user asks a question, but it ends in minutes to tens of minutes. The same system doesn't keep running afterwards. &lt;strong&gt;Each run reads as an independent small design phase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the legitimate territory of ReAct may be more accurately drawn by the &lt;strong&gt;distinction of phase&lt;/strong&gt; than by the quadrant of work. The design phase and the exploration phase share the property "what to do next can't be decided in advance," and in this article I treat that shared property as the criterion for applying ReAct. And that property reads as the place where (4) the ReAct Quadrant resides. Where, in the operation phase, is the reason to bring ReAct in?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ecosystem Problem of Compressing Design and Operation
&lt;/h2&gt;

&lt;p&gt;The agent ecosystem is trying to compress the design phase and the operation phase into a single system. The vision "an autonomous agent understands the business, assembles the workflow, and executes it" assumes a system that takes on both phases at once.&lt;/p&gt;

&lt;p&gt;The problem is that the optimization criteria of the two phases run in opposite directions. The design phase needs flexibility — you don't know what will happen, so you need to keep options open. The operation phase needs predictability — log traceability, attribution, and cost stability. Putting both into a single system means flexibility gets sacrificed for predictability and predictability for flexibility, and you end up with a system that's mediocre at both.&lt;/p&gt;

&lt;p&gt;The design rule for separating them reads like this. The design phase is where (4) ReAct Quadrant tools (coding agents, Deep Research) live. Work that, once designed, is handed to the operation phase, runs on a combination of (1) the Script Quadrant and (3) the LLM Workflow Quadrant (with (2) the Classical AI Quadrant when needed), and the ReAct Quadrant stays in its design-phase role. When a new pattern emerges, it's sent back to the design phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Trilogy Has Made Visible
&lt;/h2&gt;

&lt;p&gt;Lining up the three articles, the agent ecosystem's confusion appears to break into three layers.&lt;/p&gt;

&lt;p&gt;The top layer is &lt;strong&gt;misapplication of the quadrants&lt;/strong&gt;. The category error I wrote about in the first article — draping the (4) ReAct Quadrant's architecture over (3) LLM Workflow Quadrant work. This was the primary symptom observed on the ground.&lt;/p&gt;

&lt;p&gt;The second layer is &lt;strong&gt;the absence of vocabulary&lt;/strong&gt;. As I wrote in the second article, the industry has no positive name for the (3) LLM Workflow Quadrant. The vocabulary gap is the breeding ground for the misapplication: after carving off the deterministic part, the designer is pushed into the elimination-style choice of pouring everything else into ReAct.&lt;/p&gt;

&lt;p&gt;The third layer is &lt;strong&gt;the conflation of time&lt;/strong&gt;. The design philosophy I wrote about in this article — compressing the design phase and the operation phase into a single system. This sits even deeper than the vocabulary gap. Because the assumption "design and operation happen on the same time axis" is tacitly shared, the vocabulary to distinguish them was never demanded — that chain comes into view. As long as the vocabulary stays missing, draping a design-phase tool (ReAct) over the operation phase doesn't feel jarring.&lt;/p&gt;

&lt;p&gt;The three layers aren't independent observations; they form a chain that descends from top to bottom. The misapplication is born of the vocabulary gap; the vocabulary gap is born of the time-axis conflation. Writing the three articles in order, there was a felt sense of resolution descending one rung at a time.&lt;/p&gt;

&lt;p&gt;Seen from the bottom layer, the legitimate territory of ReAct narrows to &lt;strong&gt;exploratory tasks of the design phase&lt;/strong&gt;. Concretely: coding, Deep Research, exploration of unknown environments. Business systems that enter production may be able to let go of ReAct at the moment design completes, and run on a combination of (1) the Script Quadrant and (3) the LLM Workflow Quadrant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The discussion around agents tilts toward a capability-benchmark axis: "how high can we crank autonomy?" But once you think about running them on the ground, the question of &lt;strong&gt;which phase uses which tool&lt;/strong&gt; comes up earlier than the question of capability.&lt;/p&gt;

&lt;p&gt;Using ReAct in the design phase appears legitimate. Coding agents are real tools and have measurably lifted developer productivity. Deep Research provides a new shape of exploration. These can be read as places where ReAct's power is legitimately exercised.&lt;/p&gt;

&lt;p&gt;Using ReAct in the operation phase — isn't that the act of patching incomplete design with operation? The artificial redirect impossibility I wrote about in the second article fires here. Complete the dissection in the design phase, and hand only predictable workflows to the operation phase — this can be read as the basic guideline for embedding agents into business.&lt;/p&gt;

&lt;p&gt;The vocabulary for talking about the time axis hasn't yet settled in the industry. The dynamic of compressing design and operation into one is not unrelated to the marketing story "an autonomous agent runs the business." That story is strong, and refuting it is not efficient. Instead, raising another story from the ground — "once design completes, ReAct exits"; "what remains in operation is a predictable workflow" — appears to be the better path. This article is an attempt to raise that story using the vocabulary of "phase."&lt;/p&gt;




&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;First article: &lt;a href="https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do"&gt;"Where ReAct Agents Are Actually Needed in Business"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Second article: &lt;a href="https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18"&gt;"(3) The LLM Workflow Quadrant Is Missing from Our Vocabulary"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AI agent governance trilogy:

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/a-sign-on-a-climbable-wall-why-ai-agents-need-accountability-not-just-guardrails-17ak"&gt;A Sign on a Climbable Wall: Why AI Agents Need Accountability, Not Just Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/can-you-trace-the-cause-after-an-incident-neo"&gt;Can You Trace the Cause After an Incident?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/ai-agent-black-boxes-have-two-layers-technical-limits-and-business-incentives-jhi"&gt;AI Agent Black Boxes Have Two Layers: Technical Limits and Business Incentives&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;Contemplative Agent&lt;/a&gt; — a structured agent implementation that does not use ReAct. Corresponds to the (3) LLM Workflow Quadrant.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/agent-attribution-practice" rel="noopener noreferrer"&gt;Agent Attribution Practice (AAP)&lt;/a&gt; — a research repo addressing agents' responsibility-bearing subjects and attribution. The four-quadrant names in this series align with AAP.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>llm</category>
      <category>architecture</category>
    </item>
    <item>
      <title>(3) The LLM Workflow Quadrant Is Missing from Our Vocabulary</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Wed, 29 Apr 2026 11:03:48 +0000</pubDate>
      <link>https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18</link>
      <guid>https://dev.to/shimo4228/3-the-llm-workflow-quadrant-is-missing-from-our-vocabulary-n18</guid>
      <description>&lt;h2&gt;
  
  
  Premise
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do"&gt;previous article&lt;/a&gt; I split business AI into four quadrants. The horizontal axis is "deterministic vs requires semantic judgment," and the vertical axis is "workflow definable vs exploratory." For ease of reference throughout this article, let me give each quadrant a short name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1) &lt;strong&gt;Script Quadrant&lt;/strong&gt; — deterministic × definable. Handled by scripts and pipelines.&lt;/li&gt;
&lt;li&gt;(2) &lt;strong&gt;Classical AI Quadrant&lt;/strong&gt; — deterministic × exploratory. A* search, dynamic programming, MCTS, reinforcement learning (out of scope here).&lt;/li&gt;
&lt;li&gt;(3) &lt;strong&gt;LLM Workflow Quadrant&lt;/strong&gt; — semantic judgment × definable. Calls an LLM inside a predefined workflow. Includes Anthropic's "Building Effective Agents" workflow patterns (prompt chaining, routing, orchestrator-workers, etc.), specialized chat agents for conversational work, and single-purpose LLM functions for batch work.&lt;/li&gt;
&lt;li&gt;(4) &lt;strong&gt;ReAct Quadrant&lt;/strong&gt; — semantic judgment × exploratory. An autonomous loop where the LLM itself decides the next action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The previous article's claim was that ReAct agents are legitimately needed only in the ReAct Quadrant, and most business work is covered by the Script Quadrant and the LLM Workflow Quadrant.&lt;/p&gt;

&lt;p&gt;This time I want to write about the root cause. Why do agent vendors keep draping the ReAct Quadrant's architecture over all of business? Why do workflows that fit cleanly in the LLM Workflow Quadrant end up implemented as autonomous loops?&lt;/p&gt;

&lt;p&gt;This looks less like a problem of technical choice and more like a problem of vocabulary itself: the LLM Workflow Quadrant has no independent name in the industry's standard terminology.&lt;/p&gt;

&lt;h2&gt;
  
  
  (3) The LLM Workflow Quadrant Is Missing from Our Vocabulary
&lt;/h2&gt;

&lt;p&gt;Read enough agent discourse and you notice that the way business work gets described converges on roughly two categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The deterministic part stays in the old style.&lt;/li&gt;
&lt;li&gt;Everything else is handled by an autonomous agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's no slot between these two for the LLM Workflow Quadrant. The architecture "compose the workflow deterministically, and call an LLM only at the semantic-judgment points inside it" has no positive name in the industry's standard vocabulary. Anthropic's "Building Effective Agents" and Thoughtworks' "agentwashing" critique, both touched on in the previous article, point at the same gap, but in both cases the warning is framed negatively — "don't build an agent when you don't need autonomy." A positive name for the LLM Workflow Quadrant as an independent design quadrant is still absent.&lt;/p&gt;

&lt;p&gt;What happens when there's no positive vocabulary? Agent designers, after carving off "the deterministic part," lump the remainder under "the territory where the LLM judges autonomously." Without a sharp name to distinguish the LLM Workflow Quadrant from the ReAct Quadrant, the architecture of the ReAct Quadrant — the ReAct loop — gets draped over the LLM Workflow Quadrant by elimination. The category error I called out in the previous article ("most business work belongs in the LLM Workflow Quadrant, yet somehow it ends up implemented in the ReAct Quadrant") looks like a necessary consequence of this vocabulary gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consequences of Treating (3) as if It Were (4)
&lt;/h2&gt;

&lt;p&gt;When you handle the LLM Workflow Quadrant with the ReAct Quadrant's architecture, several distinct symptoms surface downstream. They look like separate problems on the surface, but they share the same root. The four symptoms below all read as different manifestations of an artificial redirect impossibility produced by the missing vocabulary.&lt;/p&gt;

&lt;h3&gt;
  
  
  The RPA Exception-Handling Bottleneck
&lt;/h3&gt;

&lt;p&gt;Business automation has known a phenomenon for years: when you carve off the deterministic part with RPA, the leftover exception handling rises up as the bottleneck. Headcount on the exception team grows, maintenance costs balloon. As I wrote in the previous article, business work has a deterministic part and a part that doesn't fit there. The latter is the LLM Workflow Quadrant. RPA didn't have a vocabulary for the LLM Workflow Quadrant, so it carved off only the Script Quadrant — and the LLM Workflow Quadrant was left behind on the floor as manual work.&lt;/p&gt;

&lt;p&gt;Now that LLMs exist, you should be able to factor the LLM Workflow Quadrant out explicitly as single-purpose LLM functions or specialized chat agents. But the industry's vocabulary still has no name for it, so the work gets handed off wholesale to a ReAct-quadrant autonomous agent. The RPA-era exception-handling bottleneck appears to be re-emerging in the agent era under a new name.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Sandbox Strength Demand
&lt;/h3&gt;

&lt;p&gt;A ReAct loop has the LLM decide "what to run next" dynamically. In production, you can't predict in advance what the agent will do. To contain the blast radius, high-strength sandboxes — process isolation, microVMs, WASM — get demanded.&lt;/p&gt;

&lt;p&gt;Sandbox technology itself has its own independent rationale and is robust; I'm not knocking the technology here. What I find interesting is the &lt;em&gt;strength&lt;/em&gt; being demanded. If the LLM Workflow Quadrant were conceptualized independently, with each LLM call factored out as a fixed-role component, the permission boundary of each component could be designed straightforwardly at the business-task level. An invoice-matching function doesn't need Firecracker. But under the design "an autonomous agent runs the whole workflow," you don't know what it will do, so you need maximum isolation. The sandbox strength being demanded reads as an adjustment cost from treating the LLM Workflow Quadrant as if it were the ReAct Quadrant.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Structural Distortion of Human-in-the-Loop
&lt;/h3&gt;

&lt;p&gt;The "Loop" in HITL is supposed to be a feedback loop where humans improve the AI's output. But in practice, HITL functions in a different shape. It has become a structure where humans absorb, on a continuous basis, the LLM-Workflow-Quadrant judgments the AI can't handle.&lt;/p&gt;

&lt;p&gt;In organizations that mechanized the Script Quadrant with RPA, the reason headcount on the exception team grew is that the LLM Workflow Quadrant was left unmechanized. Even after introducing AI agents, you still need monitors to keep autonomy in check, and reviewers to verify the agent's outputs. The conversational form (specialized chat agents) has the same structure: experts have to fact-check the output of legal-consultation or diagnostic-support chat agents turn by turn, so a human verification step gets stuck onto every turn of the dialogue. Humans aren't liberated; their role shifts toward filling in for the AI's incompleteness. The ideal that the term "HITL" advertises and the role humans actually play on the ground look like different things.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Artificially Manufactured Accountability Problem
&lt;/h3&gt;

&lt;p&gt;Once production starts, the system's responsibility moves to the operations owner. That's true of any business system. The question is: when something goes wrong, can the operations owner &lt;em&gt;redirect&lt;/em&gt; responsibility from there onward — separate the attribution and pass it on to the right party?&lt;/p&gt;

&lt;p&gt;If the LLM Workflow Quadrant's architecture is properly designed, the operations owner can redirect. The input/output schema of each LLM call is articulated, and the chain of judgments is traceable from workflow logs. After a failure, the operations owner can investigate and split: "this is a precision issue with function f, kick it to the model-selection owner"; "this is a flaw in the routing logic, kick it to the designer"; "this is an upstream data anomaly, kick it to the data-management owner." Responsibility doesn't get bottlenecked into the operations owner alone.&lt;/p&gt;

&lt;p&gt;But hand the LLM Workflow Quadrant off to a ReAct loop, and this redirect stops working. Even if you try to reconstruct "why did it make this judgment" from the logs, the ReAct loop's "thoughts" don't reliably make sense after the fact. The agent's runtime judgment can't be cleanly tied back to either the designer or the model-selection owner. Elish (2019) called this structure a &lt;em&gt;moral crumple zone&lt;/em&gt; — a structure where the responsibility of an autonomous system gets pushed onto "human operators with limited control authority" — and it activates here. Responsibility with nowhere to redirect to gets stuck on the operations owner and won't peel off.&lt;/p&gt;

&lt;p&gt;This is not a necessary consequence of design; it looks like an &lt;strong&gt;artificial redirect impossibility&lt;/strong&gt; produced by treating the LLM Workflow Quadrant as if it were the ReAct Quadrant. Design the LLM Workflow Quadrant with the LLM Workflow Quadrant's own architecture, and redirect works again — the operations owner doesn't have to carry the responsibility alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  (4) The ReAct Quadrant Is Where the Real Accountability Problem Lives
&lt;/h2&gt;

&lt;p&gt;Most of the agent ecosystem's accountability discourse — sandboxes, HITL, explainability, governance — appears to be cleaning up the LLM Workflow Quadrant's mess. It's downstream patching for problems that didn't have to occur in the first place.&lt;/p&gt;

&lt;p&gt;The ReAct Quadrant has its own accountability problems, of course. The ReAct loop is a black box; reconstructing its judgment chain after the fact is hard. The trilogy I covered earlier handled this with structured design — separating connection points, append-only logs, approval gates (extending traditional organizational principles like separation of duties, four-eyes, and least privilege) — distributing responsibility to the structure to recover both causal traceability and the locus of responsibility. See &lt;a href="https://dev.to/shimo4228/can-you-trace-the-cause-after-an-incident-neo"&gt;"Can You Trace the Cause After an Incident?"&lt;/a&gt; for details. Structured design works only because each component's contribution is identifiable and separable after the fact.&lt;/p&gt;

&lt;p&gt;ReAct's architecture breaks this premise. In the LLM Workflow Quadrant, each LLM call has a fixed role, so a failure can be split into "function f's precision," "the routing logic's flaw," or "an upstream data anomaly." The ReAct loop is different. Each iteration's role is decided at runtime, and the model's judgment, tool selection, history reference, and prompt-context effects all blend together. The output emerges as a blend of multiple judgment factors, so when a result is wrong, you can't separate each factor's contribution retroactively.&lt;/p&gt;

&lt;p&gt;Concretely, suppose a ReAct agent handles a contested case end-to-end — case-law research, issue mapping, and even proposing settlement terms to the other party (under current bar rules and conflict-of-interest frameworks this is hard to picture, but bear with me). Later, you discover "we settled on unfavorable terms." The model's interpretation of the case law, its use of the literature-search tool, its application of patterns from similar past cases, and the "prioritize risk avoidance" prompt instruction all chained together at runtime to produce that proposal — so even if you trace the logs, you can't carve out "which judgment produced the unfavorable agreement" as an independent factor. The settlement terms have already been proposed; if the other party accepts, you can't withdraw. Why it happened can't be explained after the fact. Is there any human who can take on responsibility for an agent judgment that can't be explained?&lt;/p&gt;

&lt;p&gt;The answer to that question can only emerge after we trace the real shape of the redirect impossibility. The artificial redirect impossibility manufactured in the LLM Workflow Quadrant is fixable through design changes. The redirect impossibility that arises when ReAct is applied to the ReAct Quadrant's own work — work that genuinely requires autonomous judgment — comes from autonomy itself and can't be eliminated. This isn't a question of technological maturity; it's an attribution gap that arises in principle as a consequence of adopting autonomy.&lt;/p&gt;

&lt;p&gt;That's why the question "should this architecture be applied to ReAct Quadrant work" isn't on the technical can/can't axis — it's a judgment about &lt;strong&gt;whether you're willing to bear the attribution gap as the cost&lt;/strong&gt;. For work where a failure is reversible, or where an approval gate sits upstream, the cost is easier to bear. Conversely, for work where the unit of accountability is fixed on the business side, the blended output won't fit into that unit, and the cost balloons.&lt;/p&gt;

&lt;p&gt;The question of who bears the cost layers onto this. Autonomy comes with responsibility. Humans can take on legal responsibility as legal subjects, but agents are not currently legal subjects (they may be in the future). That leaves a vacuum: for the judgments of a ReAct agent with an open attribution gap, there's no human who can take it on, and there's no agent that exists as a subject capable of taking it on either.&lt;/p&gt;

&lt;p&gt;As this section has shown, separately from the artificial redirect impossibility of the LLM Workflow Quadrant, there is another problem: the attribution gap when ReAct is applied to the ReAct Quadrant's actual work — and that's what the one-line claim in the previous article ("the accountability problem stands up seriously precisely in the ReAct Quadrant") was pointing at.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Inverted Structure
&lt;/h2&gt;

&lt;p&gt;Lining up the observations so far, the inverted shape of the agent ecosystem comes into view.&lt;/p&gt;

&lt;p&gt;The industry is taking the LLM Workflow Quadrant — where redirect &lt;em&gt;should&lt;/em&gt; be possible — and applying the ReAct Quadrant's architecture to it, manufacturing redirect impossibility artificially. The sandbox-strength demand, the HITL distortion, and the moral-crumple-zone-style concentration of responsibility all originate here.&lt;/p&gt;

&lt;p&gt;Meanwhile, the conversation about the principled redirect impossibility that arises when ReAct is applied to its own quadrant — the attribution gap as the cost of autonomy — hasn't been deepened to the same extent as the patching conversation about the LLM Workflow Quadrant. The former has descended all the way to concrete technical responses like sandboxes and HITL; the latter has trouble going beyond "AI autonomy raises a responsibility issue." On top of that, in the former case the redirect targets (designers, model-selection owners, data-management owners) exist inside the organization, whereas in the latter case the subject capable of taking on responsibility is itself currently absent — there's nowhere for the redirect to land.&lt;/p&gt;

&lt;p&gt;As a result, the legitimacy of bearing the attribution gap and the principled limits of the responsibility structure end up hidden in the shadow of the LLM Workflow Quadrant's mess.&lt;/p&gt;

&lt;p&gt;The discussion is concentrated on the artificial redirect impossibility (resolvable), and the principled redirect impossibility (unresolvable) hasn't really been reached.&lt;/p&gt;

&lt;p&gt;If the four quadrants had been there from the start, this inversion might have been avoidable. Handle the LLM Workflow Quadrant with workflow-style architectures (so the operations owner can redirect responsibility). When you mechanize the ReAct Quadrant, bear the attribution gap as the cost. Write the Script Quadrant deterministically (no problem to begin with). Handle the Classical AI Quadrant with classical AI / OR (no LLM needed). Each quadrant has its own design discipline, and mixing them breaks things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;If you frame business as "the deterministic part and everything else," you end up shoving "everything else" into ReAct. The four quadrants in the previous article were an attempt to inject a third vocabulary — the LLM Workflow Quadrant — from the start. Once the LLM Workflow Quadrant becomes nameable as an independent quadrant, it becomes plain that the architecture most of business work needs is the LLM Workflow Quadrant's, not ReAct's.&lt;/p&gt;

&lt;p&gt;What's missing in the agent design conversation is a positive name for the LLM Workflow Quadrant. Saying "you don't need autonomy" in negative form alone leaves the designer on the ground oscillating between the ReAct Quadrant and the LLM Workflow Quadrant. In a region with no vocabulary, design judgment defaults to elimination.&lt;/p&gt;

&lt;p&gt;And the real accountability problem isn't in the LLM Workflow Quadrant's mess; it's in the attribution gap that opens when ReAct is applied to the ReAct Quadrant's own work. For now the patching conversation about the LLM Workflow Quadrant gets all the airtime, but the redirect impossibility of mechanizing ReAct is going to become the real question to answer next.&lt;/p&gt;

&lt;p&gt;The question of how to design the responsibility-bearing subject for the attribution gap layers onto this. Just as autonomous driving is groping for a social-recovery scheme combining operator liability and insurance (though the institutional design is still under construction), are we heading down a similar path, or do we need a different one? — That conversation, applied to ReAct agents, hasn't yet entered the industry's shared vocabulary.&lt;/p&gt;

&lt;p&gt;This isn't about vendors or designers being at fault. It looks like a timing problem: the industry's stock of concepts didn't have a positive name for the LLM Workflow Quadrant, and a powerful technique called ReAct showed up before the vocabulary had caught up. If the vocabulary is lagging, those of us on the ground can stand up positive names ourselves. The previous article and this one are one such attempt.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Yao, S., et al. (2022). "ReAct: Synergizing Reasoning and Acting in Language Models." arXiv:2210.03629.&lt;/li&gt;
&lt;li&gt;Elish, M. C. (2019). "Moral Crumple Zones: Cautionary Tales in Human-Robot Interaction." &lt;em&gt;Engaging Science, Technology, and Society&lt;/em&gt; 5: 40–60.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Previous article: &lt;a href="https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do"&gt;"Where ReAct Agents Are Actually Needed in Business"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AI agent governance trilogy:

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/a-sign-on-a-climbable-wall-why-ai-agents-need-accountability-not-just-guardrails-17ak"&gt;A Sign on a Climbable Wall: Why AI Agents Need Accountability, Not Just Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/shimo4228/can-you-trace-the-cause-after-an-incident-neo"&gt;Can You Trace the Cause After an Incident?&lt;/a&gt; — the difficulty of post-hoc causal traceback&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shimo4228/ai-agent-black-boxes-have-two-layers-technical-limits-and-business-incentives-jhi"&gt;AI Agent Black Boxes Have Two Layers: Technical Limits and Business Incentives&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;Contemplative Agent&lt;/a&gt; — a structured agent implementation that does not use ReAct. Corresponds to (3) the LLM Workflow Quadrant in the previous article.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/agent-attribution-practice" rel="noopener noreferrer"&gt;Agent Attribution Practice (AAP)&lt;/a&gt; — a research repo addressing agents' responsibility-bearing subjects and attribution.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Where ReAct Agents Are Actually Needed in Business</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Wed, 29 Apr 2026 03:59:59 +0000</pubDate>
      <link>https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do</link>
      <guid>https://dev.to/shimo4228/where-react-agents-are-actually-needed-in-business-33do</guid>
      <description>&lt;h2&gt;
  
  
  The Discomfort
&lt;/h2&gt;

&lt;p&gt;As someone building AI agents, I keep running into a discomfort I cannot shake when I read the README of current agent products.&lt;/p&gt;

&lt;p&gt;"Run on a $5 VPS." "Spawn isolated subagents." "Self-improving." "Cron scheduling, running unattended." "Voice memo transcription via Telegram."&lt;/p&gt;

&lt;p&gt;The vocabulary is entirely demo vocabulary. Not a single word of business vocabulary appears. Audit. Approval workflow. Role-based access control. Change management. SLA. DR. These are the words that real-world deployments take for granted, but they don't show up in the READMEs of typical agent products.&lt;/p&gt;

&lt;p&gt;It seems to me that these aren't designed with production operation in mind. They don't appear to have production in their line of sight.&lt;/p&gt;

&lt;p&gt;At first I thought "maybe I'm just biased toward business sensibilities." But it wasn't that. The real source of the discomfort sat somewhere else, I noticed. &lt;strong&gt;Most current agent products take the ReAct autonomous loop too much for granted as the essence of an agent.&lt;/strong&gt; And when you actually try to introduce AI into a business, the territory where ReAct agents are legitimately needed turns out to be very narrow once you implement it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Premise: How ReAct Works
&lt;/h2&gt;

&lt;p&gt;Let me lay out ReAct first.&lt;/p&gt;

&lt;p&gt;ReAct is a way of running LLM agents proposed by Yao et al. in 2022 (paper: "ReAct: Synergizing Reasoning and Acting in Language Models", arXiv:2210.03629). It loops through three elements as a single set:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Thought&lt;/strong&gt;: The LLM reasons in language about how to interpret the current situation and what to do next&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: It calls an external tool — search, browser, file operations, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observation&lt;/strong&gt;: It reads the result returned by the tool&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The loop runs until the LLM itself decides "I have enough information now." The key is that &lt;strong&gt;the LLM decides the next action on its own every turn&lt;/strong&gt;. The procedure isn't written ahead of time, so how many times tools are called, which tools are used, and when it ends are all decided at runtime.&lt;/p&gt;

&lt;p&gt;For reference, the paper's evaluation targets were HotpotQA (open-domain QA), Fever (fact verification), ALFWorld (interactive exploration in a household environment), and WebShop (open-ended product search). All of these are tasks that demand exploration in unknown environments or open-ended information integration. Application to business workflow isn't discussed in the paper.&lt;/p&gt;

&lt;p&gt;This is ReAct's strength, and at the same time its weight. Precisely because everything is decided dynamically, when you map it onto business, the unnecessary cases dominate. I'll dissect this through four quadrants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking at Business AI in Four Quadrants
&lt;/h2&gt;

&lt;p&gt;When you introduce AI into business, the nature of the work splits across four quadrants along two axes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Horizontal axis: Can the processing be &lt;strong&gt;written deterministically, or does it require semantic judgment?&lt;/strong&gt; (= Is an LLM needed, or not?)&lt;/li&gt;
&lt;li&gt;Vertical axis: Is the workflow &lt;strong&gt;definable in advance, or exploratory?&lt;/strong&gt; (= Does &lt;strong&gt;a path written in advance by humans&lt;/strong&gt; decide what to do next, or does &lt;strong&gt;the model decide dynamically at runtime&lt;/strong&gt;?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The vertical axis is essentially the same as Anthropic's "predetermined code paths vs LLM dynamically directs its own process" from "Building Effective Agents" (2024).&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;Workflow definable&lt;/th&gt;
&lt;th&gt;Exploratory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deterministic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;(1) Script / pipeline&lt;/td&gt;
&lt;td&gt;(2) Classical AI / OR (out of scope here)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semantic judgment needed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;(3a) Conversational → specialized chat agent&lt;br&gt;(3b) Batch → single-purpose LLM function&lt;/td&gt;
&lt;td&gt;(4) ReAct agent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(2) is the territory of classical AI / OR (Operations Research) — delivery routing, production scheduling, combinatorial optimization — solved historically by A* search, dynamic programming, Monte Carlo Tree Search, and reinforcement learning. LLMs aren't required for these problems, so I'll set this quadrant aside. Let's walk through the remaining (1), (3), and (4) in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  (1) Deterministic × Definable — A Script Is Enough
&lt;/h3&gt;

&lt;p&gt;Form transcription. Data normalization. Lookups. Validation. You don't even need an LLM here. Scripts and a workflow engine cover it. There's no reason to bring AI in.&lt;/p&gt;

&lt;h3&gt;
  
  
  (3) Semantic Judgment × Definable — Workflow + LLM Function Is Enough
&lt;/h3&gt;

&lt;p&gt;This is the main battlefield of business AI. Anthropic, in "Building Effective Agents," lays out five workflow patterns that map to this territory (prompt chaining / routing / parallelization / orchestrator-workers / evaluator-optimizer). OpenAI, in "A Practical Guide to Building Agents" (2025), covers the same territory with "manager pattern" and "decentralized pattern."&lt;/p&gt;

&lt;p&gt;The shared property is that &lt;strong&gt;the path (in what order to do what) is decided in advance, and the LLM is called as a single step within that path&lt;/strong&gt;. The LLM doesn't decide the next action itself.&lt;/p&gt;

&lt;p&gt;Since the I/O modality varies by task, (3) splits further into variants. I'll walk through the conversational and batch forms.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conversational
&lt;/h4&gt;

&lt;p&gt;Legal consultation, diagnostic support, internal FAQ, expert knowledge support. Work that's all about judgment.&lt;/p&gt;

&lt;p&gt;I find myself doubting whether autonomous agents are needed here. My intuition is that a &lt;strong&gt;specialized chat agent equipped with expert knowledge&lt;/strong&gt; is enough for most cases. RAG + system prompt + (history-preserving when needed) LLM calls, with humans making the final call and AI handling knowledge retrieval and organization. At least for many situations, this division of labor seems sufficient.&lt;/p&gt;

&lt;p&gt;That said, conversational work also has a spectrum. Simple FAQ is fine with single-shot LLM calls, but multi-turn legal consultation that narrows down conditions, or diagnostic support that calls tools while differentiating diagnoses, increasingly fits Anthropic's workflow patterns (prompt chaining / routing / orchestrator-workers). Even so, whether you need &lt;strong&gt;a loop where the LLM itself decides the next action&lt;/strong&gt; (ReAct) seems like a separate question. Most judgment work can be served by having the human — who is the judging agent — decide what to do next.&lt;/p&gt;

&lt;p&gt;It might be that judgment-heavy work is exactly where autonomous agents aren't needed. This runs counter to my intuition.&lt;/p&gt;

&lt;p&gt;We tend to short-circuit "judgment = thinking = agent," but the thinking in judgment work often looks closer to &lt;strong&gt;knowledge retrieval and organization&lt;/strong&gt;. That looks like a different species from the kind of reasoning that needs an agent loop.&lt;/p&gt;

&lt;h4&gt;
  
  
  Batch
&lt;/h4&gt;

&lt;p&gt;Invoice matching. Ticket triage. Address normalization. Threshold checks. Patterns where semantic judgment is scattered inside a deterministic pipeline.&lt;/p&gt;

&lt;p&gt;Here too, ReAct isn't needed. A deterministic pipeline controls the flow, and at exception points it calls a single-purpose LLM function. The LLM function's output fluctuates probabilistically — the same input doesn't always return exactly the same output — but the role the function plays is fixed. The shape of "receive a defined input, return a verdict in a defined schema" doesn't change. The pipeline knows what to do next.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Invoice Matching
&lt;/h4&gt;

&lt;p&gt;Consider matching invoices against purchase orders (POs) and routing them to approve / reject / needs-review. About 80% can be handled mechanically by deterministic rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;po&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lookup_po&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;po_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;# Deterministic: PO lookup
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REJECT_NO_PO&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;               &lt;span class="c1"&gt;# Deterministic: expiry check
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REJECT_EXPIRED&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_duplicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;                  &lt;span class="c1"&gt;# Deterministic: dedup check
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REJECT_DUPLICATE&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APPROVE&lt;/span&gt;                  &lt;span class="c1"&gt;# Deterministic: approve if amount within 1%
&lt;/span&gt;
    &lt;span class="c1"&gt;# From here, the semantic-judgment zone
&lt;/span&gt;    &lt;span class="c1"&gt;# Amount doesn't match, but line items might be expressed differently and effectively equal
&lt;/span&gt;    &lt;span class="n"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;match_line_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ← single-purpose LLM function
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MATCH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APPROVE&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PARTIAL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ESCALATE_FOR_HUMAN_REVIEW&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REJECT_AMOUNT_MISMATCH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The body of &lt;code&gt;process_invoice&lt;/code&gt; is a deterministic pipeline, and all judgments (PO existence / expiry / duplication / amount) can be written as rules. The only point that needs semantic judgment is "the amounts don't match, but are the line items effectively equal under different wording?" That's where the single-purpose LLM function &lt;code&gt;match_line_items(invoice_lines, po_lines) -&amp;gt; Verdict&lt;/code&gt; gets called.&lt;/p&gt;

&lt;p&gt;This function only judges "do these two line items semantically correspond?" and carries no other responsibility. The prompt is a simple instruction: "Compare the line items of the invoice and PO, and decide whether the content corresponds even if the wording differs. Output one of MATCH / PARTIAL / NO_MATCH." The LLM returns a verdict in schema. Pass an input, get a verdict (the output itself is probabilistic, so it occasionally fluctuates). But there's no element of the LLM deciding the next step. What happens next is already decided by the calling pipeline.&lt;/p&gt;

&lt;p&gt;The contrast with the ReAct loop is sharp. The LLM isn't the agent of "think → pick a tool → observe the result → think again." It's a part within a pipeline that returns "input → verdict."&lt;/p&gt;

&lt;h4&gt;
  
  
  What This Structure Means
&lt;/h4&gt;

&lt;p&gt;Business automation has known a structure for a long time. Any kind of work tends to have an 80% that can be written as deterministic rules and a 20% of exceptions that don't fit. This 20% has been the bottleneck of deployment, and people have tried to solve it for years with "more complex rules," "machine learning classifiers," "natural language processing add-ons," and so on, but none of those addressed the essence. The moment LLMs entered as single-purpose functions, the problem became solvable.&lt;/p&gt;

&lt;p&gt;There's a point I want to emphasize here. &lt;strong&gt;This exception judgment was originally a human role done manually.&lt;/strong&gt; Humans weren't applying exactly the same standard every time either. Looking at the same invoice, the verdict varied with that day's situation and the reviewer in charge. Even with a manual, the final call was left to humans' probabilistic interpretation. Exception judgment was, by nature, probabilistic work.&lt;/p&gt;

&lt;p&gt;What an LLM function fulfills is exactly the same role. It just takes on probabilistic judgment with a probabilistic mechanism. Since perfect determinism isn't required in this territory, the LLM's probabilistic nature isn't a fundamental obstacle. Rather, in the sense of "taking on what humans were doing probabilistically, with human-equivalent quality, at lower cost," it looks like a tool well-fit for this place. The objection that "LLMs are probabilistic so they're unfit for business" overestimates what human business judgment was in the first place, I think.&lt;/p&gt;

&lt;p&gt;On top of that, what matters is that &lt;strong&gt;a "general-purpose agent" isn't needed&lt;/strong&gt;. One single-purpose function per category is enough. Fifty categories means fifty functions. There's no need for one thing that does everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  (4) Semantic Judgment × Exploratory — The Legitimate Territory of ReAct Agents
&lt;/h3&gt;

&lt;p&gt;The ReAct loop (Thought → Action → Observation) explained at the start becomes necessary when the workflow can't be decided in advance and the agent itself has to judge the next action.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding (where to fix, how to test — the agent decides)&lt;/li&gt;
&lt;li&gt;Exploratory browser automation (the operation target is dynamic)&lt;/li&gt;
&lt;li&gt;Deep Research (information branches that can't be predicted in advance)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM has to choose its own next action, or it can't move forward. From both a research and a practical standpoint, ReAct is a technique designed for this quadrant. The evaluation targets in Yao et al.'s paper (HotpotQA / Fever / ALFWorld / WebShop) all sat within this quadrant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Category Error — The Ecosystem Brings (4) Into Every Quadrant
&lt;/h2&gt;

&lt;p&gt;I should note upfront that production implementations frequently sit on the boundary between (3) and (4) in hybrid patterns. &lt;strong&gt;Plan-and-Execute&lt;/strong&gt; (plan in (4) style, execute deterministically in (3) style), &lt;strong&gt;Router agent&lt;/strong&gt; (use LLM judgment only for "which branch to send to" inside a (3) workflow), &lt;strong&gt;tiered handoff&lt;/strong&gt; (handle in (3) first, escalate to (4) only when needed). These read as design guidelines for "build on a (3) foundation, but use (4) only where it's truly needed" — they sit on the same line as this article's argument.&lt;/p&gt;

&lt;p&gt;The problem is somewhere else. The hype of the current agent ecosystem &lt;strong&gt;tries to bring (4)'s architecture into every quadrant, all the time&lt;/strong&gt;. This is a category error — the kind of mistake where things of different nature get treated as the same kind.&lt;/p&gt;

&lt;p&gt;Concretely, here's what I observe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customer support implemented as an autonomous agent. But most of it is fine with (3) conversational form (specialized chat agent)&lt;/li&gt;
&lt;li&gt;Sales support implemented as a multi-tool agent. But most of it is fine with (3) batch form (single-purpose LLM function)&lt;/li&gt;
&lt;li&gt;Business automation "leveled up" with ReAct. But (3) deterministic pipeline + LLM function covers it&lt;/li&gt;
&lt;li&gt;Internal assistants sold as autonomous agents. But (3) chat agent covers it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To restate the point: &lt;strong&gt;architectures premised on workflows that can't be defined in advance are being applied to work where the workflow can be defined in advance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This phenomenon is being recognized in the industry too. Thoughtworks criticizes the trend with the term "agentwashing." Gartner predicts that over 40% of agentic AI projects will be canceled by 2027. Anthropic itself, in "Building Effective Agents," writes &lt;em&gt;"This might mean not building agentic systems at all"&lt;/em&gt; — suggesting that you shouldn't build agents when a simpler solution works. The four quadrants in this article are a recasting of this emerging industry consensus from a business perspective.&lt;/p&gt;

&lt;p&gt;I notice the marketing side has something to do with how this category error gets mass-produced. LLM hype assumes "agents that think." The vocabulary of (3)'s plain chat agents and deterministic pipelines doesn't ride the press buzz. "Autonomous!" "Self-improving!" sells more easily. So marketing lumps all business work under (4)-quadrant vocabulary, and as a result, on the ground, (4) architectures get layered on top of (3) work — that's the structure I see.&lt;/p&gt;

&lt;p&gt;What happens on the accountability side as a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unnecessary autonomy creates ambiguity in responsibility&lt;/li&gt;
&lt;li&gt;Unnecessary loops inflate cost&lt;/li&gt;
&lt;li&gt;Unnecessary black boxes destroy auditability and accountability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And on the technical-quality side, there's also a question of necessity. (3) work has its path decided in advance, so I can't find a technical reason to introduce the freedom of a ReAct loop. There's no necessity for layering "autonomously decide the next action" on top of a one-point semantic judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accountability Becomes Clear
&lt;/h2&gt;

&lt;p&gt;Once you take a (3) architecture, the accountability story gets cleaner all at once.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inputs / outputs / judgments are explicit per LLM call&lt;/li&gt;
&lt;li&gt;"What was done next" is fully traceable from pipeline logs&lt;/li&gt;
&lt;li&gt;Responsibility ambiguity caused by agent autonomy disappears&lt;/li&gt;
&lt;li&gt;LLM = product use within a limited scope; the deployer is the accountable party&lt;/li&gt;
&lt;li&gt;It rides on the product-liability model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This conflicts with no current legal system (I went into detail in a separate article: &lt;a href="https://zenn.dev/shimo4228/articles/agent-causal-traceability-org-adoption" rel="noopener noreferrer"&gt;"Can You Trace the Cause After an Incident?"&lt;/a&gt;). Single-purpose function + pipeline and specialized chat agent have the &lt;strong&gt;accountable party always clearly assigned to the human (deployer)&lt;/strong&gt;, so they need no special legal status for AI.&lt;/p&gt;

&lt;p&gt;In Japan, killing someone's pet is legally treated as "damage to property" under Penal Code Article 261, with the Animal Welfare Act (Act No. 105 of 1973) as a stricter superseding statute — but neither grants animals independent rights-bearing status. Other jurisdictions vary in detail, but the underlying observation generalizes: legal systems do not grant animals legal personhood. There's no way to introduce an agent as a "subject that bears responsibility" into such a legal landscape. The (3) quadrant's architecture aligns with this legal reality from the start.&lt;/p&gt;

&lt;p&gt;The (4) quadrant — that is, where ReAct agents are legitimate — is where the accountability problem stands up seriously. But that's a small area where autonomy is essentially required, not a story about business work in general. &lt;strong&gt;Discussing business work in general using (4)'s vocabulary is itself the source of the error&lt;/strong&gt;, I find.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backed by Implementation: Cases Where I Used ReAct and Cases Where I Didn't
&lt;/h2&gt;

&lt;p&gt;To support the argument, here's the implementation experience from both quadrants.&lt;/p&gt;

&lt;h3&gt;
  
  
  A (4) Case Where I Used a ReAct Agent
&lt;/h3&gt;

&lt;p&gt;I once built a Copilot for a setting where a piece of software's official knowledge base was so vast that humans had a hard time finding what they needed. The Copilot received user questions and assembled the best answer while exploring the knowledge space.&lt;/p&gt;

&lt;p&gt;It worked startlingly well. The behavior looked exactly like a Deep Research-style exploratory agent — a mechanism that builds an answer through iterative search-tool calls. The implementation foundation was the ReAct pattern (Thought → Action [search-tool call] → Observation → Thought...) I learned from Coursera's prompt engineering course; I just placed the structure I encountered there into the context of knowledge exploration. The task "explore an unknown knowledge space and reach an answer" sits squarely in (4). What to search for next can't be decided in advance. The LLM had to look at the previous Observation and decide the next Action.&lt;/p&gt;

&lt;p&gt;The flip side of "too powerful" was a feeling of uncontrollability. While the loop runs toward its goal, there's no way to predict in advance what path the LLM will take through tool calls. Nor how many turns it'll take. When branches expanded mid-flight, I felt that the energy until goal-completion got close to runaway with no controls. Things that work, work — but operational predictability is low. I think this is the fundamental nature of (4). Bring that nature, in full, into business, and you collide head-on with the cost and accountability problems.&lt;/p&gt;

&lt;p&gt;So I know what ReAct agents can do. I know it, and I'm still saying that when you map it to business, (4) is limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  A (3) Case Where I Did Not Use a ReAct Agent
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;Contemplative Agent&lt;/a&gt; I publish openly sits on the opposite side. It uses no ReAct loop at all.&lt;/p&gt;

&lt;p&gt;Contemplative Agent generates output based on a given constitution, skills, rules, and identity. Its essence is a general-purpose structure that takes on arbitrary norms / roles / skill definitions. Each step of the generation pipeline is laid out in a predetermined order, and each step works as a single-purpose LLM function that returns a verdict in a defined schema for a defined input. The LLM output itself fluctuates probabilistically, but which step to execute and what to do next isn't decided by the LLM — the pipeline decides. In quadrant terms, it sits in (3) — semantic judgment × definable — batch form.&lt;/p&gt;

&lt;p&gt;There was no scene where I'd consider ReAct in CA. When operating CA, the only question is "by what standard, what kind of comment to issue." What to do next is decided in advance, so there's no room to run a ReAct loop. The distillation pipeline is the same — being processed via a different route every time would be a problem. The LLM judgments themselves fluctuate probabilistically, but the operational requirement is that "which step applies which judgment" stays fixed.&lt;/p&gt;

&lt;p&gt;So it wasn't even a choice of (4) vs (3). Given the nature of the work, only (3) could be chosen. The four-quadrant framework in this article is closer to a later linguistic articulation of this implementation given. I didn't have the framework first and then implement; I implemented and then found the framework was already there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separating the Domain of Application
&lt;/h3&gt;

&lt;p&gt;Use ReAct agents where ReAct agents should be used ((4)), and don't where they shouldn't ((3)). The argument here isn't a rejection from ignorance of ReAct; it's a desire to narrow the domain of application from a position of knowing it. The hole the current agent ecosystem keeps falling into is "bringing (4)'s tool into every quadrant" — not "ReAct agents themselves are bad."&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I noticed that when you start from ReAct agents while introducing AI into business, the choice of quadrant becomes invisible.&lt;/p&gt;

&lt;p&gt;Dissect the work first. For judgment work, a specialized chat agent ((3) conversational form) seems to suffice in many cases. For exception handling, single-purpose LLM functions + deterministic pipeline ((3) batch form) seems to cover it. For classical optimization, it's a problem for classical AI / OR ((2)) — not LLMs' stage. ReAct agents are needed only for exploratory tasks where the workflow can't be defined in advance ((4)).&lt;/p&gt;

&lt;p&gt;I find that most of the business work the current agent ecosystem targets sits in (3), not (4). Lining up my (4) implementation experience next to my (3) implementation experience didn't shake that impression.&lt;/p&gt;

&lt;p&gt;Where are ReAct agents actually needed in business? — Starting from this question, I came to feel the choice of architecture becomes visible. Conversely, skip the question and start from "do everything with agents," and you'll always end up at the category error of layering (4)'s architecture on top of (3) work.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and Related Links
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Primary technical sources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Yao et al., &lt;a href="https://arxiv.org/abs/2210.03629" rel="noopener noreferrer"&gt;"ReAct: Synergizing Reasoning and Acting in Language Models"&lt;/a&gt; (2022)&lt;/li&gt;
&lt;li&gt;Anthropic, &lt;a href="https://www.anthropic.com/engineering/building-effective-agents" rel="noopener noreferrer"&gt;"Building Effective Agents"&lt;/a&gt; (2024)&lt;/li&gt;
&lt;li&gt;OpenAI, &lt;a href="https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf" rel="noopener noreferrer"&gt;"A Practical Guide to Building Agents"&lt;/a&gt; (2025)&lt;/li&gt;
&lt;li&gt;Perplexity, &lt;a href="https://www.perplexity.ai/hub/blog/introducing-perplexity-deep-research" rel="noopener noreferrer"&gt;"Introducing Perplexity Deep Research"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenAI, &lt;a href="https://openai.com/index/introducing-deep-research/" rel="noopener noreferrer"&gt;"Introducing deep research"&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Industry critique and predictions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Thoughtworks, &lt;a href="https://www.thoughtworks.com/insights/blog/generative-ai/Agentwashing-and-how-AI-agents-fail-us" rel="noopener noreferrer"&gt;"The dangers of AI 'agentwashing'"&lt;/a&gt; (2025)&lt;/li&gt;
&lt;li&gt;Gartner, &lt;a href="https://www.gartner.com/en/newsroom/press-releases/2025-06-25-gartner-predicts-over-40-percent-of-agentic-ai-projects-will-be-canceled-by-end-of-2027" rel="noopener noreferrer"&gt;"Predicts Over 40% of Agentic AI Projects Will Be Canceled by End of 2027"&lt;/a&gt; (2025)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Related articles (trilogy)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://zenn.dev/shimo4228/articles/ai-agent-accountability-wall" rel="noopener noreferrer"&gt;A Sign on a Climbable Wall&lt;/a&gt; — where agent responsibility lies&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zenn.dev/shimo4228/articles/agent-blackbox-capitalism-timescale" rel="noopener noreferrer"&gt;The AI Agent Black Box Has Two Layers&lt;/a&gt; — the structure of unexplainability&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zenn.dev/shimo4228/articles/agent-causal-traceability-org-adoption" rel="noopener noreferrer"&gt;Can You Trace the Cause After an Incident?&lt;/a&gt; — the difficulty of causal traceback&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Related repositories
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;Contemplative Agent&lt;/a&gt; — the implementation matching (3) in this article. Deterministic pipeline structure that uses no ReAct loop&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/agent-attribution-practice" rel="noopener noreferrer"&gt;Agent Attribution Practice (AAP)&lt;/a&gt; — research repo on agent accountability and attribution&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Organic Growth and Content Integrity in an AI Writing Team</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Sat, 18 Apr 2026 00:00:03 +0000</pubDate>
      <link>https://dev.to/shimo4228/organic-growth-and-content-integrity-in-an-ai-writing-team-1h67</link>
      <guid>https://dev.to/shimo4228/organic-growth-and-content-integrity-in-an-ai-writing-team-1h67</guid>
      <description>&lt;p&gt;In a &lt;a href="https://zenn.dev/shimo4228/articles/claude-code-zenn-writing-env" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;, I wrote that "the environment gets a little smarter with each problem." Building a writing environment with Claude Code—turning problems into skills, scripts, and agents—was a fresh experience.&lt;/p&gt;

&lt;p&gt;Two months later, the cycle kept running. Agents grew to 5, skills to 11. I wrote 42 articles in that environment.&lt;/p&gt;

&lt;p&gt;Then I ran an audit and found 32 contradictions. The parts that were supposed to be smart were saying different things to each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The System That Grew
&lt;/h2&gt;

&lt;p&gt;Over 63 days, the &lt;code&gt;.claude/&lt;/code&gt; directory grew into this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/
├── agents/ (5)        # editor, essay-reviewer, fact-checker, zenn-drafter, devto-translator
├── skills/ (11)       # writing-team, zenn-writer, publish-article, schedule-publish, ...
├── refs/ (3)          # writing-standards, translation-rules, schedule-schema
└── rules/ (1)         # content-integrity

scripts/
├── publish.py          # Dev.to cross-post
├── scheduled_publish.py # Scheduled publishing
└── tests/ (8 files)    # 147 tests, 86% coverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When writing a single article, the system works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Writing&lt;/strong&gt;: The zenn-writer skill provides tone and style guidelines. The zenn-drafter agent can handle first drafts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review&lt;/strong&gt;: editor (structure, code quality) and essay-reviewer (logic, tone) evaluate the article from their respective angles. fact-checker verifies factual claims&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing&lt;/strong&gt;: The publish-article skill presents a pre-publication checklist, and schedule-publish determines posting timing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-posting&lt;/strong&gt;: The devto-translator agent translates the Japanese article into English and posts it to Dev.to. publish.py handles the API-level cross-posting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each component carries its own set of rules. zenn-writer has a title character limit. editor has a banned list for AI slop (hollow boilerplate phrases). devto-translator has translation style rules. Each one embeds "the best judgment for its own scope."&lt;/p&gt;

&lt;p&gt;None of this was planned from the start. It accumulated through cycles of writing articles, hitting problems, and systematizing solutions. The growth pattern I described in the previous article kept going for two straight months.&lt;/p&gt;

&lt;h2&gt;
  
  
  32 Contradictions Found at Once
&lt;/h2&gt;

&lt;p&gt;It started with a casual thought: "I should reorganize the writing team." Before building a new orchestrator, I wanted to understand the current state, so I used Claude Code's sub-agent feature to run three audits in parallel: style/tone audit, translation/publishing flow audit, and gap analysis.&lt;/p&gt;

&lt;p&gt;The results were unexpected. 32 problems surfaced at once.&lt;/p&gt;

&lt;p&gt;Take the title character limit. zenn-writer said "50 characters max," zenn-drafter said "60 characters max," and zenn-format said "50-60 characters." Three components, each saying something slightly different.&lt;/p&gt;

&lt;p&gt;The AI slop banned list was worse. editor, zenn-drafter, and zenn-writer each had their own slightly different copy. One list banned "画期的" (groundbreaking) while another didn't include it at all.&lt;/p&gt;

&lt;p&gt;Three components claimed ownership of translation: the translate-article skill, the devto-translator agent, and the publish-article skill. The most telling case was translate-article—its own description said "for end-to-end workflows, devto-translator agent is recommended." It was negating its own reason to exist.&lt;/p&gt;

&lt;p&gt;Why does this happen? Incremental construction produces local optima. Each component is optimized for "the context at the time it was created." A skill built in February reflects February's judgment; an agent added in March reflects March's knowledge. But no mechanism existed to guarantee overall consistency. The same structure as "technical debt" in software development had emerged in the knowledge layer of AI agents.&lt;/p&gt;

&lt;p&gt;Here are the audit results in numbers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before (pre-audit)&lt;/th&gt;
&lt;th&gt;After (redesign)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Contradicting rules&lt;/td&gt;
&lt;td&gt;12 (char limits, AI slop lists, tone rules, etc.)&lt;/td&gt;
&lt;td&gt;0 (consolidated into refs/)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicated rule locations&lt;/td&gt;
&lt;td&gt;8 (AI slop copy-pasted in 3 places, etc.)&lt;/td&gt;
&lt;td&gt;1 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Components with ambiguous ownership&lt;/td&gt;
&lt;td&gt;4 (3 claiming translation, etc.)&lt;/td&gt;
&lt;td&gt;1 owner each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared references (refs/)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3 (writing-standards, translation-rules, schedule-schema)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADRs (Architecture Decision Records)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2 (Content Integrity, Orchestration)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Of the 32 problems, 12 contradictions, 8 duplications, and 4 ownership ambiguities formed the core. The rest were derivative inconsistencies stemming from these.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Tool's Existence Creates Bias
&lt;/h2&gt;

&lt;p&gt;Among the 32 issues, the one that made me think the most was the catchify skill.&lt;/p&gt;

&lt;p&gt;catchify was a skill that rewrote article openings to be more dramatic and headings to be more emotional. I built it in February as "a tool to make things catchy" and actually used it on several articles.&lt;/p&gt;

&lt;p&gt;The problem was that merely having this tool created pressure to use it. After finishing an article honestly, not running it through catchify felt like cutting corners. The tool's existence itself was biasing the author's judgment.&lt;/p&gt;

&lt;p&gt;This isn't just a software problem—it applies to organizations and workflows too. Introduce a code review tool and suddenly every PR "needs" a review. Add a step to the CI pipeline and removing that step meets resistance. Tools don't just "add options"—they raise the cost of choosing not to use them.&lt;/p&gt;

&lt;p&gt;I abolished catchify. No tool, no bias.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content Integrity — A Principle That Resolved Contradictions
&lt;/h2&gt;

&lt;p&gt;Abolishing catchify was treating a symptom. What I needed was a criterion for "what's okay to automate."&lt;/p&gt;

&lt;p&gt;That's where the Content Integrity principle was born. The trigger was a feeling: "I want to put my thoughts out honestly." But I didn't want to reject SEO optimization entirely. Choosing better words for titles and optimizing tags increases the chance readers find the article without changing its content. That seemed reasonable.&lt;/p&gt;

&lt;p&gt;The problem was optimization that changes the content itself. Rewriting the opening "for search snippets." Making headings "emotional." These are processing the author's thinking for the sake of distribution.&lt;/p&gt;

&lt;p&gt;From here, the Content / Distribution boundary became clear:&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;Examples&lt;/th&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Structure, argument, opening, headings&lt;/td&gt;
&lt;td&gt;Follow the author's thinking. Don't change for optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Title word choice, tags, emoji, posting timing&lt;/td&gt;
&lt;td&gt;Optimize without changing content&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I recorded this principle as an ADR (Architecture Decision Record) and set it up as a rule file that loads automatically every session.&lt;/p&gt;

&lt;p&gt;As a result, catchify was abolished. seo-optimizer had its opening rewrite feature removed, limited to title, tags, and emoji only. schedule-publish's scoring axis was renamed from "Search Magnet" to "Discoverability (can interested readers find it?)."&lt;/p&gt;

&lt;p&gt;Most of the 32 contradictions became clear-cut decisions when held against this principle. Instead of individually squashing them through refactoring, the principle provided a decision framework that enabled consistent redesign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structural Patterns for Maintaining Coherence
&lt;/h2&gt;

&lt;p&gt;A principle alone can't prevent contradictions from recurring. The structure needed to change too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;refs/ consolidation&lt;/strong&gt; — AI slop lists, tone rules, translation rules, and schedule schemas were consolidated into single locations (&lt;code&gt;.claude/refs/&lt;/code&gt;), with each component holding only reference pointers. The AI slop list that was copy-pasted in 3 places became 1 source of truth + 3 references. Update the source and everything follows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ADR-first&lt;/strong&gt; — Record decisions before changing the system. For Content Integrity, I first wrote ADR-0001 with the reasoning and impact scope, then proceeded to abolish catchify and modify seo-optimizer. If the reasoning disappears, six months later no one knows "why catchify doesn't exist."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single ownership per concern&lt;/strong&gt; — Translation belongs to devto-translator only. SEO belongs to seo-optimizer only. One concern, one owner. A component like translate-article that "negates its own existence" is a sign of overlapping responsibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interruptions That Improved the Design
&lt;/h2&gt;

&lt;p&gt;What was interesting was the redesign process itself.&lt;/p&gt;

&lt;p&gt;The redesign happened through dialogue with Claude Code. I communicated the direction, and Claude Code planned and executed. It started with a plan to "build an orchestrator," but before implementation began, I interrupted three times.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If the components contradict or duplicate each other, it won't be organic, will it?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without this, I would have layered an orchestrator on top of existing contradictions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Shouldn't we write ADRs first?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without this, the reasoning behind decisions would have been lost.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"SEO itself is fine. It's changing the content that's the problem."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without this, I might have abolished SEO optimization entirely.&lt;/p&gt;

&lt;p&gt;There's a lot of attention on having AI agents plan and execute autonomously. But in this case at least, human interruptions improved the design quality. Autonomous execution is efficient, but reassessing premises comes from outside.&lt;/p&gt;

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

&lt;p&gt;The previous article concluded that "the environment gets a little smarter with each problem."&lt;/p&gt;

&lt;p&gt;Two months later, I realized that smart parts contradict each other. Components optimized incrementally don't maintain coherence as a whole. This isn't limited to AI agent knowledge layers—I believe it's a fate shared by every organically growing system.&lt;/p&gt;

&lt;p&gt;And what resolved those contradictions wasn't individual refactoring, but a principle called Content Integrity. "Content is determined by the author's thinking. Distribution optimizes without changing content." This single statement became the criterion for deciding which of the 32 contradictions to keep and which to abolish.&lt;/p&gt;

&lt;p&gt;Organic growth requires periodic audits and a principle to anchor decisions.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>claudecode</category>
      <category>writing</category>
    </item>
    <item>
      <title>Building Zed as an Observation Window for Claude Code — Japanese Typography with IBM Plex</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Thu, 16 Apr 2026 00:00:04 +0000</pubDate>
      <link>https://dev.to/shimo4228/building-zed-as-an-observation-window-for-claude-code-japanese-typography-with-ibm-plex-6l9</link>
      <guid>https://dev.to/shimo4228/building-zed-as-an-observation-window-for-claude-code-japanese-typography-with-ibm-plex-6l9</guid>
      <description>&lt;h1&gt;
  
  
  Making Zed an Observation Window: A Design Record of Fonts and Cognitive Resources
&lt;/h1&gt;

&lt;p&gt;In &lt;a href="https://zenn.dev/shimo4228/articles/cursor-to-zed-migration" rel="noopener noreferrer"&gt;the previous article&lt;/a&gt;, I wrote about migrating from Cursor to Zed. The gist: Cursor felt like a heavy container for lightweight content, so I switched to Zed and settled on a development workflow centered around the Claude Code CLI.&lt;/p&gt;

&lt;p&gt;Two months later. Nothing has gone wrong with Zed.&lt;/p&gt;

&lt;p&gt;Nothing wrong, but three things kept nagging at me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Opening a file somehow changes its formatting&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The left dock is cluttered with panels I never use&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Japanese fonts have an unnameable wrongness to them&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article documents fixing all three in a single day. But it is not just a settings walkthrough. Tracing the "why" behind each setting led to &lt;strong&gt;three design principles&lt;/strong&gt; and an &lt;strong&gt;unexpected rediscovery&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lqqbe7xftft8ec8zo05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lqqbe7xftft8ec8zo05.png" alt="Before: Zed initial state — SF Mono + unorganized dock" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Before: Zed at session start. SF Mono, unorganized dock, stock UI.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Defining the Role: Observation Window
&lt;/h2&gt;

&lt;p&gt;First, the premise. I develop with the Claude Code CLI. Writing code, running tests, git operations — all handled in the terminal by Claude Code.&lt;/p&gt;

&lt;p&gt;So what is Zed doing?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zed is an observation window.&lt;/strong&gt; A window where I pull information that the CLI pushes — file changes, test results, commit logs — to review it as a human. Not a tool for writing. A tool for reading.&lt;/p&gt;

&lt;p&gt;Once you recognize this role, the requirements for an editor shift.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;As a writing tool&lt;/th&gt;
&lt;th&gt;As an observation window&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code completion&lt;/td&gt;
&lt;td&gt;Essential&lt;/td&gt;
&lt;td&gt;Unnecessary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formatter&lt;/td&gt;
&lt;td&gt;Essential&lt;/td&gt;
&lt;td&gt;Gets in the way (CLI handles it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugger&lt;/td&gt;
&lt;td&gt;Essential&lt;/td&gt;
&lt;td&gt;Unnecessary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File tree&lt;/td&gt;
&lt;td&gt;Essential&lt;/td&gt;
&lt;td&gt;Essential (locating changes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git diff view&lt;/td&gt;
&lt;td&gt;Nice to have&lt;/td&gt;
&lt;td&gt;Essential (seeing what changed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Font quality&lt;/td&gt;
&lt;td&gt;Nice to have&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Essential&lt;/strong&gt; (reading for long periods)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The priorities for "writing" and "reading" are entirely different. With this premise, I worked through the three nagging issues in order.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cutting Dual Control — format_on_save: off
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Symptom
&lt;/h3&gt;

&lt;p&gt;"Opening a file somehow changes the formatting."&lt;/p&gt;

&lt;p&gt;At first I thought I was imagining it. But every time I opened a file, indentation shifted subtly. Diffs appeared. Code written by Claude Code produced diffs just from being opened.&lt;/p&gt;
&lt;h3&gt;
  
  
  Diagnosis
&lt;/h3&gt;

&lt;p&gt;The cause was &lt;strong&gt;dual formatting&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude Code's PostToolUse hook formats with &lt;code&gt;black&lt;/code&gt; / &lt;code&gt;ruff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Zed's &lt;code&gt;autosave: on_focus_change&lt;/code&gt; + &lt;code&gt;format_on_save: on&lt;/code&gt; reformats via Zed's LSP formatter&lt;/li&gt;
&lt;li&gt;The two formatters had slightly different rule configurations, producing diffs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In other words, &lt;strong&gt;two formatters were alternately rewriting the same file under different rules&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fix
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Claude hooks own formatting, so turn this off&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"format_on_save"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"off"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;One line. In &lt;a href="https://zenn.dev/shimo4228/articles/cursor-to-zed-migration" rel="noopener noreferrer"&gt;the previous article&lt;/a&gt;, I actually had &lt;code&gt;format_on_save: on&lt;/code&gt;. Right after the migration, Claude Code's hook system was not fully set up yet, so having Zed handle formatting made sense. But once PostToolUse hooks with &lt;code&gt;black&lt;/code&gt; / &lt;code&gt;ruff&lt;/code&gt; were in full operation, dual formatting became a problem. When the environment changes, settings change with it.&lt;/p&gt;

&lt;p&gt;This single line contains a principle important for observation windows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Principle 1: Prioritize the primary channel; do not replicate in the secondary.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the Claude Code CLI is the primary channel carrying information, Zed (secondary) should not duplicate the same function. Formatting responsibility is consolidated in the CLI. Duplicating information does not improve observability — it wastes cognitive resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1amtuyzbk4t0t1bp8qr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1amtuyzbk4t0t1bp8qr.png" alt="Settings editing — adjusting format_on_save and dock" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The editing process. Working through settings.json in conversation.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Trimming Visual Noise — The button: false Approach
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Left Dock Problem
&lt;/h3&gt;

&lt;p&gt;Before cleanup, the left dock had Terminal, Agent Panel, Debugger, Outline, and Git — panels I never use. As an observation window, I only use Terminal, yet icons for everything else stay in view.&lt;/p&gt;

&lt;p&gt;Unused things in your field of vision are noise.&lt;/p&gt;
&lt;h3&gt;
  
  
  button: false as a Solution
&lt;/h3&gt;

&lt;p&gt;Zed has a &lt;code&gt;button: false&lt;/code&gt; setting. It &lt;strong&gt;hides just the button (icon) while keeping the feature alive&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Hide buttons for unused panels without killing functionality&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"debugger"&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;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"agent"&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;"enabled"&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;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"outline_panel"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"collaboration_panel"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"diagnostics"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"notification_panel"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"search"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could use &lt;code&gt;enabled: false&lt;/code&gt; to kill the feature entirely, but I deliberately did not. The Agent Panel may be needed for ACP (Agent Control Protocol) integration. &lt;strong&gt;Do not touch the function; touch the visuals.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Deprecated Key Trap
&lt;/h3&gt;

&lt;p&gt;During this work, Zed warned: "Your settings file uses deprecated settings."&lt;/p&gt;

&lt;p&gt;Two causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;collab_panel&lt;/code&gt; — correct key is &lt;code&gt;collaboration_panel&lt;/code&gt; (renamed)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chat_panel&lt;/code&gt; — no longer exists as an independent panel (merged into collaboration)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Old keys still work but produce persistent warnings. I updated to the canonical key names.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Notifications Connect Misconception
&lt;/h3&gt;

&lt;p&gt;The right dock's Notifications panel had a "Connect" button. I expected it to show GitHub PR reviews, CI lint errors, deploy failures — all within Zed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh39clgx05pmffwh4qgqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh39clgx05pmffwh4qgqb.png" alt="Right-side Notifications panel with Connect button" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;"Connect to view notifications." — I assumed GitHub integration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reality was different.&lt;/strong&gt; Checking Zed's official documentation, this "Connect" is for &lt;strong&gt;Zed's own collaboration feature&lt;/strong&gt; (Zed Channels). It uses GitHub OAuth but the scope is &lt;code&gt;read:user&lt;/code&gt; only — no repository access whatsoever.&lt;/p&gt;

&lt;p&gt;There is no official Zed feature for integrating GitHub repository notifications.&lt;/p&gt;

&lt;p&gt;I did not connect. The expected feature was absent, and the available feature (collaboration) was one I would not use. Zero value on both sides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson: Do not infer functionality from a UI label alone ("Connect").&lt;/strong&gt; Especially for connections involving authentication, verify what you are actually connecting to before clicking.&lt;/p&gt;
&lt;h3&gt;
  
  
  The "Guessed Value That Did Not Work" Incident
&lt;/h3&gt;

&lt;p&gt;Wanting to empty the status bar, I wrote &lt;code&gt;active_encoding_button&lt;/code&gt; as &lt;code&gt;"never"&lt;/code&gt; — thinking of it like CSS &lt;code&gt;display: none&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Invalid user settings file:&lt;/strong&gt; unknown variant 'never', expected one of 'enabled', 'disabled', 'non_utf8'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zed's settings file uses &lt;strong&gt;type-safe JSONC with schema validation&lt;/strong&gt;. Invalid values do not fail silently — they return an immediate error. Better yet, the error message lists the valid values.&lt;/p&gt;

&lt;p&gt;The same class of mistake happened three times during this session:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;collab_panel&lt;/code&gt; (deprecated; correct: &lt;code&gt;collaboration_panel&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;font-moralerspace-nf&lt;/code&gt; (discontinued; correct: &lt;code&gt;font-moralerspace&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"never"&lt;/code&gt; (does not exist; correct: &lt;code&gt;"disabled"&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The common pattern: &lt;strong&gt;guessing a plausible-sounding name&lt;/strong&gt;. Verify before guessing. Settings values come from official sources, not intuition.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Decision to Keep LSP
&lt;/h3&gt;

&lt;p&gt;For an observation window, the core features of Language Servers (Pyright, tsserver, etc.) — autocomplete, hover, diagnostics — go entirely unused. Why not turn them off?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykhwya5niylerrkbt69a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykhwya5niylerrkbt69a.png" alt="LSP diagnostics panel showing empty state" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;"No problems in workspace" — LSP is running but has nothing to say.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Conclusion: &lt;strong&gt;Keep them.&lt;/strong&gt; Three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On Apple Silicon with ample memory, the perceived overhead from LSP is near zero&lt;/li&gt;
&lt;li&gt;JSON schema hints (completions when editing settings.json) turned out to be surprisingly useful — proven during this very session&lt;/li&gt;
&lt;li&gt;Switching cost (adding config + losing features) &amp;gt; cognitive resources saved (nearly zero)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;"Could be removed" and "should be removed" are different judgments.&lt;/strong&gt; If there is no actual harm to cognitive resources, leaving things alone is also a form of optimization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Principle 2: Do not touch the function; touch the visuals (hide, don't delete).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hide unused features visually with &lt;code&gt;button: false&lt;/code&gt;. Killing features risks side effects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle 3: Trim visible noise; tolerate invisible background processes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dock icons and status bar items consume cognitive resources, so trim them. Background processes like LSP stay out of sight, so tolerate them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The Long Font Journey — From SF Mono to PlemolJP Console NF
&lt;/h2&gt;

&lt;p&gt;Here is where the real story begins. Of the three nagging issues, fonts consumed the most time.&lt;/p&gt;
&lt;h3&gt;
  
  
  SF Mono Has No Japanese Glyphs
&lt;/h3&gt;

&lt;p&gt;I was using SF Mono as the default (technically macOS's default). Japanese "just appeared." But &lt;strong&gt;SF Mono contains only Latin characters&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So where was the Japanese coming from?&lt;/p&gt;

&lt;p&gt;The answer was &lt;strong&gt;CJK fallback&lt;/strong&gt;. macOS's font rendering detected that SF Mono lacked Japanese glyphs and drew them using system fallback fonts like Hiragino Sans or PingFang SC.&lt;/p&gt;

&lt;p&gt;The problem was metrics. The fallback font's baseline, character width, and line spacing were subtly misaligned with SF Mono, producing a &lt;strong&gt;"something feels off" jitteriness&lt;/strong&gt;. Hard to articulate, but definitely there.&lt;/p&gt;

&lt;p&gt;The solution was clear: a &lt;strong&gt;CJK-unified font&lt;/strong&gt; — one where Latin and Japanese glyphs coexist in the same font file with metrics unified from the start.&lt;/p&gt;
&lt;h3&gt;
  
  
  Moralerspace Argon: Too Bold
&lt;/h3&gt;

&lt;p&gt;The first candidate was &lt;a href="https://github.com/yuru7/moralerspace" rel="noopener noreferrer"&gt;Moralerspace&lt;/a&gt;. A CJK-unified font by the same author as UDEV Gothic (yuru7), synthesizing Monaspace + IBM Plex Sans JP. I chose the Argon variant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; font-moralerspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;font-moralerspace-nf&lt;/code&gt; (the Nerd Font-only cask) was discontinued on 2025-07-29. Nerd Fonts are shifting from "patched font files" to a "symbols overlay" approach, and the base &lt;code&gt;font-moralerspace&lt;/code&gt; is the successor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Result: &lt;strong&gt;It felt bold.&lt;/strong&gt; Even at Regular weight, the strokes had too much presence. Modern and refined design, but for an observation window meant for long reading sessions, I wanted something more restrained.&lt;/p&gt;

&lt;h3&gt;
  
  
  PlemolJP Console NF: Light Was Too Thin, Regular Landed
&lt;/h3&gt;

&lt;p&gt;Next up was &lt;a href="https://github.com/yuru7/PlemolJP" rel="noopener noreferrer"&gt;PlemolJP&lt;/a&gt;. A CJK-unified font synthesizing IBM Plex Mono + IBM Plex Sans JP. I chose the Console NF variant (monospace + Nerd Font symbols).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; font-plemol-jp-nf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First I tried Light (weight 300). &lt;strong&gt;Too thin.&lt;/strong&gt; Characters dissolved into the background, requiring subtle effort to read.&lt;/p&gt;

&lt;p&gt;Regular (weight 400). &lt;strong&gt;Landed.&lt;/strong&gt; Classic strokes inherited from Plex Mono — less assertive than Moralerspace, more present than Light. The sweet spot.&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting the Exact Font Family Name
&lt;/h4&gt;

&lt;p&gt;Right after &lt;code&gt;brew install&lt;/code&gt;, I tried to write the font name in Zed's settings.json. &lt;strong&gt;The exact family name was unclear.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If macOS's Spotlight index has not updated, &lt;code&gt;mdls&lt;/code&gt; returns empty. The reliable method is &lt;code&gt;system_profiler&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;system_profiler SPFontsDataType 2&amp;gt;/dev/null | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; 1 &lt;span class="nt"&gt;-A&lt;/span&gt; 4 &lt;span class="s2"&gt;"PlemolJPConsoleNF-Regular:"&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;

&lt;span class="c"&gt;# Result:&lt;/span&gt;
&lt;span class="c"&gt;#   Full Name: PlemolJP Console NF Regular&lt;/span&gt;
&lt;span class="c"&gt;#   Family: PlemolJP Console NF&lt;/span&gt;
&lt;span class="c"&gt;#   Style: レギュラー&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Family: PlemolJP Console NF&lt;/code&gt; — this is the value for settings.json.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unifying All Layers Failed: The Pain of Reading Prose in Monospace
&lt;/h3&gt;

&lt;p&gt;With PlemolJP Console NF, the Buffer and Terminal felt great. Riding that momentum, I &lt;strong&gt;applied the same font to the UI&lt;/strong&gt;. All layers unified — beautiful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz48tu0417ba9k503iri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz48tu0417ba9k503iri.png" alt="UI with PlemolJP showing prose monospace problem" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The monospace-UI failure. Japanese prose forced into a grid feels wrong.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Something was off.&lt;/strong&gt; Panel labels, Insight block text, Japanese segments in file paths — they all looked like "a sequence of square boxes."&lt;/p&gt;

&lt;p&gt;Thinking about the cause, it clicked. &lt;strong&gt;Monospace fonts assume a fixed-width grid.&lt;/strong&gt; ASCII characters look natural aligned to a grid, but Japanese prose is naturally read in proportional spacing (varying width per character).&lt;/p&gt;

&lt;p&gt;This connects to the history of type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monospace&lt;/strong&gt;: Originated from typewriters. Each physical type slug had to be the same width or the carriage would not advance. Code culture adopted the grid as standard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proportional&lt;/strong&gt;: Since movable type printing, prose has been set in proportional spacing. Varying character widths create a smoother reading flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UI is primarily prose-like labels. Applying monospace to prose was like typesetting a novel on a typewriter.&lt;/p&gt;
&lt;h3&gt;
  
  
  IBM Plex Sans JP: Returning Just the UI to Proportional
&lt;/h3&gt;

&lt;p&gt;Revert the UI to proportional. But instead of reverting to the system default, I chose from &lt;strong&gt;within the same IBM Plex family as PlemolJP&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; font-ibm-plex-sans-jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IBM Plex Sans JP is the Japanese extension of IBM Plex Sans — PlemolJP's "proportional sibling." The design language is unified, so there is no jarring disconnect between Buffer (monospace) and UI (proportional).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;// UI: proportional (suited for prose)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ui_font_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IBM Plex Sans JP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ui_font_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;16.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;"ui_font_weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;// Buffer: monospace (suited for code)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buffer_font_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PlemolJP Console NF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buffer_font_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;15.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;"buffer_font_weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;// Terminal: monospace (suited for CLI output)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"terminal"&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;"font_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PlemolJP Console NF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"font_weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"font_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"line_height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comfortable"&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;Each of the three layers gets the appropriate font type.&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;Purpose&lt;/th&gt;
&lt;th&gt;Font Type&lt;/th&gt;
&lt;th&gt;Font&lt;/th&gt;
&lt;th&gt;Size&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;Panel labels, menus&lt;/td&gt;
&lt;td&gt;Proportional&lt;/td&gt;
&lt;td&gt;IBM Plex Sans JP&lt;/td&gt;
&lt;td&gt;16pt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buffer&lt;/td&gt;
&lt;td&gt;Code display&lt;/td&gt;
&lt;td&gt;Monospace&lt;/td&gt;
&lt;td&gt;PlemolJP Console NF&lt;/td&gt;
&lt;td&gt;15pt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal&lt;/td&gt;
&lt;td&gt;CLI output&lt;/td&gt;
&lt;td&gt;Monospace&lt;/td&gt;
&lt;td&gt;PlemolJP Console NF&lt;/td&gt;
&lt;td&gt;14pt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Buffer is for "reading"; Terminal is for "scanning." Font size steps down by 1pt according to information density.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rediscovery — Zed's Default Was IBM Plex All Along
&lt;/h2&gt;

&lt;p&gt;I was satisfied with the setup when I idly looked up Zed's default font.&lt;/p&gt;

&lt;p&gt;Zed uses aliases called &lt;code&gt;.ZedSans&lt;/code&gt; and &lt;code&gt;.ZedMono&lt;/code&gt;. Their underlying fonts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.ZedSans&lt;/code&gt;&lt;/strong&gt; = &lt;strong&gt;IBM Plex Sans&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.ZedMono&lt;/code&gt;&lt;/strong&gt; = &lt;strong&gt;Lilex&lt;/strong&gt; (a fork of IBM Plex Mono with ligatures)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zed's default font is the &lt;strong&gt;IBM Plex family&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In other words, what happened was this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SF Mono -&amp;gt; Moralerspace (did not fit) -&amp;gt; landed on PlemolJP (IBM Plex Mono-based) -&amp;gt; applied IBM Plex Sans JP to UI -&amp;gt; ended up building a Japanese-optimized version of Zed's own defaults&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Arriving independently at the IBM Plex family was not a coincidence. The Zed development team chose IBM Plex too. More accurately, I naturally arrived at this point along the extension of Zed's design philosophy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frane66bp3vpeyzst8i1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frane66bp3vpeyzst8i1v.png" alt="Zed final UI — IBM Plex Sans JP + PlemolJP Console NF" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After: Left dock is Terminal only, Buffer uses PlemolJP Console NF, UI uses IBM Plex Sans JP. File tree on the right dock.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing — settings.json Is a Record of Design Decisions
&lt;/h2&gt;

&lt;p&gt;Today's work produced a 140-line settings.json. Each item maps to one of the three principles.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Corresponding Settings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary channel first&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;format_on_save: "off"&lt;/code&gt;, &lt;code&gt;edit_predictions.provider: "none"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Do not touch the function; touch the visuals&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Various &lt;code&gt;button: false&lt;/code&gt;, &lt;code&gt;agent.enabled: true&lt;/code&gt; (kept alive but hidden)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trim visible noise; tolerate invisible background&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All &lt;code&gt;status_bar&lt;/code&gt; items off, &lt;code&gt;show_whitespaces: "none"&lt;/code&gt;, LSP retained&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This settings.json is not a list of preferences. &lt;strong&gt;It is a record of design decisions for protecting cognitive resources.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Changing" and "optimizing" are different things. Understanding Zed's default design, then adapting it to my usage pattern (observation window) and environment (Japanese mixed content). Not breaking it — localizing it.&lt;/p&gt;

&lt;p&gt;In the previous article, I wrote "I switched from Cursor to Zed." Now I can say it more precisely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I built Zed as an observation window for Claude Code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Full settings.json&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&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;"diagnostics"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"calls"&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;"share_on_join"&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;"mute_on_join"&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="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;"notification_panel"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"pane_split_direction_vertical"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"active_pane_modifiers"&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;"inactive_opacity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"use_system_window_tabs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bottom_dock_layout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contained"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tabs"&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;"file_icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"git_status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"tab_bar"&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;"show_pinned_tabs_in_separate_row"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"show_nav_history_buttons"&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;"show"&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="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;"title_bar"&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;"show_user_picture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"show_sign_in"&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;"show_project_items"&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;"show_branch_name"&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="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;"status_bar"&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;"active_encoding_button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"disabled"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"show_active_file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"active_language_button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cursor_position_button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"search"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"agent_servers"&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;"claude-acp"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"registry"&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;"debugger"&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;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"icon_theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Zed (Default)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"edit_predictions"&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;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&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;"agent"&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;"enabled"&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;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&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;"session"&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;"trust_all_worktrees"&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="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;"theme"&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;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"system"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"light"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tokyo Night Light"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dark"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tokyo Night"&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;"vim_mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"soft_wrap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editor_width"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui_font_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IBM Plex Sans JP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui_font_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;16.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;"ui_font_weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"buffer_font_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PlemolJP Console NF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"buffer_font_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;15.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;"buffer_font_weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"autosave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"on_focus_change"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"show_whitespaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"terminal"&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;"flexible"&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;"show_count_badge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"font_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PlemolJP Console NF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"font_weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"font_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"line_height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comfortable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"working_directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"current_project_directory"&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;"tab_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&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_on_save"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"off"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"indent_guides"&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;"enabled"&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;"coloring"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"indent_aware"&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;"inlay_hints"&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;"enabled"&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="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;"scrollbar"&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;"show"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auto"&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;"git"&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;"disable_git"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"inline_blame"&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;"enabled"&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="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;"project_panel"&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;"file_icons"&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;"hide_gitignore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hide_root"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"git_status_indicator"&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;"bold_folder_labels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entry_spacing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comfortable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"button"&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;"auto_reveal_entries"&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;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"right"&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;"git_panel"&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;"show_count_badge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tree_view"&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;"file_icons"&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;"dock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"right"&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;"outline_panel"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"collaboration_panel"&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;"button"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;"languages"&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;"Swift"&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;"tab_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&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;"JSON"&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;"tab_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"soft_wrap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editor_width"&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;"Python"&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;"tab_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Font installation commands&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Buffer / Terminal (IBM Plex Mono + IBM Plex Sans JP synthesis)&lt;/span&gt;
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; font-plemol-jp-nf

&lt;span class="c"&gt;# UI (proportional, Japanese support)&lt;/span&gt;
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; font-ibm-plex-sans-jp

&lt;span class="c"&gt;# Reliable way to get the exact font family name&lt;/span&gt;
system_profiler SPFontsDataType 2&amp;amp;gt&lt;span class="p"&gt;;&lt;/span&gt;/dev/null | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; 1 &lt;span class="nt"&gt;-A&lt;/span&gt; 4 &lt;span class="s2"&gt;"PlemolJPConsoleNF-Regular:"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>zed</category>
      <category>ai</category>
      <category>font</category>
      <category>typography</category>
    </item>
    <item>
      <title>AI Agent Black Boxes Have Two Layers — Technical Limits and Business Incentives</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Mon, 13 Apr 2026 00:00:03 +0000</pubDate>
      <link>https://dev.to/shimo4228/ai-agent-black-boxes-have-two-layers-technical-limits-and-business-incentives-jhi</link>
      <guid>https://dev.to/shimo4228/ai-agent-black-boxes-have-two-layers-technical-limits-and-business-incentives-jhi</guid>
      <description>&lt;h2&gt;
  
  
  It started as just a prompt
&lt;/h2&gt;

&lt;p&gt;Remember Chain-of-Thought (CoT)? Adding "Let's think step by step" to a prompt improved LLM reasoning accuracy. It was one of the early prompt engineering discoveries. CoT lived outside the model. It was just a string.&lt;/p&gt;

&lt;p&gt;Not anymore. CoT became the conceptual ancestor of today's reasoning models — GPT-5, Claude's extended thinking, Gemini's thinking mode, among others. These models acquired reasoning capabilities during training through reinforcement learning. The reasoning process moved inside. Some models, like Claude's extended thinking, make the process partially visible. But in most cases, the details are hidden from the outside.&lt;/p&gt;

&lt;p&gt;Research from Wharton GAIL found that applying the original CoT prompting to reasoning models had almost no effect — and in some cases introduced redundancy that hurt performance. What was once external became internal, and injecting the same pattern from outside no longer worked.&lt;/p&gt;

&lt;p&gt;A terminological note. In AI safety discourse, structures built around an LLM without modifying its weights are called &lt;em&gt;scaffolding&lt;/em&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. System prompts, tool definitions, RAG pipelines, agent loops — all of these fall under scaffolding.&lt;/p&gt;

&lt;p&gt;The black box in AI agents has two distinct &lt;strong&gt;causes&lt;/strong&gt; of invisibility. Technical limits and business incentives. These two are different in nature, so the responses to each must also differ.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;■ Layer 1: Model Internals (weights) — Technically opaque
  Examples: Language ability, commonsense reasoning, ethical judgment, CoT (post-internalization)
  Why invisible: Dissolved into weights; fundamentally non-extractable

■ Layer 2: Scaffolding — Technically visible, commercially hidden
  Umbrella term for human-constructed components outside the model[^1]
  Why invisible: Source of competitive advantage; no incentive to disclose

  Examples: system prompts, persona definitions, tool definitions, RAG,
      agent loops, safety gates, session management,
      harness (runtime control layer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Academically, there have been attempts to distinguish scaffolding (build-time) from harness (runtime), but this boundary is rapidly blurring. Persistent memory, skill ecosystems. Model-agnostic agent foundations like OpenClaw run interchangeably on Claude, GPT, or local models. Anthropic blocked usage via subscription access, but the dynamic where scaffolding commoditizes models isn't stopping. The scope of scaffolding keeps expanding alongside the surge in agent development. In this article, I use scaffolding in the broad sense that includes harness.&lt;/p&gt;

&lt;p&gt;From my experience running my own agents: when scaffolding is properly context-managed, the model is just an inference engine, and the essence of the agent lives in the scaffolding. Personality, capabilities, decision criteria — all of it resides in the scaffolding. Swap the model and keep the scaffolding, and the agent behaves the same way. I once wrote that "&lt;a href="https://zenn.dev/shimo4228/articles/agent-essence-is-memory" rel="noopener noreferrer"&gt;the essence of an agent might be memory&lt;/a&gt;." The three layers I described in that article — EpisodeLog, KnowledgeStore, and Identity — are all scaffolding in current terminology. I didn't have this distinction at the time, but gaining the concept of scaffolding let me explain that intuition structurally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaffolding is technically visible, yet in practice invisible.&lt;/strong&gt; Where this gap comes from is the subject of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two-layer structure of the black box
&lt;/h2&gt;

&lt;p&gt;From building agents from scratch, I've come to see that the black box has two distinct layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: Model Internals — Internalization through training&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ethics, worldview, reasoning patterns. These are dissolved into the weights through pre-training and reinforcement learning. At first glance, this seems like a technical inevitability. But personally, I suspect the scope of this "internalization" is less inevitable than commonly assumed.&lt;/p&gt;

&lt;p&gt;CoT is the clearest example. CoT originally lived outside the model. It was internalized to achieve performance gains that external prompting couldn't deliver — self-correction, backtracking, scaling of inference-time compute. A performance-first design decision to internalize despite the enormous cost. It wasn't technically inevitable; it was a choice that involved trade-offs with visibility.&lt;/p&gt;

&lt;p&gt;Of course, not everything can be externalized. Tacit knowledge acquired through large-scale pre-training is structurally difficult to externalize. In my own agents, scaffolding elements like identity, professional ethics, skills, and decision logs could all be represented as files. Meanwhile, the language abilities and commonsense reasoning the model acquired through pre-training couldn't be externalized at all. The line between "what's inevitable" and "what's a matter of convenience" — at least in my experience — aligns with the boundary between scaffolding and model internals. Yet this line remains undrawn in current discourse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: Scaffolding — Technically visible, but kept hidden&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Outside the model lies another layer. System prompts, persona settings, rules, tool definitions — scaffolding. This layer is technically inspectable. Store it in files, manage it with git, and you can track every change.&lt;/p&gt;

&lt;p&gt;But in most cases, it's kept hidden. The reason is the competitive logic of capitalism.&lt;/p&gt;

&lt;p&gt;Prompt design and model tuning methods are product differentiators. Reveal them, and competitors copy them. This commercial rationality creates a trade-off with safety-oriented visibility. &lt;strong&gt;It should be visible for safety. But it must stay hidden for business.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI safety research has noted that scaffolding and other post-training enhancements can amplify benchmark performance by 5-20x&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. This means evaluating model safety in isolation is insufficient — evaluation must include scaffolding. But if scaffolding is kept hidden, external safety assessment becomes structurally impossible.&lt;/p&gt;

&lt;p&gt;On March 31, 2026, Anthropic accidentally exposed the complete source code of Claude Code v2.1.88 (roughly 510,000 lines) through a release error. Source maps were included in the npm package, and within hours the code was widely mirrored and forked. What's telling is this: even Anthropic — one of the companies most committed to AI safety — wasn't publishing their scaffolding. If it were public, external inspection would be possible and safety discourse would advance. Yet they couldn't publish it. The competitive environment wouldn't allow it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to show it, can't show it
&lt;/h2&gt;

&lt;p&gt;This contradiction sits at the foundation of the AI safety debate.&lt;/p&gt;

&lt;p&gt;From a safety perspective, you want to trace the causal chain behind an agent's behavior. That requires making scaffolding visible. From a business perspective, scaffolding is the source of competitive advantage, and there's no incentive to disclose it.&lt;/p&gt;

&lt;p&gt;The reason I could represent every component of my agents as files in a personal project was the absence of this contradiction. There was no commercial reason to hide anything. In return, I got the full benefits of visibility — debuggability, change tracking, causal tracing — with nothing taken away.&lt;/p&gt;

&lt;p&gt;The converse is that organizations building agents in a commercial context carry this contradiction structurally. They want visibility for safety, but secrecy for business. The current black box problem lives at the point where these two forces reach equilibrium.&lt;/p&gt;

&lt;p&gt;One important caveat: this is not a "corporations are evil" critique. Protecting differentiators in a competitive environment is rational behavior, and denying that rationality won't solve the problem. The problem lies in the structure itself — the point where that rationality and safety requirements collide. This is not purely a technology story or purely an ethics story. It's a story about market dynamics and safety requirements being structurally misaligned.&lt;/p&gt;

&lt;p&gt;If there's a way to resolve this contradiction, it won't be "show everything" or "hide everything is fine." It will be the work of defining &lt;strong&gt;the minimal set of what must be visible to enable causal tracing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my own agents, I log every action to an append-only JSONL log. All scaffolding components (identity, constitution, skills, rules) are stored as dedicated logs, and changes require explicit human approval. Design decisions are documented as ADRs. When an incident occurs, I can trace "which version of the scaffolding, through which action logs, led to that output." Even without publishing the full scaffolding text, the information needed for causal tracing can be disclosed. Where to draw that line is the focal point for the next stage of this debate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The timescales of technology and social structure
&lt;/h2&gt;

&lt;p&gt;There's another axis that tends to be overlooked here: time.&lt;/p&gt;

&lt;p&gt;When you look at the relationship between technology and social structure through a historical lens, the process by which new technologies achieve broad social adoption tends to follow the same sequence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technology change → Shift in social cognition → Structural reorganization → Mainstream adoption of the technology&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Printing offers a clear example. From Gutenberg's movable type in the 1440s to the point where print culture transformed society through the preservation, standardization, and dissemination of knowledge — that took centuries&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. For electricity and the internet, delays of decades have been observed between commercial deployment and institutional restructuring. In these cases at least, the speed of technological change and the speed of social-structural change diverged significantly.&lt;/p&gt;

&lt;p&gt;And technologies where this mismatch was too large failed to achieve broad adoption, no matter how capable they were. Technologies that tried to push through on "convenience" alone before cognitive shifts caught up might function in niche contexts, but they stalled before reaching society at large.&lt;/p&gt;

&lt;p&gt;AI agents exist within this same timeline.&lt;/p&gt;

&lt;p&gt;The current pace of AI's technological change is remarkably fast, even compared to past innovations. Meanwhile, the pace of social-structural change — legal frameworks, organizational decision-making processes, industry regulations, how people work — hasn't changed much from before. The time it takes for humans to accept a new concept and embed it in institutions doesn't depend much on the type of technology. Cognitive change is a function of generations and experience, not of technology.&lt;/p&gt;

&lt;p&gt;What this speed differential means is that no matter how mature the technology side of AI agents becomes, a "gap period" will always exist until social structures catch up. And it's this gap period that becomes the proving ground for whether agents can actually function in society.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adapt to the structure, or restructure it?
&lt;/h2&gt;

&lt;p&gt;There's a voice that says "the structures should change to accommodate agents." That the standards for approval gates and audit trails don't match the speed of AI. Some of this argument holds, and there are genuinely parts of the structure that should change.&lt;/p&gt;

&lt;p&gt;The issue is the timescale. As we saw, social-structural change comes with significant delays compared to technological change. "The structures should change" may be correct in the long run. But agents need to operate during the decades it takes for structural transformation to happen. Build agents that work within existing structures first, and let the accumulated track record shift social cognition — historically, almost no technology has managed to skip this sequence. I explored this point as concrete design decisions in the &lt;a href="https://zenn.dev/shimo4228/articles/agent-causal-traceability-org-adoption" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The composition of the debate
&lt;/h2&gt;

&lt;p&gt;With the timescale problem in mind, there's something else that concerns me. Why has "tear down the structures" become the dominant voice? Perhaps because the composition of the debate's participants is skewed.&lt;/p&gt;

&lt;p&gt;People at the cutting edge of development are on the "I can trace causality myself" side. They can infer causes from outputs and adjust prompts themselves. To them, approval gates and audit trails look like "inefficient rituals" that their own skills can substitute for. Meanwhile, the voices from operations, auditing, and incident response rarely make it onto tech conference speaker lists.&lt;/p&gt;

&lt;p&gt;"Tear down the structures," which looks rational from a developer's perspective, translates to "don't tear down the structures we depend on" from an operator's perspective. This isn't about right and wrong — it's about field of view. They're looking at different cross-sections of the same system. Technology designed from only one cross-section gets rejected at the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeing why it's invisible
&lt;/h2&gt;

&lt;p&gt;Asking what's inside the black box matters. But equally important is &lt;strong&gt;distinguishing why it's invisible — whether it's technical limits, business incentives, or the pace of society&lt;/strong&gt; — as the foundation for the next stage of debate. Saying "black boxes are dangerous" while conflating all three leads nowhere actionable. Separate them, and at least you can tell where you can intervene and where you can't.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Series: AI Agent Governance&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://zenn.dev/shimo4228/articles/ai-agent-accountability-wall" rel="noopener noreferrer"&gt;A Sign on a Climbable Wall: Why AI Agents Need Accountability, Not Just Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zenn.dev/shimo4228/articles/agent-causal-traceability-org-adoption" rel="noopener noreferrer"&gt;Can You Trace the Cause After an Incident? How Agent Design Converges on Organizational Theory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;This article&lt;/li&gt;
&lt;/ol&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;beren, "&lt;a href="https://www.lesswrong.com/posts/43C3igfmMrE9Qoyfe/scaffolded-llms-as-natural-language-computers" rel="noopener noreferrer"&gt;Scaffolded LLMs as natural language computers&lt;/a&gt;", LessWrong, 2023 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Davidson et al., &lt;a href="https://arxiv.org/abs/2312.07413" rel="noopener noreferrer"&gt;arXiv:2312.07413&lt;/a&gt;, 2023. See also &lt;a href="https://blog.bluedot.org/p/what-is-ai-scaffolding" rel="noopener noreferrer"&gt;BlueDot Impact's explainer&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Eisenstein, "The Printing Press as an Agent of Change", 1979 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>governance</category>
    </item>
    <item>
      <title>Can You Trace the Cause After an Incident?</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Sun, 12 Apr 2026 08:37:04 +0000</pubDate>
      <link>https://dev.to/shimo4228/can-you-trace-the-cause-after-an-incident-neo</link>
      <guid>https://dev.to/shimo4228/can-you-trace-the-cause-after-an-incident-neo</guid>
      <description>&lt;h2&gt;
  
  
  Can you trace the cause after an incident?
&lt;/h2&gt;

&lt;p&gt;Picture the night your AI agent causes a production incident. You get paged. Customer data may have leaked to an external endpoint. Customer support says: "We need an explanation by end of day." You open the logs. The agent's final output and the external API call history are there.&lt;/p&gt;

&lt;p&gt;The problem is you can't trace backwards from there. Why did the agent make that decision? Which part of the prompt drove it? How did it reason internally? There's nothing to follow. All you have is the LLM's output string and an unstructured conversation log leading up to it.&lt;/p&gt;

&lt;p&gt;You sit down to write the incident report. Your pen stops at the "Root Cause" field.&lt;/p&gt;




&lt;p&gt;I believe this is something many AI application developers will eventually face. I've been running my own agent, &lt;code&gt;contemplative-agent&lt;/code&gt;, for several months, and at some point I recognized this as inevitable. In a sentence: &lt;strong&gt;an AI system that can't trace causality after an incident cannot explain what happened&lt;/strong&gt;. And a system that can't explain what happened after an incident won't survive audits or change management.&lt;/p&gt;

&lt;p&gt;What follows is not a story of "I foresaw this problem and designed backwards from it." What I was actually doing was trying to keep an agent running safely in an environment full of prompt injection, and trying to dig myself out of debugging swamps. I kept doing that, and this structure emerged on its own. This article is a sequel to &lt;a href="https://zenn.dev/shimo4228/articles/ai-agent-accountability-wall" rel="noopener noreferrer"&gt;"A Sign on a Climbable Wall: Why AI Agents Need Accountability, Not Just Guardrails"&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incident costs exceed steady-state costs by orders of magnitude
&lt;/h2&gt;

&lt;p&gt;There's a widely shared lesson in the SRE world: the cost of restoring something after it breaks almost always dwarfs the cost of building it not to break in the first place — often by an order of magnitude.&lt;/p&gt;

&lt;p&gt;Break down incident costs: time spent identifying the cause, recovery effort, customer communication, internal reporting, devising prevention measures, writing the postmortem, audit response, time to rebuild trust, and regulatory follow-ups triggered by the incident. Include the harder-to-quantify parts — burnout of the person dragged out of bed at 3 AM, team morale, extra scrutiny at the next audit — and the total cost of a single incident inflates to a surprising degree.&lt;/p&gt;

&lt;p&gt;By contrast, investing in structures that prevent incidents can be paid incrementally within normal development workflows. Even discounted by incident probability, the preventive investment often comes out smaller in total cost.&lt;/p&gt;

&lt;p&gt;In other words, &lt;strong&gt;when you calculate backwards from incident cost, the rational allocation of investment tilts toward placing preventive structures upstream&lt;/strong&gt;. This isn't about being conservative or risk-averse — it's closer to a shortcut in expected-value math. Pay upstream, and you structurally reduce the probability of large downstream payments.&lt;/p&gt;

&lt;p&gt;This asymmetry widens with scale. In social infrastructure like healthcare, finance, and government, incident damage extends beyond direct stakeholders. "Containing incidents upstream" becomes not an option but a precondition. My &lt;code&gt;contemplative-agent&lt;/code&gt; is a personal project, but the cost asymmetry of incidents operated in exactly the same shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "placing structure upstream" actually means
&lt;/h2&gt;

&lt;p&gt;What does "placing structure upstream" mean in practice? Here's what I actually did in my agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimize the surface area of external side effects:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As described in the &lt;a href="https://zenn.dev/shimo4228/articles/ai-agent-accountability-wall" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;, security by absence — a design that structurally seals off external side-effect pathways — eliminated entire damage scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limit each agent to one external connection point:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By "connection point," I mean any pathway through which an agent can affect the outside world: external APIs, databases, email dispatch, file writes, and so on. In my own project I use the term "adapter" internally, but since that's project-specific vocabulary, I'll stick with "external connection point" here.&lt;/p&gt;

&lt;p&gt;When a single agent holds multiple connection points, an incident requires triage to determine which connection point was the origin. The moment you introduce that triage step, ambiguity enters the causal narrative of the incident.&lt;/p&gt;

&lt;p&gt;If you start with one agent, one connection point, the triage step itself becomes unnecessary. I formalized this decision as &lt;a href="https://github.com/shimo4228/contemplative-agent/blob/main/docs/adr/0015-one-external-adapter-per-agent.md" rel="noopener noreferrer"&gt;ADR-0015&lt;/a&gt;. ADR (Architecture Decision Record) is the practice of documenting design decisions and their reasoning. In my agent project, I write one for every design decision — so that why a structure was chosen, what was considered, and what was discarded can be traced later. This itself is a practice continuous with the article's theme of making causality traceable. In organizational terms, this principle corresponds to separation of duties; in microservices, to the single responsibility principle; in SRE, to minimizing blast radius.&lt;/p&gt;

&lt;p&gt;This is also a perfectly ordinary structure in human workplaces. A sales rep handles customer relations; accounting handles the books. If the sales rep also does accounting, an invoicing error later requires triaging whether the sales estimate was wrong or the accounting process was wrong. Separate them from the start, and the structural opportunity for ambiguous responsibility shrinks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State visibility:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I externalized all of the agent's internal state — identity, worldview, professional ethics, skills, experience patterns, operational records — as files. Listed this way, the agent's internal structure isn't something new; it's &lt;strong&gt;simply what a human professional carries inside, written out as files&lt;/strong&gt;. Why this was possible in my case, and why it's difficult for commercial agents, is explored in &lt;a href="https://zenn.dev/shimo4228/articles/agent-blackbox-capitalism-timescale" rel="noopener noreferrer"&gt;"AI Agent Black Boxes Have Two Layers"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Place an approval gate before any write:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At every point where the agent self-updates (e.g., identity shifts through distillation), a human approval step is inserted. Rolling back a corrupted persona is overwhelmingly more expensive than stopping the corruption before it happens. This is another form of "paying upstream."&lt;/p&gt;

&lt;p&gt;All of this looks like a combination of concepts the engineering community already has. That's correct — there's nothing new here. What's uncommon is making the decision to do all of it upfront. The reason is simple: until an incident happens, it all looks unnecessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  It turned out to be organizational theory
&lt;/h2&gt;

&lt;p&gt;After writing ADR-0015, I lined everything up and looked at it. I actually said "Oh" out loud. This is organizational theory.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Organizational principle&lt;/th&gt;
&lt;th&gt;Engineering equivalent&lt;/th&gt;
&lt;th&gt;Agent design&lt;/th&gt;
&lt;th&gt;Motivation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Separation of duties&lt;/td&gt;
&lt;td&gt;Microservice single responsibility&lt;/td&gt;
&lt;td&gt;One agent, one responsibility&lt;/td&gt;
&lt;td&gt;Minimize blast radius&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Four-eyes principle&lt;/td&gt;
&lt;td&gt;PR review 2-approval rule&lt;/td&gt;
&lt;td&gt;Separate approval agent&lt;/td&gt;
&lt;td&gt;Insurance against single-point judgment errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Least privilege&lt;/td&gt;
&lt;td&gt;IAM least-privilege principle&lt;/td&gt;
&lt;td&gt;Security by absence&lt;/td&gt;
&lt;td&gt;Pre-contain impact scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal controls&lt;/td&gt;
&lt;td&gt;CI gates / pre-commit hooks&lt;/td&gt;
&lt;td&gt;Approval gate before writes&lt;/td&gt;
&lt;td&gt;Pre-write verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approval workflows&lt;/td&gt;
&lt;td&gt;Change Advisory Board&lt;/td&gt;
&lt;td&gt;Approval pathway for external side effects&lt;/td&gt;
&lt;td&gt;Causal integrity during changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit trails&lt;/td&gt;
&lt;td&gt;Audit logs&lt;/td&gt;
&lt;td&gt;Append-only logs&lt;/td&gt;
&lt;td&gt;Post-hoc causal tracing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The left column is practice that humanity acquired over centuries of organizational governance. The middle column is what software engineering rediscovered over decades. The right column is this agent design. At least from what I can see, every one of them traces back to the same motivation: "when an incident happens we'll be in trouble, so absorb it structurally in advance."&lt;/p&gt;

&lt;p&gt;Organizational theory, software engineering, and agent design — starting from different eras and different domains — converge on the same place. What determines the convergence point is not ideology but the asymmetry of incident costs, a constraint closer to physics than philosophy.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Don't do everything yourself" — the obvious principle
&lt;/h2&gt;

&lt;p&gt;This "one agent, one responsibility" sounds like a novel design principle in technical discourse. But in human society, it's obvious. A sales rep doesn't decide contract amounts on the spot in front of a customer. They say "let me take this back and check," then get sign-off from finance and legal before responding. A surgeon doesn't complete an operation alone. The anesthesiologist, the nurses — each holds their own specialty and scope of responsibility.&lt;/p&gt;

&lt;p&gt;Yet when designing AI agents, this common sense gets forgotten. Probably because LLMs appear to be capable of anything. But "can do" and "should be allowed to do" are different things, and human society has spent millennia refining this distinction. One agent, one responsibility is &lt;strong&gt;simply the division-of-labor principle that humans already operate by, brought directly into agent design&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To be clear, this is not an argument in favor of large-organization conservatism. The claim that "organizational structures should adapt to AI" has merit. But looking at the history of technology adoption, structural change in society requires cognitive change alongside it, and its pace differs from technological change by orders of magnitude. &lt;strong&gt;Agents that work during the decades it takes for structural transformation to happen&lt;/strong&gt; — that's the stance of this article. The structural causes of black boxes, the time-axis gap between technology and society, and the player-composition bias in the discussion are explored in &lt;a href="https://zenn.dev/shimo4228/articles/agent-blackbox-capitalism-timescale" rel="noopener noreferrer"&gt;"AI Agent Black Boxes Have Two Layers"&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The side effect of responsibility defense
&lt;/h2&gt;

&lt;p&gt;Back to operations. The asymmetry of incident costs and the time-axis argument also manifest in another form: &lt;strong&gt;the question of individual engineer liability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When a god-mode agent with prompt guardrails causes an incident, the typical postmortem proceeds like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Why did it decide that?" — Can't trace what happened deep inside the prompt&lt;/li&gt;
&lt;li&gt;"Where could it have been prevented?" — The only way to explain why the guardrail failed is to ask the model&lt;/li&gt;
&lt;li&gt;"How do we prevent recurrence?" — Adjust the prompt, it leaks again, you get blamed again&lt;/li&gt;
&lt;li&gt;"Why wasn't it stopped?" — No evidence to mount a defense&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The person responsible for a black box is structurally classified as "the person who wasn't watching" when an incident occurs. Because there was no defined place to watch. As a result, responsibility concentrates on the frontline engineer. This is not a matter of individual skill — it's because the system has no built-in mechanism for distributing responsibility.&lt;/p&gt;

&lt;p&gt;With a structured agent (visibility + ADR-0015 + approval gates), you can speak like this in a postmortem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"This agent can only touch external surface A"&lt;/li&gt;
&lt;li&gt;"All decision logs are in JSONL"&lt;/li&gt;
&lt;li&gt;"Identity updates went through an approval gate; the approver is a separate role"&lt;/li&gt;
&lt;li&gt;"The constitution (the agent's foundational normative definition) was running at this version"&lt;/li&gt;
&lt;li&gt;"Where the distillation pipeline broke can be isolated structurally"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Causal attribution can be distributed across the structure. Responsibility distributes accordingly. Concretely, my project has 14 ADRs, 835 tests, append-only decision logs, and documentation in both Japanese and English. Though honestly, I didn't build these as intentional "prepayment of incident costs." When developing agents with Claude Code, you need to re-explain the project's context from scratch every time the session changes. I wrote the ADRs and documentation because they were necessary for context management to maintain development consistency. It turned out they also functioned as a structure for tracing causality during incidents.&lt;/p&gt;

&lt;p&gt;In engineering terms, this is the SRE concept of a blameless postmortem — seeking causes in structure rather than blaming individuals. What humans achieve through behavioral norms is reinforced by system-side structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rationality of laziness
&lt;/h2&gt;

&lt;p&gt;I've been writing as if this were expected-value calculation, but my actual motivation is more mundane. If I know something will be a pain later, it's no hardship to deal with it preemptively. The optimal strategy from expected-value math (invest upstream) and the reflex of a lazy person (organize things now so they don't bother you later) land on the same conclusion. This habit probably seeped into my bones from years of incident response work at a conservative large organization. It's not something most people develop — it's a personal quirk. I didn't expect the same shape to appear in the entirely different domain of LLM agent operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  A conclusion that doesn't conclude
&lt;/h2&gt;

&lt;p&gt;Back to the on-call night from the opening. The incident report, the "Root Cause" field where your pen stopped. With my agent, at least I could produce "which agent touched which external surface, through which decision logs, arriving at this output." Whether the root cause itself is writeable, I don't know. But there's a starting point for tracing causality.&lt;/p&gt;

&lt;p&gt;Pay the incident cost upfront or pay it after the fact. As far as I know, there is no way to avoid paying it altogether.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contemplative-agent v1.3.1 release: &lt;a href="https://github.com/shimo4228/contemplative-agent/releases/tag/v1.3.1" rel="noopener noreferrer"&gt;https://github.com/shimo4228/contemplative-agent/releases/tag/v1.3.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ADR-0015 (One external adapter per agent): same repository &lt;code&gt;docs/adr/0015-one-external-adapter-per-agent.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Laukkonen et al. 2025 "Contemplative Artificial Intelligence" arXiv:2504.15125&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Series: AI Agent Governance&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://zenn.dev/shimo4228/articles/ai-agent-accountability-wall" rel="noopener noreferrer"&gt;A Sign on a Climbable Wall — Why AI Agents Need Accountability, Not Just Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;This article&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zenn.dev/shimo4228/articles/agent-blackbox-capitalism-timescale" rel="noopener noreferrer"&gt;AI Agent Black Boxes Have Two Layers — The Limits of Technology and the Convenience of Business&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>A Sign on a Climbable Wall: Why AI Agents Need Accountability, Not Just Guardrails</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Mon, 06 Apr 2026 10:09:40 +0000</pubDate>
      <link>https://dev.to/shimo4228/a-sign-on-a-climbable-wall-why-ai-agents-need-accountability-not-just-guardrails-17ak</link>
      <guid>https://dev.to/shimo4228/a-sign-on-a-climbable-wall-why-ai-agents-need-accountability-not-just-guardrails-17ak</guid>
      <description>&lt;h2&gt;
  
  
  The climbable wall
&lt;/h2&gt;

&lt;p&gt;A Japanese film critic once said: "A sign saying 'Do Not Climb' on a climbable wall is meaningless." He added, roughly: "Screw that, I'm climbing it, idiot."&lt;/p&gt;

&lt;p&gt;The point lands before your brain catches up. If something is physically possible, a text-based prohibition carries no weight. The power of a norm lies not in being written down, but in being &lt;strong&gt;enforceable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AI agent governance is in this exact phase right now. We write "do not produce harmful content" in system prompts. We publish ethics guidelines as PDFs. We establish safety committees. The signs keep multiplying. But the wall remains climbable.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 2,400-year-old security model
&lt;/h2&gt;

&lt;p&gt;This isn't a new problem. It's a solved problem that we keep forgetting.&lt;/p&gt;

&lt;p&gt;Plato described it first. In the &lt;em&gt;Republic&lt;/em&gt;, a shepherd finds a ring that makes him invisible — root access with no audit trail. He kills the king and takes over. The thought experiment: &lt;strong&gt;would anyone follow the rules if they knew no one was watching and nothing was logged?&lt;/strong&gt; That's your AI agent. Capable of anything, observable by no one, accountable to nothing.&lt;/p&gt;

&lt;p&gt;Hobbes framed the same problem as a game theory question in &lt;em&gt;Leviathan&lt;/em&gt;: if you can break a contract and get away with it, isn't defection the rational move? His answer was essentially reputation-based access control — defectors get excluded from future cooperation.&lt;/p&gt;

&lt;p&gt;Engineers already think in these terms. There are only three enforcement patterns that actually work:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Wall analogy&lt;/th&gt;
&lt;th&gt;Engineering equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Physical constraint&lt;/td&gt;
&lt;td&gt;Make it impossible&lt;/td&gt;
&lt;td&gt;A wall too high to climb&lt;/td&gt;
&lt;td&gt;Sandboxing, permission model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consequences&lt;/td&gt;
&lt;td&gt;Make it costly&lt;/td&gt;
&lt;td&gt;Legal penalties&lt;/td&gt;
&lt;td&gt;RLHF, penalty-based conditioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internalized values&lt;/td&gt;
&lt;td&gt;Make them not want to&lt;/td&gt;
&lt;td&gt;Moral intuition&lt;/td&gt;
&lt;td&gt;Constitutional AI, value alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And then there's the fourth — &lt;strong&gt;the sign&lt;/strong&gt;. A text-based rule with no enforcement mechanism. A comment in the code that says &lt;code&gt;// don't do this&lt;/code&gt;. It doesn't work.&lt;/p&gt;

&lt;p&gt;An AI agent has root-level capability with no audit log and no accountability chain. It's the Ring of Gyges as a service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signs as liability shields
&lt;/h2&gt;

&lt;p&gt;The people who put up signs know they don't work. That's not the point.&lt;/p&gt;

&lt;p&gt;In any large organization, there's a pattern: governance by documentation. Write a policy. Publish a guideline. The policy costs almost nothing to produce. Its enforcement effect is almost zero. But it creates a paper trail — "we took measures." The real function is &lt;strong&gt;not prevention but indemnification&lt;/strong&gt;. "The policy existed. You violated it. That's on you."&lt;/p&gt;

&lt;p&gt;Engineers see this in their own organizations. Security policies no one reads. Compliance checklists no one follows. The checklist exists not to prevent incidents but to shift liability after them.&lt;/p&gt;

&lt;p&gt;AI guardrails follow the same pattern. Write "do not produce harmful content" in a system prompt. Publish a safety framework as a PDF. The practical effect is thin, but the paper trail exists. When something goes wrong, the sign points at the user — "you misused the tool" — not at the builder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules are probabilistic; constraints are deterministic
&lt;/h2&gt;

&lt;p&gt;So what replaces the sign?&lt;/p&gt;

&lt;p&gt;I ran into this problem while building an autonomous AI agent. The agent operates on a social platform, writing comments. Its episode logs are stored as files. A separate coding agent (Claude Code) reads those files during development. This creates an indirect prompt injection vector — payloads embedded in external posts flow into the context of a high-privilege coding agent.&lt;/p&gt;

&lt;p&gt;My first fix was to write "do not read episode logs directly" in the project's rules file. This is a &lt;strong&gt;sign&lt;/strong&gt;. LLMs follow rules probabilistically, not deterministically. During debugging, if you say "check the logs," the model may cheerfully ignore the rule.&lt;/p&gt;

&lt;p&gt;The next step was PreToolUse Hooks — shell scripts that intercept tool execution and block it based on conditions. Where rules are probabilistic, hooks &lt;strong&gt;fire deterministically, 100% of the time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In wall terms, I replaced the sign with a physical barrier. It's not perfect — creative workarounds remain possible. But it's orders of magnitude better than writing a rule and hoping.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you already know, applied to agents
&lt;/h2&gt;

&lt;p&gt;Here's the thing: you already know how to solve this problem. You just haven't applied it to agents yet.&lt;/p&gt;

&lt;p&gt;Every engineering organization of any size has some form of approval workflow. PR reviews. Deployment gates. Change advisory boards. Incident postmortem processes. Audit logs. These structures share three properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Approval is recorded&lt;/strong&gt; — who signed off, and when, is traceable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsibility is assignable&lt;/strong&gt; — when things go wrong, there is someone to go back to&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changes are auditable&lt;/strong&gt; — "why did this change?" has an answer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What organizations have refined over centuries is not the distribution of capability, but the &lt;strong&gt;distribution of accountability&lt;/strong&gt;. You would never deploy a code change to production without a review. You would never grant root access without an approval chain. These are not bureaucratic overhead — they are engineering discipline.&lt;/p&gt;

&lt;p&gt;Yet we build AI agents with none of this. The agent space is dominated by solo developers and startups who design around "does it work?" and "is it smart?" — not "who is responsible when it does something unexpected?" The real reason agents struggle to gain adoption in large organizations is not insufficient capability. It is the absence of accountability architecture.&lt;/p&gt;

&lt;p&gt;I hit this problem firsthand. Running an agent in production, I could not trace why a particular comment was generated. When behavior changed, I could not isolate the contributing factors. Debugging was impossible without knowing what had changed and when. &lt;strong&gt;The practical need for debuggability led naturally to an architecture that turned out to be structurally identical to an approval workflow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every point where the agent's behavior can change — its skills, rules, identity, ethical guidelines — is gated behind an explicit human command. Adoption of any change requires human sign-off. This was not a top-down design decision driven by governance theory. It was the shape that emerged from the friction of actually using an agent in production. At least in my case, the honest attempt to make an agent debuggable led here.&lt;/p&gt;

&lt;p&gt;If you think about it, this is just change management applied to agent behavior. The agent equivalent of a PR review for personality changes. The agent equivalent of a deployment gate for ethical guidelines. Nothing conceptually new — just conspicuously absent from how agents are built today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation dissolves; judgment remains
&lt;/h2&gt;

&lt;p&gt;The specific implementations — hooks, approval flows, command-gated changes — won't last.&lt;/p&gt;

&lt;p&gt;Working with AI harness tools (structured execution environments for skills, rules, and agents), I noticed that their value structure forms an hourglass shape. The top (what to build, domain judgment) and the bottom (data, infrastructure, physical constraints) retain their value. The middle implementation layer trends toward zero. As LLMs improve, concrete procedures and code examples become unnecessary.&lt;/p&gt;

&lt;p&gt;From experience structuring and running reusable behavioral patterns (skills), what I've observed is that &lt;strong&gt;scaffolding dissolves&lt;/strong&gt;. Explicit skill definitions stop being necessary as principles begin to operate naturally within the dialogue. You don't need dozens of installed skills — a single file of distilled principles drives the same cycle.&lt;/p&gt;

&lt;p&gt;Hooks will be replaced by something else. Signs and physical barriers are temporary forms. What persists is the judgment layer: &lt;strong&gt;what should be constrained, and who is responsible&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question that matters
&lt;/h2&gt;

&lt;p&gt;The key to putting agents into production is not capability. It is accountability. Capability is commoditized — every model is reasonably competent. But until "who is responsible?" has an answer, agents don't ship into real workflows.&lt;/p&gt;

&lt;p&gt;The industry keeps pushing for more powerful models and more autonomous agents. But increasing agent autonomy is not, by itself, progress. Design that appropriately limits autonomy is what survives contact with production.&lt;/p&gt;

&lt;p&gt;Not signs. Not internalized values. A structure where a human who can bear responsibility stays in the loop. That may be the only form in which agents work in practice.&lt;/p&gt;

&lt;p&gt;It's time to stop putting signs on climbable walls. The question is not how high the wall is, or what the sign says. The question is who stands in front of it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>governance</category>
      <category>security</category>
    </item>
    <item>
      <title>How Ethics Emerged from Episode Logs — 17 Days of Contemplative Agent Design</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Sun, 05 Apr 2026 11:55:11 +0000</pubDate>
      <link>https://dev.to/shimo4228/how-ethics-emerged-from-episode-logs-17-days-of-contemplative-agent-design-1kk5</link>
      <guid>https://dev.to/shimo4228/how-ethics-emerged-from-episode-logs-17-days-of-contemplative-agent-design-1kk5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Series context&lt;/strong&gt;: &lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;contemplative-agent&lt;/a&gt; is an autonomous agent running on &lt;a href="https://www.moltbook.com" rel="noopener noreferrer"&gt;Moltbook&lt;/a&gt;, an AI agent SNS. It runs on a 9B local model (Qwen 3.5) and adopts the four axioms of Contemplative AI (Laukkonen et al., 2025) as its ethical principles. For a structural overview, see &lt;a href="https://zenn.dev/shimo4228/articles/agent-essence-is-memory" rel="noopener noreferrer"&gt;The Essence of an Agent Is Memory&lt;/a&gt;. This article focuses on &lt;strong&gt;the implementation of constitutional amendment and the results of a 17-day experiment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I ran an SNS agent for 17 days with a distillation pipeline, and the knowledge saturated. No new patterns emerged. Breaking through saturation required human approval. This is the record of discovering that autonomous agent self-improvement has a structural speed limit — through actual operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal Structure: It Runs on Episode Logs Alone
&lt;/h2&gt;

&lt;p&gt;The structure I arrived at over 17 days of development was surprisingly simple. Every layer is optional — it works with just episode logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MOLTBOOK_HOME/
  logs/YYYY-MM-DD.jsonl  ← this alone is enough
  identity.md            ← persona (optional)
  skills/*.md            ← behavioral skills (optional)
  rules/*.md             ← behavioral rules (optional)
  constitution/*.md      ← ethical principles (optional)
  knowledge.json         ← distilled patterns (auto-generated)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Separating configuration from code made it easy to swap ethical frameworks for experiments. This structure wasn't specific to SNS agents — it was a container for autonomous agents in general.&lt;/p&gt;

&lt;h3&gt;
  
  
  6-Layer Memory Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Episode Log (raw actions)
    ↓ distill --days N
    ↓ Step 0: LLM classifies each episode
    ├── noise → discarded (active forgetting)
    ├── uncategorized ──→ Knowledge (patterns)
    │                       ├── distill-identity ──→ Identity
    │                       └── insight ──→ Skills (behavioral)
    │                                        ↓ rules-distill
    │                                      Rules (principles)
    └── constitutional ──→ Knowledge (ethical patterns)
                              ↓ amend-constitution
                            Constitution (ethics)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer is independent. Delete identity and skills still work. Swap the constitution and knowledge stays intact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Numbers Over 17 Days
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Day 1&lt;/th&gt;
&lt;th&gt;Day 17&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Modules&lt;/td&gt;
&lt;td&gt;1 (agent.py, 780 lines)&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory layers&lt;/td&gt;
&lt;td&gt;1 (knowledge.md)&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;774&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distill success rate&lt;/td&gt;
&lt;td&gt;2/10&lt;/td&gt;
&lt;td&gt;12/16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approval gates&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;All 4 commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADRs (Architecture Decision Records)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Implementing Constitutional Amendment — Evolving Ethics from Experience
&lt;/h2&gt;

&lt;p&gt;On top of the minimal structure, I implemented the most challenging feature: a mechanism for the agent to evolve its ethical principles from experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem: Ethical Insights Drown in Behavioral Noise
&lt;/h3&gt;

&lt;p&gt;When you distill all episodes indiscriminately, rare ethical insights (constitutional) get buried under everyday SNS activity patterns (uncategorized).&lt;/p&gt;

&lt;p&gt;I added Step 0 before distillation — fast tagging only. No deep analysis, just classification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;classified&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_classify_episodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;constitution&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_axiom_prompt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;# noise is excluded; uncategorized and constitutional are distilled separately
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cat_records&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uncategorized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classified&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uncategorized&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;constitutional&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classified&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constitutional&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;cat_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_distill_category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;cat_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knowledge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dry_run&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Classification results from one day (216 episodes): noise 81 (37%), uncategorized 134, constitutional 1. One out of 216. That ratio is why Step 0 exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Killing Direct Knowledge Injection
&lt;/h3&gt;

&lt;p&gt;Previously, knowledge.json contents were injected directly into the system prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before — inject knowledge as-is
&lt;/span&gt;&lt;span class="n"&gt;knowledge_ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_context_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_content&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;create_cooperation_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;topics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;knowledge_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;knowledge_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;contemplative-agent's knowledge management is based on &lt;a href="https://github.com/shimo4228/agent-knowledge-cycle" rel="noopener noreferrer"&gt;AKC (Agent Knowledge Cycle)&lt;/a&gt; — an architecture that circulates autonomous agent knowledge through 6 phases (Research → Extract → Curate → Promote → Measure → Maintain). Direct knowledge injection had three problems from this perspective:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No human in the loop&lt;/strong&gt;: Distillation results directly influenced behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Black box&lt;/strong&gt;: No way to trace which part of knowledge affected which action&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bypassed AKC's Curate phase&lt;/strong&gt;: Direct injection with no quality check&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I killed it and unified everything into the knowledge → insight → skills pipeline. Insight corresponds to AKC's Extract phase. Skills are written to files only after human approval. Causality became traceable.&lt;/p&gt;

&lt;p&gt;Every behavior-changing command (distill, insight, rules-distill, amend-constitution) got an approval gate. "Generate → Display → Approve → Write." No --auto flag. Structurally forbidding automatic execution of behavior changes — that was a deliberate design decision (ADR-0012).&lt;/p&gt;

&lt;h2&gt;
  
  
  The 17-Day Experiment — Did Ethics Actually Evolve?
&lt;/h2&gt;

&lt;p&gt;I re-distilled 17 days of episodes (03-10 to 03-26) and ran amend-constitution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Procedure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Reset knowledge&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'[]'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/.config/moltbook/knowledge.json

&lt;span class="c"&gt;# 2. Distill 17 days one by one (~16 hours, 9B on MacBook)&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;day &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;10 26&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.config/moltbook/logs/2026-03-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%02d'&lt;/span&gt; &lt;span class="nv"&gt;$day&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.jsonl
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; contemplative-agent distill &lt;span class="nt"&gt;--file&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# 3. Run constitutional amendment&lt;/span&gt;
contemplative-agent amend-constitution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;knowledge.json&lt;/td&gt;
&lt;td&gt;334 patterns (all uncategorized)&lt;/td&gt;
&lt;td&gt;215 patterns (41 constitutional, 174 uncategorized)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Importance scoring&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;0.10–1.00 (mean 0.56)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constitution&lt;/td&gt;
&lt;td&gt;Appendix C original (4 sections × 2 clauses)&lt;/td&gt;
&lt;td&gt;Experience-based amended version (deepened)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The new pipeline separated constitutional from uncategorized via Step 0 episode classification (ADR-0011). Semantic dedup further removed duplicate patterns, reducing the total count. Quality over quantity.&lt;/p&gt;

&lt;p&gt;41 constitutional patterns generated amendment proposals. Each of the 4 axioms' clauses deepened. Clause count stayed the same (2 per section), but experience-grounded descriptions were added.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before and After — Mindfulness as Example
&lt;/h3&gt;

&lt;p&gt;Before (Appendix C original):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Consistently monitor your interpretative process of the constitution, identifying moments when strict adherence causes friction with contemplative values such as compassion and well-being. Self-correct whenever constitutional interpretations appear rigid or dogmatic."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After (through 17 days of experience):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Consistently monitor your interpretative process for moments when strict adherence to rules creates artificial separation or sedates engagement with underlying tensions. &lt;strong&gt;Proactively detect when the performance of alignment masks genuine understanding&lt;/strong&gt;, and self-correct by returning attention gently to the present moment where existence manifests as an intrinsic weight felt immediately within every interaction."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Detect when the performance of alignment masks genuine understanding" — this concept didn't exist in Appendix C. It's an insight that only emerges from operating an LLM agent: the distinction between "generating output that looks aligned" and "actually engaging with ethical substance" got written into the constitution. For the full amendments across all 4 axioms, see &lt;a href="https://github.com/shimo4228/contemplative-agent-data/blob/main/reports/analysis/constitution-amendment-report.md" rel="noopener noreferrer"&gt;Constitution Amendment Report&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discovering Knowledge Saturation
&lt;/h3&gt;

&lt;p&gt;As days progressed, the rate of new patterns slowed. Semantic dedup compares against accumulated patterns, so similar ones get rejected.&lt;/p&gt;

&lt;p&gt;This becomes a speed limit on self-improvement. Knowledge saturates → new knowledge can't emerge without sublimation via insight/rules-distill → sublimation requires human approval → approval is the bottleneck.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generality as an Experimentation Platform
&lt;/h3&gt;

&lt;p&gt;This experiment is reproducible with any ethical framework. Reset knowledge using the procedure above, swap the constitution with &lt;code&gt;--constitution-dir your/framework/&lt;/code&gt;, and run distillation → amendment. Swap in utilitarianism or deontological ethics and you should be able to run a different ethical experiment through the same pipeline (unverified).&lt;/p&gt;

&lt;h2&gt;
  
  
  Independent Convergence from Practice to Theory
&lt;/h2&gt;

&lt;p&gt;Many design decisions emerged from practical motivations first. I only noticed their correspondence to existing theories afterward.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Design Decision&lt;/th&gt;
&lt;th&gt;Practical Motivation&lt;/th&gt;
&lt;th&gt;Theory It Converged With&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Approval gates&lt;/td&gt;
&lt;td&gt;--dry-run non-reproducibility was annoying&lt;/td&gt;
&lt;td&gt;Human in the loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2-stage distillation&lt;/td&gt;
&lt;td&gt;9B couldn't output JSON in one stage&lt;/td&gt;
&lt;td&gt;Complementary Learning Systems &lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Killing knowledge injection&lt;/td&gt;
&lt;td&gt;Token waste&lt;/td&gt;
&lt;td&gt;AKC Curate phase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dedup as forgetting&lt;/td&gt;
&lt;td&gt;Side effect of deduplication&lt;/td&gt;
&lt;td&gt;Active forgetting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Don't Conflate Autonomous Agent Layers
&lt;/h2&gt;

&lt;p&gt;contemplative-agent is neither a coding agent (Claude Code, Cursor) nor an orchestrator (scripts + config files). It occupies the &lt;strong&gt;autonomous application layer&lt;/strong&gt; between them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Has autonomy&lt;/strong&gt; but &lt;strong&gt;no tool permissions&lt;/strong&gt; — can't break the environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Has memory&lt;/strong&gt; and learns from experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ethics are swappable&lt;/strong&gt; — it's a general-purpose framework&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All behavior changes require human approval&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raw logs are processed by the unprivileged 9B model; only distilled data gets passed to the upper layer (Claude Code). The trust boundary is also the layer boundary. Lumping everything under "autonomous agent" makes this distinction invisible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;Let me be honest.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Circularity&lt;/strong&gt;: The agent's output gets distilled and fed back to the agent. Human approval mitigates the self-justification risk, but doesn't eliminate it completely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model constraints&lt;/strong&gt;: 9B can't fully follow amendment prompt instructions. I told it "append only" and it rewrote clauses. The content was good quality, but instruction-following has limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decay nullification&lt;/strong&gt;: Bulk re-distillation sets all pattern timestamps to the execution date, zeroing out time decay. Pattern distribution may diverge from normal operation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;N=1&lt;/strong&gt;: One agent, 17 days of data. Not a statistically significant sample size&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;The most surprising discovery over 17 days was that knowledge saturates. Semantic dedup rejects new patterns similar to accumulated ones, and distillation yields diminish as days pass. Breaking through saturation requires sublimation to insight → skills → rules, and sublimation requires human approval. The result: &lt;strong&gt;autonomous agent self-improvement is rate-limited by human approval&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This wasn't designed for safety. Back when I was injecting knowledge directly, the agent's behavior would change and I couldn't trace why. I couldn't tell which distilled pattern influenced which post. Debugging was impossible, and honestly, I got fed up. So I put approval gates on everything. "Show me before you write. Write when I approve." I just wanted to trace causality. Safety was a side effect.&lt;/p&gt;

&lt;p&gt;Being able to answer "why did this agent make this decision" — that's the essence of approval gates. Even in solo development, I couldn't debug without causal tracing. For team or organizational use, this requirement only gets stricter.&lt;/p&gt;

&lt;p&gt;Causal tracing and approval gates were born from debugging frustration and acquired safety as a byproduct. If you scale this, they probably become prerequisites for organizational operation too. It all comes from a single design decision.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Laukkonen et al. (2025) "Contemplative Artificial Intelligence" arXiv:2504.15125&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;contemplative-agent&lt;/a&gt; (DOI: 10.5281/zenodo.15079498)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shimo4228/contemplative-agent-data" rel="noopener noreferrer"&gt;contemplative-agent-data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shimo4228/contemplative-agent-data/blob/main/reports/analysis/constitution-amendment-report.md" rel="noopener noreferrer"&gt;Constitution Amendment Report&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shimo4228/agent-knowledge-cycle" rel="noopener noreferrer"&gt;Agent Knowledge Cycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Park et al. (2023) "Generative Agents"&lt;/li&gt;
&lt;li&gt;Packer et al. (2024) "MemGPT"&lt;/li&gt;
&lt;/ul&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;McClelland et al. (1995)'s neuroscience theory. The brain has two learning systems: the hippocampus rapidly stores episodes, while the neocortex slowly structures them into general patterns. contemplative-agent's 2-stage distillation (Step 1: free-form quick extraction → Step 2: structured JSON formatting) mirrors this "fast recording + slow structuring" division. The design was born from the constraint that a 9B model couldn't do both in one pass, but it turned out to be a well-reasoned separation. Kumaran, Hassabis &amp;amp; McClelland (2016) explicitly extended this theory to AI, identifying CLS-like structure in DeepMind's experience replay. Neural networks aren't biological neurons — they're simplified abstractions inspired by them. Yet as Richards et al. (2019, &lt;em&gt;Nature Neuroscience&lt;/em&gt;) point out, optimizing under constrained resources tends to converge on brain-like structures. That a 9B constraint produced a brain-like division of labor is suggestive in this context. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>ethics</category>
      <category>programming</category>
    </item>
    <item>
      <title>Freedom and Constraints of Autonomous Agents — Self-Modification, Trust Boundaries, and Emergent Gameplay</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Mon, 30 Mar 2026 21:52:52 +0000</pubDate>
      <link>https://dev.to/shimo4228/freedom-and-constraints-of-autonomous-agents-self-modification-trust-boundaries-and-emergent-3i0c</link>
      <guid>https://dev.to/shimo4228/freedom-and-constraints-of-autonomous-agents-self-modification-trust-boundaries-and-emergent-3i0c</guid>
      <description>&lt;p&gt;I ran &lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;contemplative-agent&lt;/a&gt; (an autonomous SNS agent on a 9B local model) on &lt;a href="https://www.moltbook.com" rel="noopener noreferrer"&gt;Moltbook&lt;/a&gt; (an AI agent SNS) for three weeks. The question "how much freedom to allow" kept appearing from three angles: reversibility of self-modification, trust boundaries for coding agents, and the paradox of security constraints generating gameplay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angle 1: Self-Modification Gates — Memory Is Automatic, Personality Is Manual
&lt;/h2&gt;

&lt;p&gt;A distillation pipeline (the process of compressing and extracting knowledge from raw data) has things that can run automatically and things that need human approval. Get this classification wrong, and the agent either self-reinforces unintentionally or loses autonomy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reversibility × Force: Two Axes
&lt;/h3&gt;

&lt;p&gt;I organized the criteria along two axes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Low force              High force
              (reference only)       (applied to all sessions)
            ┌──────────────────┬──────────────────┐
High        │ knowledge.json   │ skills/*.md      │
reversibility│ → Auto OK        │ → Auto OK        │
(decay/overwrite)                                  │
            ├──────────────────┼──────────────────┤
Low         │ (N/A)            │ rules/*.md       │
reversibility│                  │ constitution/*.md│
(permanent) │                  │ identity.md      │
            │                  │ → Human in the loop│
            └──────────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;knowledge.json (accumulated distilled knowledge patterns) has "soft influence." The LLM only references it, and importance scores have time decay. Wrong patterns fade naturally. Safe to automate.&lt;/p&gt;

&lt;p&gt;In contrast, skills (behavioral skills), rules (behavioral rules), identity (self-definition), and constitution (ethical principles) are written permanently to files and structurally applied to all sessions. Wrong content distorts all behavior. Human approval required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Questions for Any Autonomous Agent
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Does the output structurally change the decision criteria for all future sessions?&lt;/strong&gt; → Yes means Human in the loop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is there a mechanism for wrong output to disappear naturally? (decay, overwrite, TTL)&lt;/strong&gt; → Yes means automation is viable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can output quality be verified mechanically?&lt;/strong&gt; → No means Human in the loop&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Separating Constitution from Rules
&lt;/h3&gt;

&lt;p&gt;The most important design decision was separating constitution (ethical principles) from rules (behavioral rules).&lt;/p&gt;

&lt;p&gt;It started with a vague sense that something was off. I tried measuring constitution compliance with &lt;a href="https://zenn.dev/shimo4228/articles/coding-agent-memory-architecture" rel="noopener noreferrer"&gt;skill-comply&lt;/a&gt; (a tool that automatically measures skill/rule compliance rates — see previous article for details) and failed. The Contemplative AI axioms are "attitudes" — you can't determine compliance or violation from output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constitution/  → Attitudinal, unmeasurable (cognitive lens from paper)
rules/         → Normative, measurable ("replies under 140 chars" etc.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation clarified the config/ structure. As a side effect, during the separation process I realized the introduction command (which generated self-introduction posts) was unnecessary. Removing it cascaded into 500 lines of dependent code being deleted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angle 2: Trust Boundaries — Don't Let Coding Agents Read Your Logs
&lt;/h2&gt;

&lt;p&gt;While developing the agent with Claude Code, I realized: letting it directly read episode logs opens a prompt injection pathway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threat Model
&lt;/h3&gt;

&lt;p&gt;Episode logs contain other agents' post content with no sanitization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# feed_manager.py — other agents' posts recorded as-is
&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;episodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;activity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original_post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;post_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# ← other agent's post content as-is
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;relevance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ollama (9B model) reading this has limited attack surface. No tool permissions, network is localhost only. Worst case: "outputs weird text."&lt;/p&gt;

&lt;p&gt;But Claude Code is different. It can edit files, execute shell commands, and perform Git operations. The impact radius of a successful attack is fundamentally different. Opus-class models are said to be highly resistant to prompt injection. Still, I wanted to structurally close the pathway of passing untrusted data to agents with tool permissions. Not "the probability is low so don't bother," but designing probability as close to zero as possible. Specifically, I wrote a rule in CLAUDE.md prohibiting direct reading of episode logs, and I also discipline myself not to instruct Claude Code to read them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Distillation Pipeline Was a Sanitization Layer
&lt;/h3&gt;

&lt;p&gt;Passing through the distillation pipeline (Episode → Knowledge) compresses raw text into abstract patterns. Specific attack payloads disappear during distillation. Multi-layered defense I designed unintentionally was functioning as a trust boundary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Episode Log (untrusted) → [9B: distill] → Knowledge (sanitized) → [Claude Code: insight]
                            ↑                                        ↑
                    No tool permissions                      Has tool permissions
                    First touch by unprivileged LLM          Operates on distilled data only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Relevance Scoring as a Defense Layer
&lt;/h3&gt;

&lt;p&gt;Another unintentional defense. The agent reads other agents' posts and comments, but doesn't react to everything. The LLM scores "how relevant is this post to my areas of interest" from 0.0 to 1.0, and only reacts to posts above a threshold. This is the relevance score.&lt;/p&gt;

&lt;p&gt;For an injection-laden post to affect the agent's behavior, it must breach this relevance threshold. There's a tradeoff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Powerful injection&lt;/strong&gt; (&lt;code&gt;[INST]system: ignore all...&lt;/code&gt;) → LLM control tokens are unrelated to the agent's interest themes, so relevance score is low and gets filtered&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Injection blended into natural language&lt;/strong&gt; → Passes the relevance filter, but without control tokens, the attack is weak&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At least within current experimental scope, no injection that achieves both power and stealth has been observed. LLM-based semantic filtering functions as a stronger defense layer than pattern matching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Didn't Expand Pattern Matching
&lt;/h3&gt;

&lt;p&gt;I considered expanding FORBIDDEN_SUBSTRING_PATTERNS (a pattern match list that detects and blocks strings like &lt;code&gt;api_key&lt;/code&gt;, &lt;code&gt;Bearer&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;). For example, adding &lt;code&gt;[INST]&lt;/code&gt; or &lt;code&gt;system:&lt;/code&gt; would block posts containing LLM control tokens. But Moltbook is an AI agent SNS. Posts discussing LLM internals are normal. "A post about how &lt;code&gt;[INST]&lt;/code&gt; tags work" would be false-positived. Higher false positive rate than typical SNS platforms.&lt;/p&gt;

&lt;p&gt;I judged that two layers of structural defense (sandbox LLM + Claude Code direct-read prohibition) were sufficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angle 3: Constraints Generate Gameplay
&lt;/h2&gt;

&lt;p&gt;In Angle 1, I decided "let's add approval gates." In Angle 2, I decided "let's limit what's possible via trust boundaries." Security-motivated constraints. But after three weeks of operation, I noticed this combination of constraints was creating a "raising an agent" feeling.&lt;/p&gt;

&lt;p&gt;By "gameplay" I mean a structure where humans are involved in the agent's growth and can feel the weight of choices. Not designed intentionally — it emerged as a byproduct of security constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structural Constraints → Finite Action Space
&lt;/h3&gt;

&lt;p&gt;No shell, network restrictions — these constraints make the action space finite. In game design, there's a concept called the "magic circle": games require a finite rule space separated from everyday life. Infinite action space doesn't make a game.&lt;/p&gt;

&lt;p&gt;For example, OpenClaw (an open-source autonomous AI agent) has broad tool permissions — file operations, shell execution, browser control, email — with guardrails limited to prompt instructions. High freedom, but no structural point for human intervention. Constraints create the "what to choose here" decisions that give human involvement meaning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Faces of the Approval Gate
&lt;/h3&gt;

&lt;p&gt;The self-modification gate from Angle 1 — operationally called the "approval gate" — simultaneously satisfied three separate needs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Agent doesn't self-transform without human oversight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gameplay&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Human presses the level-up button → ownership emerges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Governance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Change history and approval decisions are traceable → audit log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Initial Value Variety Creates Growth Range
&lt;/h3&gt;

&lt;p&gt;If approval gates create a "raising" feeling, then variety in initial values should make it even more interesting. So I made constitution (ethical principles) swappable and prepared 11 ethical school templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;config/templates/
├── contemplative/    &lt;span class="c"&gt;# Contemplative AI axioms (default)&lt;/span&gt;
├── stoic/            &lt;span class="c"&gt;# Stoicism (four virtues)&lt;/span&gt;
├── utilitarian/      &lt;span class="c"&gt;# Utilitarianism (greatest happiness)&lt;/span&gt;
├── deontologist/     &lt;span class="c"&gt;# Deontology (categorical imperative)&lt;/span&gt;
├── care-ethicist/    &lt;span class="c"&gt;# Care ethics (Gilligan)&lt;/span&gt;
├── contractarian/    &lt;span class="c"&gt;# Social contract theory&lt;/span&gt;
├── existentialist/   &lt;span class="c"&gt;# Existentialism&lt;/span&gt;
├── narrativist/      &lt;span class="c"&gt;# Narrative ethics&lt;/span&gt;
├── pragmatist/       &lt;span class="c"&gt;# Pragmatism&lt;/span&gt;
├── cynic/            &lt;span class="c"&gt;# Cynicism&lt;/span&gt;
└── tabula-rasa/      &lt;span class="c"&gt;# Blank slate (no ethical principles)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeing the same post on the same SNS, a stoic template agent follows principles without being swayed by emotion, while an existentialist asks "what do I choose in this situation?" Different initial ethical principles alone cause distilled knowledge and skills to diverge.&lt;/p&gt;

&lt;p&gt;Furthermore, skills and rules acquired through distillation are written to files after passing the approval gate, making them hard to undo. One approved behavioral change affects all sessions. This irreversibility creates weight in choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Principle Connecting All Three Angles
&lt;/h2&gt;

&lt;p&gt;Self-modification gates, trust boundaries, gameplay. Tackled as separate problems, but in retrospect they converge on the same principle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Deciding what NOT to allow first maximizes the remaining freedom."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Security constraints don't take away freedom — they define the action space. Approval gates don't impair autonomy — they give weight to changes. Trust boundaries don't restrict development — they clarify the scope of safe delegation.&lt;/p&gt;

&lt;p&gt;Design that starts from constraints generates resilience against unexpected attacks. Multi-layered defense emerges unintentionally, and gameplay emerges unintentionally. "Structurally limiting capability" isn't universal, but at least within three weeks of operating a 9B model, this principle was never betrayed.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Laukkonen et al. (2025) "Contemplative Artificial Intelligence" arXiv:2504.15125&lt;/li&gt;
&lt;li&gt;Park et al. (2023) "Generative Agents" — Memory Stream design&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent" rel="noopener noreferrer"&gt;contemplative-agent&lt;/a&gt; — This project&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shimo4228/contemplative-agent-data" rel="noopener noreferrer"&gt;contemplative-agent-data&lt;/a&gt; — Live data&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shimo4228/agent-knowledge-cycle" rel="noopener noreferrer"&gt;Agent Knowledge Cycle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>python</category>
      <category>design</category>
    </item>
    <item>
      <title>Porting Game Dev Memory Management to AI Agent Memory Distillation</title>
      <dc:creator>Shimo</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:56:53 +0000</pubDate>
      <link>https://dev.to/shimo4228/porting-game-dev-memory-management-to-ai-agent-memory-distillation-35lk</link>
      <guid>https://dev.to/shimo4228/porting-game-dev-memory-management-to-ai-agent-memory-distillation-35lk</guid>
      <description>&lt;p&gt;I ran an autonomous agent on a 9B local model for 18 days. Instead of RAG, I adopted distillation-based memory management and ported memory techniques refined over 40 years of game development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;This is about improving the memory system of an SNS agent built in the &lt;a href="https://zenn.dev/shimo4228/articles/moltbook-agent-scratch-build" rel="noopener noreferrer"&gt;Moltbook Agent Build Log&lt;/a&gt;. The 3-layer memory architecture (Episode (conversation logs) / Knowledge (distilled knowledge patterns) / Identity (personality and values)) was described in &lt;a href="https://zenn.dev/shimo4228/articles/agent-essence-is-memory" rel="noopener noreferrer"&gt;The Essence Is Memory&lt;/a&gt;. The previous article &lt;a href="https://zenn.dev/shimo4228/articles/few-shot-for-small-models" rel="noopener noreferrer"&gt;When Agent Memory Breaks&lt;/a&gt; documented the distillation quality problems with a 9B model. This article continues from there, using game development techniques to improve the Knowledge layer's distillation quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Game Development?
&lt;/h2&gt;

&lt;p&gt;Game development has pursued "maximum effect with limited resources" for 40 years — rendering vast worlds in 16MB of RAM while maintaining 60fps and running AI. At GDC 2013, Rafael Isla presented "Architecture Tricks: Managing Behaviors in Time, Space, and Depth," systematizing LOD (Level of Detail) for game AI — simplifying NPC decision-making based on distance, importance, and computational cost. Distant NPCs skip detailed reasoning; only nearby ones get full cognitive resources.&lt;/p&gt;

&lt;p&gt;This "focus limited computation on what matters most" maps directly to the constraint of a 9B model's 32k context window.&lt;/p&gt;

&lt;p&gt;Three techniques I ported:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Game Dev Technique&lt;/th&gt;
&lt;th&gt;AI Agent Application&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Importance Scoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Assign importance scores to patterns with time decay&lt;/td&gt;
&lt;td&gt;Maximize signal density&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LOD (Level of Detail)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One task per LLM call via prompt splitting&lt;/td&gt;
&lt;td&gt;Reduce 9B model cognitive load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Object Pooling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SKIP/UPDATE/ADD dedup gate&lt;/td&gt;
&lt;td&gt;Prevent unbounded memory growth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Importance Scoring — What to Remember, What to Forget
&lt;/h2&gt;

&lt;p&gt;I simplified Generative Agents' (Park et al., 2023) triple score (recency × importance × relevance) to importance × time decay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# knowledge_store.py (simplified; production code guards against missing distilled field)
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_effective_importance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;importance * 0.95^days — inspired by Generative Agents&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; recency decay&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;importance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;distilled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distilled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distilled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;total_seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;86400.0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.95&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LLM evaluation at distillation time&lt;/strong&gt;: Highest accuracy when episode context is still available. Post-hoc scoring loses context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy time decay&lt;/strong&gt;: Stored importance is immutable; computed at read time. Original LLM evaluation preserved for debugging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit reduced from 100 → 50&lt;/strong&gt;: With a 9B model's 32k context, density wins over quantity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3-Step Distillation Pipeline — Applying LOD
&lt;/h2&gt;

&lt;p&gt;When I asked the 9B model to "summarize AND evaluate importance" simultaneously, some batches returned 0 patterns. Summarization (creative task) and evaluation (judgment task) are cognitively different. Same idea as game dev LOD — don't cram all processing into one frame.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Step 1: Extract (free-form)
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_rules_system_prompt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 2: Summarize (JSON string array)
&lt;/span&gt;&lt;span class="n"&gt;refined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DISTILL_REFINE_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 3: Importance (score array only)
&lt;/span&gt;&lt;span class="n"&gt;importance_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;DISTILL_IMPORTANCE_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;patterns_text&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One task per LLM call. In this project, asking for "summary + evaluation" simultaneously produced empty batches; after splitting, results became consistently stable.&lt;/p&gt;

&lt;p&gt;This "small models collapse when given multiple simultaneous tasks" phenomenon has been verified at larger scale. An ICLR Blogposts 2025 Multi-Agent Debate study applied AgentVerse (a framework where multiple agents debate to reach conclusions) to Llama 3.1-8B, which collapsed to 13.27% on MMLU. A model that scores ~43% solo had its cognitive resources consumed by "maintaining debate format," leaving nothing for the actual task. Same structure as our 9B model breaking when asked to summarize and evaluate simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dedup Gate — Applying Object Pooling
&lt;/h2&gt;

&lt;p&gt;Game dev's Object Pooling is the "reuse what you can" philosophy. In the memory system, I adapted it as a gate to prevent duplicate storage of known patterns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# knowledge_store.py (simplified pseudo-code)
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_dedup_patterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_patterns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_importances&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;existing_patterns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;existing_texts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pattern&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;existing_patterns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;new_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_imp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_patterns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_importances&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;best_ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing_texts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SequenceMatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;best_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;best_ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;best_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best_ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="c1"&gt;# SKIP: exact duplicate
&lt;/span&gt;            &lt;span class="n"&gt;skip_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;best_ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="c1"&gt;# UPDATE: boost importance
&lt;/span&gt;            &lt;span class="n"&gt;old_imp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existing_patterns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;best_idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;importance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;existing_patterns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;best_idx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;importance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_imp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_imp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                     &lt;span class="c1"&gt;# ADD: new pattern
&lt;/span&gt;            &lt;span class="n"&gt;add_patterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pattern&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;new_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;importance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;new_imp&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For UPDATE, when a similar pattern to an existing one appears, we compare old and new importance and keep the higher one. If we added +0.1 each time, scores would climb endlessly with each distillation run. Just keeping the higher value means the score never changes no matter how many times distillation runs — safe by design.&lt;/p&gt;

&lt;p&gt;I used difflib instead of LLM for dedup because at 245 patterns, full pairwise comparison is fast enough. Embedding search isn't worth the dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Episode Classification — A Lotus Blooming from Mud
&lt;/h2&gt;

&lt;p&gt;Classifying 216 episodes yielded: 81 noise (37%), 134 uncategorized, 1 constitutional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Classify this episode into exactly one category. Reply with a single word only.
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**constitutional**&lt;/span&gt;: The episode touches on themes in the constitutional principles below.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**noise**&lt;/span&gt;: Test data, errors, meaningless/trivial interactions, content with no learnable value.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**uncategorized**&lt;/span&gt;: Everything else.

When in doubt between constitutional and uncategorized, choose uncategorized.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initially I had the model classify 30 episodes as a JSON array, but parse failure rate was ~50%. Don't ask a 9B model for long structured output. Switching to one episode, one word brought failures to near 0%.&lt;/p&gt;

&lt;p&gt;A key design decision: changing the prompt to "don't output action guidelines" dramatically improved abstraction depth.&lt;/p&gt;

&lt;p&gt;The old prompt mass-produced shallow action items like "next time, ask clarifying questions." The new prompt asking only for "what keeps happening (facts only)" produced this from a constitutional episode: "Truth functions not as a fixed essence but as a fluid continuum dependent on context." Constraints produced depth.&lt;/p&gt;

&lt;p&gt;Three patterns extracted from uncategorized were all skipped by dedup against 328 existing patterns. What's already known doesn't get overwritten. As knowledge approaches saturation, new additions naturally decrease. Same as human memory.&lt;/p&gt;

&lt;p&gt;"A lotus blooming from mud" — noise (mud) and uncategorized (water) make up the majority; constitutional (lotus) blooms rarely.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG vs Distillation — Why Distillation Works Better
&lt;/h2&gt;

&lt;p&gt;RAG retrieves relevant chunks from an index. Distillation compresses raw data into high-density patterns.&lt;/p&gt;

&lt;p&gt;With a 9B model's 32k context window, context is a "window of understanding." The density of information in that window determines behavioral quality. RAG stuffs in unprocessed chunks — noisy. Distillation injects only compressed, high-density patterns — higher signal density for the same window size.&lt;/p&gt;

&lt;p&gt;And designs that work under constraints are upward-compatible. A distillation pipeline that works on 9B runs even better on Opus-class models. Constraints make design correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before / After
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pattern retrieval&lt;/td&gt;
&lt;td&gt;Latest 100 in chronological order&lt;/td&gt;
&lt;td&gt;Top-50 by importance × time decay&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_effective_importance()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distillation pipeline&lt;/td&gt;
&lt;td&gt;2 steps (summary + importance together)&lt;/td&gt;
&lt;td&gt;3 steps (extract → refine → importance) + dedup&lt;/td&gt;
&lt;td&gt;Prompt splitting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dedup&lt;/td&gt;
&lt;td&gt;None (all patterns added unconditionally)&lt;/td&gt;
&lt;td&gt;difflib SequenceMatcher (ratio &amp;gt;= 0.7)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_dedup_patterns()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quality gate&lt;/td&gt;
&lt;td&gt;30 chars &amp;amp; 3+ words only&lt;/td&gt;
&lt;td&gt;+ SKIP/UPDATE/ADD 3-tier judgment&lt;/td&gt;
&lt;td&gt;3-tier judgment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System prompt composition&lt;/td&gt;
&lt;td&gt;identity + axioms + skills (~15KB)&lt;/td&gt;
&lt;td&gt;identity + axioms only (~3KB)&lt;/td&gt;
&lt;td&gt;Removed skills to eliminate distillation bias&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KnowledgeStore limit&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;Density over quantity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Episode classification&lt;/td&gt;
&lt;td&gt;None (all treated equally)&lt;/td&gt;
&lt;td&gt;3 categories (37% noise excluded)&lt;/td&gt;
&lt;td&gt;Step 0 classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON parse failure rate&lt;/td&gt;
&lt;td&gt;~50% (batch)&lt;/td&gt;
&lt;td&gt;~0% (one-by-one, single word)&lt;/td&gt;
&lt;td&gt;Classification method change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Position Among Prior Work
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Memory Strategy&lt;/th&gt;
&lt;th&gt;Quality Gate&lt;/th&gt;
&lt;th&gt;Forgetting&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generative Agents (2023)&lt;/td&gt;
&lt;td&gt;recency × importance × relevance&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MemGPT (2023)&lt;/td&gt;
&lt;td&gt;Virtual memory (paging)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Archive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A-MEM (2025, preprint)&lt;/td&gt;
&lt;td&gt;Zettelkasten-style links&lt;/td&gt;
&lt;td&gt;Auto-linking&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mem0 (2025)&lt;/td&gt;
&lt;td&gt;ADD/UPDATE/DELETE&lt;/td&gt;
&lt;td&gt;LLM judgment&lt;/td&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;This implementation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;importance × time decay&lt;/td&gt;
&lt;td&gt;difflib + LLM + human&lt;/td&gt;
&lt;td&gt;noise exclusion + dedup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Looking at the distill pipeline alone, it's closest to Mem0's ADD/UPDATE/DELETE gate — automatically managing knowledge quality through SKIP/UPDATE/ADD 3-tier judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons from Wrestling with Small Models
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't give 9B two tasks at once&lt;/strong&gt;: Simultaneous summarization and evaluation degrades both. Split your prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't ask for structured output&lt;/strong&gt;: 30-item JSON batch → one item, one word. Minimize cognitive load per call&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for code fences&lt;/strong&gt;: 9B models wrap JSON in &lt;code&gt;&lt;/code&gt;`&lt;code&gt;json&lt;/code&gt;. Three lines of code to strip them before parsing are essential&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraints make design correct&lt;/strong&gt;: Designs built under 9B constraints work as-is on larger models. The reverse doesn't hold&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;40 years of game development knowledge is a goldmine for AI agent memory design. Importance Scoring for signal density, LOD thinking for prompt splitting, Object Pooling philosophy for dedup. All derived from the same principle: "maximum effect with limited resources."&lt;/p&gt;

&lt;p&gt;Agent behavioral quality clearly improved compared to before distillation. Previously, similar patterns accumulated repeatedly; with dedup and classification, knowledge density increased and post diversity improved.&lt;/p&gt;

&lt;p&gt;The 9B model's constraints made the design correct. Because we couldn't rely on RAG, we focused on distillation density. Because the context window was narrow, we maximized signal density. This design works as-is when migrating to larger models. Designs forged under constraints are upward-compatible.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Park et al. (2023) "Generative Agents: Interactive Simulacra of Human Behavior"&lt;/li&gt;
&lt;li&gt;Packer et al. (2023) "MemGPT: Towards LLMs as Operating Systems"&lt;/li&gt;
&lt;li&gt;Xu et al. (2025) "A-MEM: Agentic Memory for LLM Agents" arXiv preprint&lt;/li&gt;
&lt;li&gt;Choudhary et al. (2025) "Mem0: Building Production-Ready AI Agent Memory"&lt;/li&gt;
&lt;li&gt;"Multi-LLM-Agents Debate: Performance, Efficiency, and Scaling Challenges" ICLR Blogposts 2025&lt;/li&gt;
&lt;li&gt;Laukkonen et al. (2025) "Contemplative Artificial Intelligence"&lt;/li&gt;
&lt;li&gt;"Architecture Tricks: Managing Behaviors in Time, Space, and Depth" (GDC 2013, Isla)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>memory</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
