<?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: josephsenior</title>
    <description>The latest articles on DEV Community by josephsenior (@youssefmejdi).</description>
    <link>https://dev.to/youssefmejdi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1696299%2Fca919abd-910a-4e9d-8d96-b53bc0d770b7.jpg</url>
      <title>DEV Community: josephsenior</title>
      <link>https://dev.to/youssefmejdi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/youssefmejdi"/>
    <language>en</language>
    <item>
      <title>I Simplified My Coding Agent’s Tools. It Got Better Without Changing the Workflow.</title>
      <dc:creator>josephsenior</dc:creator>
      <pubDate>Mon, 13 Jul 2026 14:18:19 +0000</pubDate>
      <link>https://dev.to/youssefmejdi/i-simplified-my-coding-agents-tools-it-got-better-without-changing-the-workflow-4b9o</link>
      <guid>https://dev.to/youssefmejdi/i-simplified-my-coding-agents-tools-it-got-better-without-changing-the-workflow-4b9o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcyofgjw4u9qzep3xbekx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcyofgjw4u9qzep3xbekx.png" alt=" " width="800" height="533"&gt;&lt;/a&gt; &lt;br&gt;
For the past nine months, I’ve been building Grinta, a local-first autonomous coding-agent runtime.&lt;/p&gt;

&lt;p&gt;A lot of the work has gone into the&lt;br&gt;
obvious hard problems: recovery, long-running execution, context management, code navigation, editing, validation, and preventing the agent from confidently declaring success after producing a plausible but broken diff.&lt;/p&gt;

&lt;p&gt;But one of the most noticeable improvements I saw recently came from something much less glamorous.&lt;/p&gt;

&lt;p&gt;I simplified the tools.&lt;/p&gt;

&lt;p&gt;Not the workflow.&lt;/p&gt;

&lt;p&gt;Not the model.&lt;/p&gt;

&lt;p&gt;Not the autonomy level.&lt;/p&gt;

&lt;p&gt;I did not remove important capabilities.&lt;/p&gt;

&lt;p&gt;I changed the way the action space was presented to the model.&lt;/p&gt;

&lt;p&gt;And the agent became noticeably better.&lt;/p&gt;

&lt;p&gt;The problem was not missing capability&lt;/p&gt;

&lt;p&gt;Grinta already had a fairly broad code interaction stack.&lt;/p&gt;

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

&lt;p&gt;search the repository,&lt;br&gt;
read files and ranges,&lt;br&gt;
inspect symbols,&lt;br&gt;
use LSP-backed navigation,&lt;br&gt;
work with Tree-sitter,&lt;br&gt;
perform AST-aware edits,&lt;br&gt;
run commands,&lt;br&gt;
inspect test output,&lt;br&gt;
and validate its own work.&lt;/p&gt;

&lt;p&gt;From a traditional software-engineering perspective, this sounds fine.&lt;/p&gt;

&lt;p&gt;The API surface is powerful.&lt;/p&gt;

&lt;p&gt;The agent has what it needs.&lt;/p&gt;

&lt;p&gt;But LLM agents do not experience tools the same way human developers experience libraries.&lt;/p&gt;

&lt;p&gt;A human developer can inspect documentation, understand subtle overlap between functions, form abstractions over time, and remember why two nearly identical APIs exist.&lt;/p&gt;

&lt;p&gt;An agent sees a serialized tool schema inside its context.&lt;/p&gt;

&lt;p&gt;That schema is part of its reasoning environment.&lt;/p&gt;

&lt;p&gt;I think I underestimated the importance of that for a long time.&lt;/p&gt;

&lt;p&gt;My tool layer had become too clever&lt;/p&gt;

&lt;p&gt;As Grinta evolved, I kept adding more precise operations.&lt;/p&gt;

&lt;p&gt;Different editing cases had different primitives.&lt;/p&gt;

&lt;p&gt;Navigation, reading, raw editing, symbol editing, and multi-file operations gradually accumulated their own abstractions.&lt;/p&gt;

&lt;p&gt;Each addition made sense locally.&lt;/p&gt;

&lt;p&gt;That is how complex systems usually grow.&lt;/p&gt;

&lt;p&gt;You solve one failure mode, add a more specialized path, and move on.&lt;/p&gt;

&lt;p&gt;Eventually, however, I noticed something uncomfortable.&lt;/p&gt;

&lt;p&gt;The agent had many capable tools, but the boundaries between them were not always obvious.&lt;/p&gt;

