<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Elixir on paradigmatic.systems</title>
    <link>https://paradigmatic.systems/tags/elixir/</link>
    <description>Recent content in Elixir on paradigmatic.systems</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 10 Aug 2025 04:30:00 +0000</lastBuildDate><atom:link href="https://paradigmatic.systems/tags/elixir/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Three Tiers of Decoupling in Elixir</title>
      <link>https://paradigmatic.systems/posts/behaviors-to-protocols/</link>
      <pubDate>Sun, 10 Aug 2025 04:30:00 +0000</pubDate>
      
      <guid>https://paradigmatic.systems/posts/behaviors-to-protocols/</guid>
      <description>A walk through three progressively stronger tiers of decoupling in Elixir—map conventions, behaviours, and protocols—drawn from a graph-schema library.</description>
      <content:encoded><![CDATA[<p>Allow me to weave you a tale of progressively stronger decoupling in Elixir.</p>
<p>I am working on a library that involves access to graph data, informed by a schema or model. Just to get things rolling I started out with a convention of holding graph nodes in a map:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span>map_graph <span style="color:#f92672">=</span> %{<span style="color:#e6db74">&#34;node1&#34;</span> <span style="color:#f92672">=&gt;</span>
</span></span><span style="display:flex;"><span>          %{<span style="color:#e6db74">&#34;class_id&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;class1&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;data&#34;</span> <span style="color:#f92672">=&gt;</span> %{ <span style="color:#e6db74">&#34;testProp&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;value&#34;</span> }}
</span></span><span style="display:flex;"><span>        %{<span style="color:#e6db74">&#34;node2&#34;</span> <span style="color:#f92672">=&gt;</span>
</span></span><span style="display:flex;"><span>          %{<span style="color:#e6db74">&#34;class_id&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;class1&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;data&#34;</span> <span style="color:#f92672">=&gt;</span> %{ <span style="color:#e6db74">&#34;testProp&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;value2&#34;</span> }}}
</span></span><span style="display:flex;"><span>node <span style="color:#f92672">=</span> map_graph[<span style="color:#e6db74">&#34;node1&#34;</span>]
</span></span><span style="display:flex;"><span>value <span style="color:#f92672">=</span> node[<span style="color:#e6db74">&#34;data&#34;</span>][<span style="color:#e6db74">&#34;testProp&#34;</span>]
</span></span></code></pre></div><p>It&rsquo;s quick, dirty, and gets the job done for proof-of-concept purposes. Clearly it&rsquo;s inadequate for other data access patterns we&rsquo;d like to be able to support. We can write transformation routines against this structure, but they won&rsquo;t be able to work with anything else.</p>
<p>It&rsquo;s time for some decoupling.</p>
<h2 id="behaviors">Behaviors</h2>
<p>A <a href="https://hexdocs.pm/elixir/1.4.5/behaviours.html">Behavior</a> defines an interface or contract that implementing modules must follow. It&rsquo;s like saying &ldquo;if you want to be a graph node accessor, you must implement these functions.&rdquo;</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">Graph</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">@callback</span> get_node(node <span style="color:#f92672">::</span> any()) <span style="color:#f92672">::</span> [any()]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">Graph.MapImpl</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">@behaviour</span> <span style="color:#a6e22e">Graph</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">defstruct</span> [<span style="color:#e6db74">:data</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">@impl</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> get_node(data, node_id) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    data[node_id]
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>Now we can do</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#a6e22e">MapImpl</span><span style="color:#f92672">.</span>get_node(map_graph, <span style="color:#e6db74">&#34;node&#34;</span>)
</span></span></code></pre></div><p>Now we have some added flexibility to define a completely different implementation that dishes up nodes from the filesystem based on a root path:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">Graph.FilesystemImpl</span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">@impl</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> get_node(%{<span style="color:#e6db74">root</span>: root_path}, node_id) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    full_path <span style="color:#f92672">=</span> resolve_path(root_path, node_id)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">case</span> <span style="color:#a6e22e">File</span><span style="color:#f92672">.</span>stat(full_path) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>      {<span style="color:#e6db74">:ok</span>, %<span style="color:#a6e22e">File.Stat</span>{<span style="color:#e6db74">type</span>: <span style="color:#e6db74">:regular</span>}} <span style="color:#f92672">-&gt;</span>
</span></span><span style="display:flex;"><span>        %{
</span></span><span style="display:flex;"><span>          <span style="color:#e6db74">class</span>: <span style="color:#e6db74">&#34;file&#34;</span>,
</span></span><span style="display:flex;"><span>          <span style="color:#e6db74">data</span>: file_data(full_path)
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>      {<span style="color:#e6db74">:ok</span>, %<span style="color:#a6e22e">File.Stat</span>{<span style="color:#e6db74">type</span>: <span style="color:#e6db74">:directory</span>}} <span style="color:#f92672">-&gt;</span>
</span></span><span style="display:flex;"><span>        %{
</span></span><span style="display:flex;"><span>          <span style="color:#e6db74">class</span>: <span style="color:#e6db74">&#34;folder&#34;</span>,
</span></span><span style="display:flex;"><span>          <span style="color:#e6db74">data</span>: folder_data(full_path)
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>      {<span style="color:#e6db74">:error</span>, _} <span style="color:#f92672">-&gt;</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>Notice here the <code>data</code> parameter on <code>get_node/2</code> serves a completely different purpose, instead providing a pointer to where to access the data. This is the first strange smell about this approach.</p>
<p>Now it&rsquo;s possible to write methods that work on either the map or the filesystem implementation. But you still need to know which one you&rsquo;re in, and <code>data</code> needs to be formed correctly:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#a6e22e">MapImpl</span><span style="color:#f92672">.</span>get_node(%{<span style="color:#e6db74">&#34;node&#34;</span> <span style="color:#f92672">=&gt;</span> ...}, <span style="color:#e6db74">&#34;node&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">FileSystemImpl</span><span style="color:#f92672">.</span>get_node(%{<span style="color:#e6db74">&#34;root&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;.&#34;</span>}, <span style="color:#e6db74">&#34;node&#34;</span>)
</span></span></code></pre></div><p>You can make things more convenient with a wrapper struct that carries the implementation and the data, and delegates the functions:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">Graph.Instance</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">@type</span> t <span style="color:#f92672">::</span> <span style="color:#960050;background-color:#1e0010">%</span>__MODULE__{
</span></span><span style="display:flex;"><span>          <span style="color:#e6db74">impl</span>: module(),
</span></span><span style="display:flex;"><span>          <span style="color:#e6db74">data</span>: any()
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> get_node(<span style="color:#960050;background-color:#1e0010">%</span>__MODULE__{<span style="color:#e6db74">impl</span>: impl, <span style="color:#e6db74">data</span>: data}, node_id) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    impl<span style="color:#f92672">.</span>get_node(data, node_id)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>Then you can write transformation routines that work on instances, and are really independent of the underlying representation.</p>
<h2 id="protocols">Protocols</h2>
<p><a href="https://hexdocs.pm/elixir/protocols.html">Protocols</a> provide a different form of decoupling. Here&rsquo;s the equivalent to the Behavior definition from above:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#66d9ef">defprotocol</span> <span style="color:#a6e22e">Graph</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> get_node(data, node_id)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>Then the implementation comes in 2 parts:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">Graph.MapGraph</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">defstruct</span> [<span style="color:#e6db74">:nodes</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> new() <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    <span style="color:#960050;background-color:#1e0010">%</span>__MODULE__{
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">nodes</span>: %{}
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">defimpl</span> <span style="color:#a6e22e">Graph</span>, <span style="color:#e6db74">for</span>: <span style="color:#a6e22e">Graph.MapGraph</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">@impl</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> get_node(%{<span style="color:#e6db74">nodes</span>: graph}, node_id) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    graph[node_id]
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>Now we don&rsquo;t need to pass around the <code>Instance</code> wrapper with its impl. Our transforms are written for &ldquo;anything that can do X&rdquo; rather than &ldquo;modules that promise to do X&rdquo;. The data itself carries the behavior.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span>graph <span style="color:#f92672">=</span> <span style="color:#a6e22e">Graph.MapGraph</span><span style="color:#f92672">.</span>new()
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Graph</span><span style="color:#f92672">.</span>get_node(graph, <span style="color:#e6db74">&#34;node&#34;</span>)
</span></span></code></pre></div><p>The extra cool part is that since the <code>defimpl</code> is separate from the <code>defmodule</code>, you can use protocols to extend existing types. So imagine we have <code>SomeLibrary.DataStructure</code> that could be interpreted as a graph. With Behaviors we would need to write an entire wrapper module. But with protocols we write a <code>defimpl Graph, for: SomeLibrary.DataStructure</code>. Then when we pass that structure to some graph routine, the method calls will look exactly the same:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span>graph <span style="color:#f92672">=</span> <span style="color:#a6e22e">SomeLibrary.DataStructure</span><span style="color:#f92672">.</span>new()
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Graph</span><span style="color:#f92672">.</span>get_node(graph, node)
</span></span></code></pre></div><p>This is a level of decoupling and flexibility that&rsquo;s hard to imagine in traditional OOP languages.</p>
<h2 id="summary">Summary</h2>
<p>With behaviors, you call <code>GraphImpl.get_node(graph, id)</code>. With protocols, you call <code>Graph.get_node(graph, id)</code> regardless of the graph&rsquo;s actual type.</p>
<p><strong>Behaviors</strong> are about modules promising to implement certain functions. The module author decides to follow the behavior contract. Complexity is pushed into the infrastructure.</p>
<p><strong>Protocols</strong> are about data types being extended with new capabilities. You can implement a protocol for any existing type, even ones you didn&rsquo;t create. Complexity is pushed into the type system.</p>
<p>I think there&rsquo;s a nice categorical perspective as well: behaviors as functors in a slice category. Protocols as natural transformations, with the &ldquo;legs&rdquo; provided by the implementation. The naturality condition looks something like</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elixir" data-lang="elixir"><span style="display:flex;"><span>graph <span style="color:#f92672">|&gt;</span> <span style="color:#a6e22e">Graph</span><span style="color:#f92672">.</span>get_node(<span style="color:#e6db74">&#34;node&#34;</span>) <span style="color:#f92672">==</span> graph<span style="color:#f92672">.</span>nodes <span style="color:#f92672">|&gt;</span> <span style="color:#a6e22e">Map</span><span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;node&#34;</span>)
</span></span></code></pre></div><p>But I&rsquo;d need to spend some time with pen and paper to convince myself on this one.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Superfluous Abstractions: The Landscape of LLM Tooling</title>
      <link>https://paradigmatic.systems/posts/superfluous-abstractions/</link>
      <pubDate>Tue, 08 Jul 2025 04:30:00 +0000</pubDate>
      
      <guid>https://paradigmatic.systems/posts/superfluous-abstractions/</guid>
      <description>Cutting through the &amp;#39;Agent&amp;#39; hype: why Elixir/OTP already gives you fault-tolerant LLM pipelines on the BEAM without a bloated framework.</description>
      <content:encoded><![CDATA[<p>Judging by the activity of marketing hypemen and growth hackers, it seems &ldquo;Agents&rdquo; are a Big Important Thing. I can&rsquo;t scroll 2 posts on social media without being offered a course or a low-code service. As usual, the grifters are trailing the edge by a few years. If you try to pin down a definition, it seems to boil down to &ldquo;a distributed, fault-tolerant software system&hellip; with LLM calls&rdquo;. So that means we just need to throw Claude on the <a href="https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)">BEAM</a>. Easy enough! For those willing to read some Elixir code I direct you to a pair of excellent blog posts from 2023:</p>
<p><a href="https://goto-code.com/blog/elixir-otp-for-llms/">Why Elixir/OTP doesn&rsquo;t need an Agent framework: Part 1</a></p>
<p><a href="https://goto-code.com/blog/elixir-otp-for-llms-part-2/">Why Elixir/OTP doesn&rsquo;t need an Agent framework: Part 2</a></p>
<p>Sadly these are his only 2 articles. He makes a few short arguments and then backs it up with a razor-sharp tutorial demonstrating scalable LLM pipelines with minimal dependencies and highly readable code ready to extend with pattern-matching. Where else but Elixir are you going to find such ergonomic code compiling to such a battle-hardened VM?</p>
<p>I came to a similar conclusion implementing an &ldquo;agentic&rdquo; feature for a client app in Elixir, though my code admittedly wasn&rsquo;t quite as clean. Others in the ecosystem are reaching similar conclusions: in an Elixir dev discussion on the topic, authors of the leading libraries admit <a href="https://elixirforum.com/t/is-anyone-working-on-ai-agents-in-elixir/69989/11">struggling</a> with whether their abstractions were worth it at all! When you&rsquo;re working in a message-passing, actor-based execution model, you really get straight to the meat of what you want your &ldquo;agent&rdquo; to do.</p>
<p>In my experience there&rsquo;s one key to interacting with LLM-based systems, whether in a chatbot or integrated in your app. That is:</p>
<blockquote>
<p>Vigilant management of context.</p></blockquote>
<p>I&rsquo;ve done some informal over-the-shoulder mentoring of AI usage for several knowledge workers now. So far  100% of them fall into the same anti-patterns. Put up a sticky note: &ldquo;Yes, really, you need to start a new chat already, this one is ruined.&rdquo;</p>
<p>With that in mind I want to briefly survey the LLM dev tooling that I find useful, and suggest some ideas of what the next steps might look like.</p>
<h2 id="instructor---runtime-schemas">Instructor -&gt; Runtime Schemas</h2>
<p>The only dependency used in the above tutorials is a port of the <a href="https://python.useinstructor.com/"><code>Instructor</code></a> library. The goal of this library is to coerce the LLM response into a structured output. It&rsquo;s <strong>essential</strong> for making tasks composable. Why? Because if the output of Task A has a known data model, then it can be used as input to a templated prompt for Task B.</p>
<p>There isn&rsquo;t really any magic here. <code>Instructor</code> just pulls a subprocess under the hood. Imagine a short back-and-forth happening at the end of every prompt:</p>
<pre tabindex="0"><code>&gt; Here&#39;s a JSON Schema. Make sure your response conforms.
&gt; OK, here&#39;s my response: ___
&gt; I couldn&#39;t parse that into JSON, please try again.
&gt; Oops, here you go: ____
&gt; This doesn&#39;t conform to the schema: The &#34;name&#34; attribute should be a string!
&gt; Ooops, here you go: ___
</code></pre><p>and so on. Of course the initial prompt and the schema itself are the biggest factor on the quality of your outcome, but I think this abstraction really belongs in the core toolkit. Nobody wants to re-implement this in every task.</p>
<p>The shortcoming I&rsquo;ve found working with this library is that your schemas (effectively) need to be defined at compile time. So imagine you&rsquo;re doing data pipeline generation and want a workflow where one task defines a schema, and another to adhere to it. It&rsquo;s a challenge with off-the-shelf tooling (to me, at least - YMMV and please let me know if it does).</p>
<p>I&rsquo;ve done a proof-of-concept with my <a href="https://hexdocs.pm/paradigm/readme.html"><code>Paradigm</code></a> library, which is designed for runtime schema manipulation. But I haven&rsquo;t gotten around to a full <code>Paradigm_Instructor</code> implementation that handles the iterative coercion steps.</p>
<h2 id="zed---editor-agents-that-dont-munch-tokens">Zed -&gt; Editor agents that don&rsquo;t munch tokens</h2>
<p>I&rsquo;ve been watching the <a href="https://zed.dev/">Zed</a> text editor for a while, and recently made the switch from Sublime as my daily driver. Besides just being a nice modern and performant editor, it has LLM features baked in from the ground up. The two features I really love are</p>
<ol>
<li>
<p>The &ldquo;Text Thread&rdquo; chat panel. There are shortcuts to add files and selections, and the entire thing just acts as a normal text buffer so you can rewrite history or delete tangents that would otherwise poison your context in a browser-based tool. This alone makes it worth using because (as I mentioned above), hawk-eyed management of context is key to successful use of LLMs.</p>
</li>
<li>
<p>The inline editor in your main text buffer. Basically your cursor (or selection) gives it the scope that it&rsquo;s allowed to rewrite. Then, your Text Thread contents can be pulled in to provide extra context. To me, this is the perfect LLM workflow. It&rsquo;s very efficient on tokens, too: I can use it all day long and spend pennies on API calls.</p>
</li>
</ol>
<p>Their recent update leans heavily into Agentic editing. I&rsquo;ve had mixed results. Sometimes it knocks through something viable, but sometimes it goes down terrible rabbit-holes where it gets nothing done. Either way it burns through tokens like crazy, so I tend to not reach for it. Even with minimal MCP handles, the baseline system prompt puts it at 5-6k tokens just to play ball. And that&rsquo;s not something you can customize.</p>
<p>I&rsquo;m looking for a middle ground between these two modes.</p>
<ol>
<li>Completely manual context management with scoped edit permissions (my current preferred way to work).</li>
<li>Token-munching agentic mode with MCP handles for full codebase access and terminal (largely deranged and ineffective)</li>
</ol>
<p>I&rsquo;m not going to work on it, but I&rsquo;ll know it when I see it! One sign I&rsquo;m watching for is transparency in the MCP bootstrap process. Can we dispense with huge system prompts? Can we give it handles to expand tools, so that some MCP categories never even enter the context? It&rsquo;s not just a matter of frugality of API calls. The workflow is critical to the quality of the outcome, and the full-scope editor apps are just not there yet.</p>
<h2 id="honorable-mention">Honorable Mention</h2>
<p>For a really nice take on sandboxing + transparency (fish-tanking?) I have to shout out this <a href="https://github.com/numtide/nix-ai-tools/tree/main/packages/claudebox">claudebox</a> project.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