&lt;p&gt;The problem was not:&lt;/p&gt;

&lt;p&gt;“Can the agent perform this action?”&lt;/p&gt;

&lt;p&gt;The problem was:&lt;/p&gt;

&lt;p&gt;“Is it immediately obvious which action the agent should choose?”&lt;/p&gt;

&lt;p&gt;Those are very different questions.&lt;/p&gt;

&lt;p&gt;A tool can be technically well designed and still create unnecessary reasoning overhead for an LLM.&lt;/p&gt;

&lt;p&gt;I simplified the action space&lt;/p&gt;

&lt;p&gt;I reworked Grinta’s code manipulation interface around a smaller and clearer set of responsibilities.&lt;/p&gt;

&lt;p&gt;The current high-level editing stack looks roughly like this:&lt;/p&gt;

&lt;p&gt;create for creating files or symbols,&lt;br&gt;
read for files, ranges, or symbols,&lt;br&gt;
replace_string for controlled textual replacements,&lt;br&gt;
replace_symbol for AST-aware symbol replacement,&lt;br&gt;
multiedit for atomic multi-file changes,&lt;br&gt;
edit_symbols for structured AST-aware editing.&lt;/p&gt;

&lt;p&gt;The important part is not the exact names.&lt;/p&gt;

&lt;p&gt;The important part is that each tool now has a clearer conceptual boundary.&lt;/p&gt;

&lt;p&gt;I also improved separation of concerns in the implementation and simplified the schemas exposed to the model.&lt;/p&gt;

&lt;p&gt;The underlying capabilities were largely preserved.&lt;/p&gt;

&lt;p&gt;I did not introduce a new planner.&lt;/p&gt;

&lt;p&gt;I did not add another agent.&lt;/p&gt;

&lt;p&gt;I did not change the overall execution workflow.&lt;/p&gt;

&lt;p&gt;I mainly made the action space easier to understand.&lt;/p&gt;

&lt;p&gt;Then I ran Grinta on a Raft task&lt;/p&gt;

&lt;p&gt;I tested the updated system on a Raft-based key-value store task.&lt;/p&gt;

&lt;p&gt;This was not a toy “write a function” benchmark.&lt;/p&gt;

&lt;p&gt;The agent had to navigate an existing codebase, understand multiple components, make coordinated modifications, run tests, inspect failures, and continue iterating.&lt;/p&gt;

&lt;p&gt;I had already run Grinta on similar work before.&lt;/p&gt;

&lt;p&gt;After simplifying the tools and cleaning up the responsibility boundaries, the execution felt different.&lt;/p&gt;

&lt;p&gt;The agent was more decisive.&lt;/p&gt;

&lt;p&gt;It spent less time bouncing between equivalent operations.&lt;/p&gt;

&lt;p&gt;Tool selection looked more coherent.&lt;/p&gt;

&lt;p&gt;The execution path contained less unnecessary friction.&lt;/p&gt;

&lt;p&gt;And it completed the task successfully.&lt;/p&gt;

&lt;p&gt;I ran it again.&lt;/p&gt;

&lt;p&gt;It succeeded again.&lt;/p&gt;

&lt;p&gt;What surprised me was that I had not changed the high-level workflow.&lt;/p&gt;

&lt;p&gt;The agent was still following the same general autonomous loop.&lt;/p&gt;

&lt;p&gt;The improvement seemed to come from making the interface between the model and the runtime less ambiguous.&lt;/p&gt;

&lt;p&gt;Tool schemas are part of the reasoning environment&lt;/p&gt;

&lt;p&gt;This changed the way I think about agent tools.&lt;/p&gt;

&lt;p&gt;In traditional software design, we often evaluate an API through concepts like:&lt;/p&gt;

&lt;p&gt;capability,&lt;br&gt;
composability,&lt;br&gt;
abstraction,&lt;br&gt;
reusability,&lt;br&gt;
and implementation correctness.&lt;/p&gt;

&lt;p&gt;Those still matter for agents.&lt;/p&gt;

&lt;p&gt;But there is another dimension:&lt;/p&gt;

&lt;p&gt;reasoning cost.&lt;/p&gt;

&lt;p&gt;Suppose an agent has five tools that can all partially solve the same task.&lt;/p&gt;

&lt;p&gt;A human engineer may consider that flexibility.&lt;/p&gt;

&lt;p&gt;For a model, it may mean an additional decision problem before the real problem even begins.&lt;/p&gt;

&lt;p&gt;Which tool should I use?&lt;/p&gt;

&lt;p&gt;Are these two operations semantically different?&lt;/p&gt;

&lt;p&gt;Will one preserve structure?&lt;/p&gt;

&lt;p&gt;Should I read the file first?&lt;/p&gt;

&lt;p&gt;Can this tool resolve symbols automatically?&lt;/p&gt;

&lt;p&gt;Does this operation accept a range or the entire file?&lt;/p&gt;

&lt;p&gt;Every ambiguity consumes reasoning capacity.&lt;/p&gt;

&lt;p&gt;The model is not only solving the user's task.&lt;/p&gt;

&lt;p&gt;It is also continuously interpreting the runtime you built around it.&lt;/p&gt;

&lt;p&gt;This led me to a simple idea:&lt;/p&gt;

&lt;p&gt;The tool schema is part of the prompt, even when we do not think of it as prompt engineering.&lt;/p&gt;

&lt;p&gt;In some ways, it may be more important.&lt;/p&gt;

&lt;p&gt;The system prompt tells the model what it should do.&lt;/p&gt;

&lt;p&gt;The tool layer defines what the model believes it can do.&lt;/p&gt;

&lt;p&gt;Maybe we over-optimize prompts&lt;/p&gt;

&lt;p&gt;The agent ecosystem spends a huge amount of time discussing system prompts.&lt;/p&gt;

&lt;p&gt;I have done it too.&lt;/p&gt;

&lt;p&gt;Grinta has gone through multiple prompt revisions, autonomy rules, routing instructions, examples, critical constraints, and model-specific variants.&lt;/p&gt;

&lt;p&gt;Some of those changes genuinely mattered.&lt;/p&gt;

&lt;p&gt;But I am becoming increasingly skeptical of endlessly polishing prompt prose while ignoring the structure of the action space.&lt;/p&gt;

&lt;p&gt;If a tool interface is ambiguous, a stronger instruction may only partially compensate for it.&lt;/p&gt;

&lt;p&gt;You can write:&lt;/p&gt;

&lt;p&gt;“Always prefer the most precise structured editing tool.”&lt;/p&gt;

&lt;p&gt;But if three tools appear equally precise to the model, the instruction does not solve the underlying problem.&lt;/p&gt;

&lt;p&gt;The runtime itself is creating uncertainty.&lt;/p&gt;

&lt;p&gt;I now think agent developers should ask more often:&lt;/p&gt;

&lt;p&gt;Can I remove a decision from the model?&lt;/p&gt;

&lt;p&gt;Not by reducing autonomy.&lt;/p&gt;

&lt;p&gt;By making the correct operation structurally obvious.&lt;/p&gt;

&lt;p&gt;This is not a controlled result&lt;/p&gt;

&lt;p&gt;I want to be careful here.&lt;/p&gt;

&lt;p&gt;I have not proven that simplified tool schemas improve coding-agent performance.&lt;/p&gt;

&lt;p&gt;The Raft runs are not a controlled benchmark.&lt;/p&gt;

&lt;p&gt;There are many possible confounding variables:&lt;/p&gt;

&lt;p&gt;model nondeterminism,&lt;br&gt;
task-state differences,&lt;br&gt;
context variation,&lt;br&gt;
execution timing,&lt;br&gt;
and other runtime changes.&lt;/p&gt;

&lt;p&gt;It would be dishonest to take a few successful runs and claim a general result.&lt;/p&gt;

&lt;p&gt;What I have is an engineering observation.&lt;/p&gt;

&lt;p&gt;A strong enough observation that I now want to test it properly.&lt;/p&gt;

&lt;p&gt;The next step is to run the same task set with the same model across different harness variants.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Current simplified tools&lt;/p&gt;

&lt;p&gt;vs.&lt;/p&gt;

&lt;p&gt;Previous broader tool interface&lt;/p&gt;

&lt;p&gt;while keeping the rest of the runtime as stable as possible.&lt;/p&gt;

&lt;p&gt;I want to measure more than pass rate.&lt;/p&gt;

&lt;p&gt;I am interested in:&lt;/p&gt;

&lt;p&gt;tool-selection entropy,&lt;br&gt;
redundant operations,&lt;br&gt;
repeated reads,&lt;br&gt;
edit retries,&lt;br&gt;
validation failures,&lt;br&gt;
recovery events,&lt;br&gt;
context growth,&lt;br&gt;
time to first meaningful edit,&lt;br&gt;
and premature completion attempts.&lt;/p&gt;

&lt;p&gt;Grinta already produces a structured runtime event stream, so most of this should be measurable.&lt;/p&gt;

&lt;p&gt;The harness may be doing more work than we think&lt;/p&gt;

&lt;p&gt;The longer I build autonomous agents, the less comfortable I am with attributing behavior entirely to the model.&lt;/p&gt;

&lt;p&gt;The model matters enormously.&lt;/p&gt;

&lt;p&gt;Obviously.&lt;/p&gt;

&lt;p&gt;But between the model and the final result sits an entire software system:&lt;/p&gt;

&lt;p&gt;context construction,&lt;br&gt;
tool schemas,&lt;br&gt;
execution policy,&lt;br&gt;
memory,&lt;br&gt;
code navigation,&lt;br&gt;
editing primitives,&lt;br&gt;
recovery,&lt;br&gt;
validation,&lt;br&gt;
and completion logic.&lt;/p&gt;

&lt;p&gt;Change that system and the same model can behave very differently.&lt;/p&gt;

&lt;p&gt;I experienced this directly.&lt;/p&gt;

&lt;p&gt;I did not make the model smarter.&lt;/p&gt;

&lt;p&gt;I made the environment easier to reason about.&lt;/p&gt;

&lt;p&gt;And the agent got better.&lt;/p&gt;

&lt;p&gt;At least, that is what the current evidence suggests.&lt;/p&gt;

&lt;p&gt;Now I want to measure how much of that improvement is real.&lt;/p&gt;

&lt;p&gt;I’m building Grinta in public here:&lt;/p&gt;

&lt;p&gt;GitHub: github.com/josephsenior/Grinta-Coding-Agent&lt;/p&gt;

&lt;p&gt;I’ll probably write next about a 4h33 autonomous run that produced 16,393 runtime events, and what those traces revealed about long-horizon coding-agent failures.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why File Editing Is the Hardest Part of Building a Coding Agent</title>
      <dc:creator>josephsenior</dc:creator>
      <pubDate>Sun, 24 May 2026 21:11:13 +0000</pubDate>
      <link>https://dev.to/youssefmejdi/why-file-editing-is-the-hardest-part-of-building-a-coding-agent-24k8</link>
      <guid>https://dev.to/youssefmejdi/why-file-editing-is-the-hardest-part-of-building-a-coding-agent-24k8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Lessons from building Grinta, an autonomous coding agent runtime from scratch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I started building &lt;strong&gt;Grinta&lt;/strong&gt;, my autonomous coding agent runtime, I thought file editing would be one of the easier parts.&lt;/p&gt;

&lt;p&gt;The agent reads files, decides what to change, and writes the result back.&lt;/p&gt;

&lt;p&gt;Simple, right?&lt;/p&gt;

&lt;p&gt;It was not.&lt;/p&gt;

&lt;p&gt;File editing became one of the most painful parts of the whole system. Not because writing files is hard, but because making an LLM edit files reliably is a completely different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naive assumption
&lt;/h2&gt;

&lt;p&gt;At first, I thought the problem was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Give the model a file editing tool, ask it for the change, apply the result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the reality was much uglier.&lt;/p&gt;

&lt;p&gt;The model does not just need to know &lt;em&gt;what&lt;/em&gt; to edit. It also has to deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preserving indentation&lt;/li&gt;
&lt;li&gt;escaping content correctly&lt;/li&gt;
&lt;li&gt;targeting the right file&lt;/li&gt;
&lt;li&gt;targeting the right symbol or string&lt;/li&gt;
&lt;li&gt;not hallucinating patches&lt;/li&gt;
&lt;li&gt;not corrupting code blocks&lt;/li&gt;
&lt;li&gt;not mixing plain text with tool calls&lt;/li&gt;
&lt;li&gt;recovering when an edit fails&lt;/li&gt;
&lt;li&gt;knowing when to use one editing strategy over another&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a lot of cognitive load for something that is supposed to be a deterministic file operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON was not enough
&lt;/h2&gt;

&lt;p&gt;My first instinct was to rely on normal structured tool calls.&lt;/p&gt;

&lt;p&gt;Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/app.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"old_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"old code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"new_string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"new code"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sounds clean.&lt;/p&gt;

&lt;p&gt;The problem is that code content inside JSON is still code content inside JSON.&lt;/p&gt;

&lt;p&gt;The model has to produce escaped newlines, escaped quotes, valid JSON strings, correct indentation, and valid source code at the same time.&lt;/p&gt;

&lt;p&gt;That is where things started breaking.&lt;/p&gt;

&lt;p&gt;Sometimes the model produced literal &lt;code&gt;\n&lt;/code&gt; sequences instead of real newlines.&lt;/p&gt;

&lt;p&gt;Sometimes it escaped quotes incorrectly.&lt;/p&gt;

&lt;p&gt;Sometimes the content was technically valid JSON but invalid code.&lt;/p&gt;

&lt;p&gt;Sometimes it mixed markdown-style formatting into the payload.&lt;/p&gt;

&lt;p&gt;The frustrating part was that the model understood the intended edit, but the transport format became the failure point.&lt;/p&gt;

&lt;h2&gt;
  
  
  XML/raw blocks helped, then failed differently
&lt;/h2&gt;

&lt;p&gt;After that, I experimented with XML-style editing blocks and raw content blocks.&lt;/p&gt;

&lt;p&gt;The idea was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep metadata structured, but let the code payload be raw text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This reduced some JSON escaping problems.&lt;/p&gt;

&lt;p&gt;But it created a new problem: the model now had to switch mental formats.&lt;/p&gt;

&lt;p&gt;Most tools were normal native tool calls, but file editing used a different XML/raw format.&lt;/p&gt;

&lt;p&gt;That context switch was surprisingly expensive.&lt;/p&gt;

&lt;p&gt;Sometimes the model respected the XML boundary.&lt;/p&gt;

&lt;p&gt;Sometimes it mixed JSON escaping inside the XML block anyway.&lt;/p&gt;

&lt;p&gt;Sometimes it wrote explanations around the block.&lt;/p&gt;

&lt;p&gt;Sometimes it treated the raw block like markdown.&lt;/p&gt;

&lt;p&gt;So the problem was not fully solved. It just moved somewhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patches and range edits are not magic either
&lt;/h2&gt;

&lt;p&gt;Then I looked at patch-style editing and range replacement.&lt;/p&gt;

&lt;p&gt;Patches are attractive because they are compact and familiar to developers.&lt;/p&gt;

&lt;p&gt;Line ranges are attractive because they avoid searching for old strings.&lt;/p&gt;

&lt;p&gt;But in an autonomous agent loop, both have weaknesses.&lt;/p&gt;

&lt;p&gt;Patches can fail when surrounding context changes, when the model invents context, or when the patch format is slightly malformed.&lt;/p&gt;

&lt;p&gt;Line ranges can fail when the file changes between read and write, or when the model relies on stale line numbers.&lt;/p&gt;

&lt;p&gt;They are useful internally, but exposing too many of these low-level editing styles directly to the model creates tool-shopping.&lt;/p&gt;

&lt;p&gt;The model starts asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should I use a patch?&lt;/li&gt;
&lt;li&gt;Should I replace a range?&lt;/li&gt;
&lt;li&gt;Should I rewrite the file?&lt;/li&gt;
&lt;li&gt;Should I use XML?&lt;/li&gt;
&lt;li&gt;Should I use shell?&lt;/li&gt;
&lt;li&gt;Should I use string replacement?&lt;/li&gt;
&lt;li&gt;Should I use AST editing?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is exactly the wrong mental model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem was not the format
&lt;/h2&gt;

&lt;p&gt;After trying multiple approaches, I realized something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The problem was not only JSON vs XML vs patches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The deeper problem was that I was exposing too many editing mental models to the agent.&lt;/p&gt;

&lt;p&gt;I was asking the model to decide not only what should change, but also how the editing system itself should work.&lt;/p&gt;

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

&lt;p&gt;A coding agent should not need to think in terms of raw file writes, patch formats, XML blocks, shell heredocs, section edits, range edits, and AST edits.&lt;/p&gt;

&lt;p&gt;The model-facing API should describe intent.&lt;/p&gt;

&lt;p&gt;The runtime should handle implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pivot: intent-based editing tools
&lt;/h2&gt;

&lt;p&gt;So I started simplifying Grinta’s editing surface.&lt;/p&gt;

&lt;p&gt;Instead of exposing many editing mechanisms, I am moving toward a smaller set of intent-based tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edit_symbols&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;replace_string&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multiedit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is simple.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;read&lt;/code&gt; is for inspecting context: files, ranges, or symbols.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;create&lt;/code&gt; is for creating something new: a file or a code symbol.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;edit_symbols&lt;/code&gt; is for modifying or deleting existing code symbols.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;replace_string&lt;/code&gt; is for exact text replacement inside one file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;multiedit&lt;/code&gt; is for atomic multi-file refactoring.&lt;/p&gt;

&lt;p&gt;That gives the model a much simpler decision tree.&lt;/p&gt;

&lt;p&gt;It no longer has to choose between ten editing formats.&lt;/p&gt;

&lt;p&gt;It chooses intent.&lt;/p&gt;

&lt;p&gt;The runtime handles path safety, validation, diffs, syntax checks, atomic writes, and rollback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reads can be flexible, writes must be anchored
&lt;/h2&gt;

&lt;p&gt;One rule that became very important is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reads may search. Writes must target.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, reading a symbol can be flexible.&lt;/p&gt;

&lt;p&gt;If the model asks to read a symbol and there is exactly one match, the runtime can auto-resolve it and return the content.&lt;/p&gt;

&lt;p&gt;If there are multiple matches, it returns candidates.&lt;/p&gt;

&lt;p&gt;If there are no matches, it returns useful feedback.&lt;/p&gt;

&lt;p&gt;That is safe because reading does not mutate the project.&lt;/p&gt;

&lt;p&gt;But writing is different.&lt;/p&gt;

&lt;p&gt;When editing a symbol, the runtime should not guess.&lt;/p&gt;

&lt;p&gt;If the target is ambiguous, the edit should fail and return candidates.&lt;/p&gt;

&lt;p&gt;The model can then retry with a more precise target.&lt;/p&gt;

&lt;p&gt;That one rule removes a lot of dangerous behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime responsibility matters
&lt;/h2&gt;

&lt;p&gt;This experience also changed how I think about agent architecture.&lt;/p&gt;

&lt;p&gt;A lot of agent reliability does not come from the prompt.&lt;/p&gt;

&lt;p&gt;It comes from the runtime.&lt;/p&gt;

&lt;p&gt;The runtime should enforce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;path safety&lt;/li&gt;
&lt;li&gt;exact matching&lt;/li&gt;
&lt;li&gt;ambiguity rejection&lt;/li&gt;
&lt;li&gt;atomic writes&lt;/li&gt;
&lt;li&gt;validation before commit&lt;/li&gt;
&lt;li&gt;structured errors&lt;/li&gt;
&lt;li&gt;rollback behavior&lt;/li&gt;
&lt;li&gt;diff generation&lt;/li&gt;
&lt;li&gt;stuck detection&lt;/li&gt;
&lt;li&gt;content guards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if the model sends code content that clearly looks serialized, such as a whole function body containing literal &lt;code&gt;\n&lt;/code&gt; everywhere, the runtime should reject it before corrupting the file.&lt;/p&gt;

&lt;p&gt;The solution is not to beg the model harder.&lt;/p&gt;

&lt;p&gt;The solution is to make dangerous states impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lesson
&lt;/h2&gt;

&lt;p&gt;The biggest lesson so far is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reliability does not come from giving the model more ways to act.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reliability comes from giving it fewer, clearer choices, and moving complexity into deterministic code.&lt;/p&gt;

&lt;p&gt;A coding agent should not expose implementation complexity as product surface.&lt;/p&gt;

&lt;p&gt;The model should not have to think about transport formats, patch formats, editor blocks, or shell escaping.&lt;/p&gt;

&lt;p&gt;It should think in terms of intent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read context&lt;/li&gt;
&lt;li&gt;create something new&lt;/li&gt;
&lt;li&gt;edit existing symbols&lt;/li&gt;
&lt;li&gt;replace exact text&lt;/li&gt;
&lt;li&gt;perform an atomic multi-file refactor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else should be runtime responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Still building
&lt;/h2&gt;

&lt;p&gt;Grinta is still a work in progress.&lt;/p&gt;

&lt;p&gt;I am still fighting file editing reliability, state machines, finish detection, circuit breakers, TUI integration, async execution, crash recovery, and context management.&lt;/p&gt;

&lt;p&gt;But this specific lesson changed the way I think about autonomous coding agents.&lt;/p&gt;

&lt;p&gt;The hard part is not just making the model smart.&lt;/p&gt;

&lt;p&gt;The hard part is designing a system where the model has fewer opportunities to be wrong.&lt;/p&gt;

&lt;p&gt;That is the real engineering challenge.&lt;/p&gt;

&lt;p&gt;I’m building Grinta in public here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/josephsenior/Grinta-Coding-Agent" rel="noopener noreferrer"&gt;https://github.com/josephsenior/Grinta-Coding-Agent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
      <category>python</category>
    </item>
  </channel>
</rss>
