<?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: Eli Hadam Zucker</title>
    <description>The latest articles on DEV Community by Eli Hadam Zucker (@radadev).</description>
    <link>https://dev.to/radadev</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%2F3904940%2Fc8220446-522a-449b-aea7-b9e2f742af9a.png</url>
      <title>DEV Community: Eli Hadam Zucker</title>
      <link>https://dev.to/radadev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/radadev"/>
    <language>en</language>
    <item>
      <title>No LLM Classifier. No Latency Tax. How Rada Routes Cloud Requests in Pure Rust.</title>
      <dc:creator>Eli Hadam Zucker</dc:creator>
      <pubDate>Thu, 07 May 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/radadev/no-llm-classifier-no-latency-tax-how-rada-routes-cloud-requests-in-pure-rust-933</link>
      <guid>https://dev.to/radadev/no-llm-classifier-no-latency-tax-how-rada-routes-cloud-requests-in-pure-rust-933</guid>
      <description>&lt;p&gt;In Post 1 I covered the broad architecture. In Post 2 I went deep on the co-determination matrix and Sentinel. This post is the third piece: the Autorouter.&lt;/p&gt;

&lt;p&gt;The Autorouter answers a deceptively simple question: when a request needs cloud, which cloud model should handle it?&lt;br&gt;
Most platforms solve this with either a dropdown menu (pick your model) or a lightweight LLM classifier that reads the prompt and decides where to send it. Both approaches have real costs. The dropdown puts the decision on the developer. The classifier adds a serial dependency: you pay latency and tokens before the actual work starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rada does neither.&lt;/strong&gt; The Autorouter is a pure Rust function. It pattern-matches on a handful of signals and resolves a cloud tier in sub-millisecond time. The decision is made before the HTTP request leaves your machine.&lt;/p&gt;
&lt;h2&gt;
  
  
  Three lanes, not one highway
&lt;/h2&gt;

&lt;p&gt;The cloud side of Rada is organized into three tiers:&lt;/p&gt;

&lt;p&gt;Heavyweight: frontier reasoning models for complex architecture, multi-file planning, and large-context tasks. Think Claude Sonnet, DeepSeek V3.&lt;/p&gt;

&lt;p&gt;Workhorse: solid general-purpose models for standard builds and explanations. Gemini Flash, Mistral Nemo.&lt;/p&gt;

&lt;p&gt;Micro: lightweight models for small completions, lint fixes, and refactors that slightly exceed local capability. Qwen 2.5 Coder 32B, Gemini Flash-8B.&lt;/p&gt;

&lt;p&gt;All routing goes through OpenRouter, which is live in production. The tier system means Rada picks the right weight class for the task rather than defaulting to the most expensive option.&lt;/p&gt;
&lt;h2&gt;
  
  
  The routing signals
&lt;/h2&gt;

&lt;p&gt;The Autorouter reads four signals to classify each request:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Intent. The developer's selected mode (Refactor, Build, or Explain) establishes a starting tier. Refactors start light. Builds start heavier. This is the same intent axis from the co-determination matrix, now extending into cloud routing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Token payload. The function estimates the total token count of the prompt, active code, and any retrieval context. Larger payloads get bumped up a tier because they typically &lt;br&gt;
represent more complex tasks that benefit from stronger reasoning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Content signals. The prompt is scanned for architectural indicators. If the request involves system design, scaffolding, or multi-file coordination, it routes to Heavyweight regardless of starting tier. I won't enumerate the exact keyword set here, but the detection is string-based and fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Memory band. Sentinel's real-time RAM classification feeds directly into the Autorouter. If the developer's machine is under critical memory pressure, even a lightweight refactor gets bumped to a higher cloud tier. The logic: if local is unsafe, don't also cheap out on cloud. Give the request the best chance of a complete, useful response so the developer isn't waiting for a re-run.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These four signals resolve to a base_tier_id through a Rust match expression. No weights. No inference. No network call. Just pattern matching.&lt;/p&gt;
&lt;h2&gt;
  
  
  Preset overrides
&lt;/h2&gt;

&lt;p&gt;On top of the base tier, Rada supports cloud presets that let users nudge the routing without picking a specific model. The current presets are:&lt;/p&gt;

&lt;p&gt;Reasoning: biases toward stronger models. A request that would have routed to Micro gets bumped to Workhorse.&lt;/p&gt;

&lt;p&gt;Speed: biases toward faster models. A request that would have routed to Heavyweight can drop to Workhorse if the payload is small enough and memory isn't critical.&lt;/p&gt;

&lt;p&gt;Coding: biases toward code-specialized models. Similar to Speed but tuned for code completion patterns.&lt;/p&gt;

&lt;p&gt;Presets are optional. If the developer doesn't set one, the base tier stands. If they do, the preset applies a second pass over the base tier resolution. Two match expressions, still sub-millisecond.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;rust&lt;/span&gt;&lt;span class="c1"&gt;// Simplified structure (not the exact production code)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;base_tier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"refactorDebug"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;evaluate_refactor_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&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="s"&gt;"buildFromScratch"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;evaluate_build_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&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;content&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;"explain"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;evaluate_explain_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&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;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"workhorse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;final_tier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;preset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"reasoning"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;bias_toward_stronger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_tier&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"speed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;bias_toward_faster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&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="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"coding"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;bias_toward_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;base_tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;

&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;involved&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;same&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="n"&gt;deterministic&lt;/span&gt; &lt;span class="n"&gt;passes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;both&lt;/span&gt; &lt;span class="n"&gt;pure&lt;/span&gt; &lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;allocations&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;hot&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why not an LLM classifier?
&lt;/h2&gt;

&lt;p&gt;Some platforms route prompts by running them through a lightweight model first: "read this prompt and decide if it's a simple or complex task." There are a few problems with this.&lt;/p&gt;

&lt;p&gt;Latency. Even a small classifier model adds 200-800ms of serial latency before the real work begins. For a tool that's supposed to feel responsive, that's a lot of dead air.&lt;/p&gt;

&lt;p&gt;Cost. The classifier consumes tokens. On a platform where every cloud interaction counts against a daily quota, spending tokens on routing instead of the actual task is waste.&lt;/p&gt;

&lt;p&gt;Brittleness. LLM classifiers are probabilistic. The same prompt might route differently on consecutive runs. Debugging why a request went to the wrong tier becomes an inference problem instead of a code path you can trace.&lt;/p&gt;

&lt;p&gt;Rada's routing is a Rust function. It's deterministic. Given the same inputs, it always produces the same output. You can unit test it. You can trace exactly why a specific request went to a specific tier. And the routing decision takes microseconds, not hundreds of milliseconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The token estimation trick
&lt;/h2&gt;

&lt;p&gt;One detail worth calling out: the Autorouter needs a token count to make its tier decision, but running a real tokenizer before routing would add overhead. Instead, Rada uses a character-based heuristic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="n"&gt;rustfn&lt;/span&gt; &lt;span class="nf"&gt;estimate_token_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="nf"&gt;.chars&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.div_ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&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;Characters divided by four, rounded up. This is a rough approximation (real tokenization varies by model and content), but it's accurate enough for tier classification. The Autorouter doesn't need an exact count. It needs to know whether the payload is small, medium, or large. A 4:1 ratio gets that right consistently, and it costs zero allocations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for the developer
&lt;/h2&gt;

&lt;p&gt;The Autorouter is invisible by design. The developer selects an intent, writes a prompt, and the system decides whether to handle it locally (via Behavioral Routing and Sentinel) or route to cloud (via the Autorouter). If it goes to cloud, the Autorouter picks the tier.&lt;br&gt;
The developer never sees a model picker. They don't need to know which cloud model is best for their task. The system handles it, and the routing logic is fast enough that it adds no perceptible delay.&lt;br&gt;
Requests routed through the Autorouter consume daily cloud quota at half the rate of manually selected models. This creates a structural incentive: trust the routing, get twice the cloud interactions per day. It's Rada's way of rewarding developers for letting the system do what it's designed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The full picture
&lt;/h2&gt;

&lt;p&gt;Three posts, three systems:&lt;/p&gt;

&lt;p&gt;Post 1: the broad architecture. Local-first with intentional cloud. Why this approach and why now.&lt;/p&gt;

&lt;p&gt;Post 2: the co-determination matrix. One model, nine behavioral profiles. Intent crossed with real-time hardware state.&lt;/p&gt;

&lt;p&gt;Post 3 (this one): the Autorouter. When local isn't enough, a pure Rust function picks the right cloud tier in microseconds.&lt;/p&gt;

&lt;p&gt;Together, Behavioral Routing, Sentinel, and the Autorouter form a single decision pipeline: measure the machine, understand the intent, adapt the local model or route to the right cloud tier. No hot-swaps. No model pickers. No wasted tokens on routing classifiers.&lt;/p&gt;

&lt;p&gt;Rada is in closed beta. If you want to see how these systems work together on your hardware, the waitlist is at userada.dev.&lt;/p&gt;

&lt;p&gt;Eli Hadam Zucker is the founder of Rada. Previously at Wise. Building local-first AI tooling in Rust.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>devex</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How One Local Model Gets Nine Personalities (Without Ever Swapping Weights)</title>
      <dc:creator>Eli Hadam Zucker</dc:creator>
      <pubDate>Tue, 05 May 2026 18:32:07 +0000</pubDate>
      <link>https://dev.to/radadev/how-one-local-model-gets-nine-personalities-without-ever-swapping-weights-1cb1</link>
      <guid>https://dev.to/radadev/how-one-local-model-gets-nine-personalities-without-ever-swapping-weights-1cb1</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/radadev/why-im-building-a-local-first-ai-coding-workspace-and-how-behavioral-routing-makes-it-work-cg2"&gt;first post&lt;/a&gt;, I laid out the broad architecture of Rada: local-first AI coding, Behavioral Routing, Sentinel, the Autorouter. Think of that post as the map. This one is the terrain.&lt;/p&gt;

&lt;p&gt;Today I'm going deep on the co-determination matrix. The system that lets a single resident model produce nine distinct behavioral profiles by crossing developer intent with real-time hardware state. And Sentinel, the Rust module that measures the hardware side of that equation on every single request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick context if you missed Post 1
&lt;/h2&gt;

&lt;p&gt;Rada keeps one local GGUF model loaded in RAM. No hot-swapping. The model adapts its behavior based on what you're doing (intent) and what your machine can handle (memory band). Sentinel monitors RAM. The Autorouter handles cloud when local isn't enough.&lt;/p&gt;

&lt;p&gt;That's the 30-second version. Now let's get into the actual implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The co-determination matrix
&lt;/h2&gt;

&lt;p&gt;The core idea is that the model's behavior isn't determined by a single variable. It's the product of two axes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intent&lt;/strong&gt; (what the developer is doing):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactor/Debug: tighten existing code, fix bugs, improve structure&lt;/li&gt;
&lt;li&gt;Build from Scratch: generate new code, scaffold features&lt;/li&gt;
&lt;li&gt;Explain: walk through logic, teach concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Memory Band&lt;/strong&gt; (what the hardware can handle right now):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Normal (&amp;lt; 70% RAM): full capability&lt;/li&gt;
&lt;li&gt;Elevated (70-84% RAM): constrained but functional&lt;/li&gt;
&lt;li&gt;Critical (≥ 85% RAM): local generation unsafe, escalate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cross those two axes and you get a 3×3 matrix. Each cell is a &lt;code&gt;BehaviorProfile&lt;/code&gt; in Rust:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;BehaviorProfile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;memory_band&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MemoryBand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt_suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;f32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_output_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_retrieval_chars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;local_token_cap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&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;Every profile controls four knobs: temperature, output token budget, retrieval context size, and a behavioral instruction injected into the system prompt.&lt;/p&gt;

&lt;p&gt;Here's the actual matrix from the codebase:&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;Normal (&amp;lt; 70%)&lt;/th&gt;
&lt;th&gt;Elevated (70-84%)&lt;/th&gt;
&lt;th&gt;Critical (≥ 85%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Refactor/Debug&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;temp 0.1, 1200 tokens&lt;/td&gt;
&lt;td&gt;temp 0.05, 900 tokens&lt;/td&gt;
&lt;td&gt;temp 0.0, 700 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;temp 0.45, 12000 tokens&lt;/td&gt;
&lt;td&gt;temp 0.3, 8000 tokens&lt;/td&gt;
&lt;td&gt;temp 0.2, 5000 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Explain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;temp 0.35, 1800 tokens&lt;/td&gt;
&lt;td&gt;temp 0.25, 1200 tokens&lt;/td&gt;
&lt;td&gt;temp 0.15, 800 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look at the spread. A Build task at normal memory gets temperature 0.45 and a 12,000-token budget. The same Build task under critical memory pressure? Temperature drops to 0.2 and the budget cuts to 5,000 tokens. The model becomes conservative precisely when your machine needs it to.&lt;/p&gt;

&lt;p&gt;Refactor at normal memory runs at 0.1 temperature. Already deterministic, already tight. Under critical pressure it drops to 0.0 and the token budget shrinks from 1,200 to 700. At that point the model is producing the smallest safe diff it can manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt suffix: behavioral steering without fine-tuning
&lt;/h2&gt;

&lt;p&gt;Each cell in the matrix also carries a &lt;code&gt;prompt_suffix&lt;/code&gt; that gets injected into the system prompt at generation time. This is how a 7B model "knows" it's supposed to refactor conservatively vs. build expansively vs. explain clearly.&lt;/p&gt;

&lt;p&gt;The prompt composition pipeline builds five layers in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Role preamble&lt;/strong&gt; (language expertise based on the active file)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentinel status&lt;/strong&gt; ("Current Sentinel profile: Refactor / Elevated. Memory band: elevated.")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intent persona&lt;/strong&gt; (operational instructions for the selected mode)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavioral routing instruction&lt;/strong&gt; (the prompt_suffix from the matrix cell)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output format spec&lt;/strong&gt; (how to structure the response with @&lt;a class="mentioned-user" href="https://dev.to/file"&gt;@file&lt;/a&gt; tags)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model sees its own constraints. It knows its memory band. It knows its token budget. That transparency turns out to matter. A model that's told "you have 900 tokens and memory is elevated" produces tighter output than one that's just given a smaller max_tokens parameter silently. The behavioral instruction gives the model permission to be concise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sentinel: measuring reality on every request
&lt;/h2&gt;

&lt;p&gt;Here's where the memory axis of the matrix becomes real.&lt;/p&gt;

&lt;p&gt;Sentinel is a Rust module that checks system RAM before every local generation. Not a polling loop. Not a timer. A synchronous check at the decision point.&lt;/p&gt;

&lt;p&gt;The implementation is platform-specific:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS&lt;/strong&gt;: calls &lt;code&gt;memory_pressure -Q&lt;/code&gt; first. If that fails (older macOS versions), falls back to parsing &lt;code&gt;vm_stat&lt;/code&gt; output, calculating used memory from free pages, speculative pages, and purgeable pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;: reads &lt;code&gt;/proc/meminfo&lt;/code&gt; and computes usage from &lt;code&gt;MemTotal&lt;/code&gt; minus &lt;code&gt;MemAvailable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;: runs &lt;code&gt;Get-CimInstance Win32_OperatingSystem&lt;/code&gt; via PowerShell and calculates from total vs. free physical memory.&lt;/p&gt;

&lt;p&gt;All three paths produce the same output: a single &lt;code&gt;u8&lt;/code&gt; representing percent of RAM in use. That number feeds into this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;classify_memory_band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory_usage_percent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MemoryBand&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;memory_usage_percent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usage&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;usage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;MemoryBand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Critical&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usage&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;usage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;MemoryBand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Elevated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;MemoryBand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Normal&lt;/span&gt;&lt;span class="p"&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;Notice the &lt;code&gt;Option&amp;lt;u8&amp;gt;&lt;/code&gt;. If platform detection fails entirely (permissions issues, unexpected output format), the system defaults to &lt;code&gt;Normal&lt;/code&gt;. Fail open, not closed. A developer who can't get RAM readings still gets full local capability rather than being locked out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two enforcement points
&lt;/h2&gt;

&lt;p&gt;Sentinel doesn't just label the memory band. It enforces it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gate 1: Pre-generation check.&lt;/strong&gt; Before any local inference starts, Sentinel reads memory and resolves the behavior profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;memory_usage_percent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;detect_system_memory_usage_percent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;behavior_profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolve_behavior_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memory_usage_percent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the result is a Critical-band profile, the request never reaches the local model. It gets rerouted to the Autorouter for cloud handling, with a message explaining why: "Sentinel escalated this request because local memory pressure is critical."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gate 2: Budget enforcement.&lt;/strong&gt; Even within Normal and Elevated bands, the resolved profile's token budgets and retrieval caps constrain the generation. A Build request that would happily consume 12,000 tokens at 60% RAM gets capped at 8,000 tokens at 75% RAM. The model adapts its output to fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why per-request, not periodic
&lt;/h2&gt;

&lt;p&gt;Your RAM state changes constantly. You open a browser tab. Docker pulls an image. Spotlight re-indexes. The memory band from 30 seconds ago might not be the one you're in now.&lt;/p&gt;

&lt;p&gt;A periodic check (say, every 5 seconds) creates a window where the system's picture of memory is stale. A per-request check means the behavioral profile is always current. The memory axis of the co-determination matrix isn't a configuration setting. It's measured. Every time.&lt;/p&gt;

&lt;p&gt;The overhead is negligible. Reading &lt;code&gt;/proc/meminfo&lt;/code&gt; on Linux takes microseconds. The macOS &lt;code&gt;memory_pressure&lt;/code&gt; call is similarly lightweight. The cost of one extra syscall per request is invisible compared to the inference time that follows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is the patentable piece
&lt;/h2&gt;

&lt;p&gt;System prompts aren't novel. Temperature scaling isn't novel. RAM monitoring isn't novel.&lt;/p&gt;

&lt;p&gt;What's novel is the co-determination: using real-time hardware state as a first-class input to model behavioral configuration, intersected with developer intent, to produce adaptive profiles from a single resident model. The model doesn't just respond to what you asked. It responds to what you asked given what your machine can handle right now.&lt;/p&gt;

&lt;p&gt;We filed a US provisional patent on this mechanism. The claim isn't any individual piece. It's the intersection.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;Developer on a 16 GB MacBook. Running VS Code, Chrome with 15 tabs, Docker, Slack. RAM sitting at 72%. They select Refactor intent and ask the model to clean up a function.&lt;/p&gt;

&lt;p&gt;Sentinel reads 72%, classifies Elevated band. The co-determination matrix resolves to: temperature 0.05, 900-token output budget, tightened retrieval context. The prompt suffix tells the model to emit the smallest possible safe diff.&lt;/p&gt;

&lt;p&gt;The model produces a focused, conservative refactor. No rambling. No unnecessary changes. The developer's machine stays stable.&lt;/p&gt;

&lt;p&gt;Same developer, same session, but they close Docker and Chrome. RAM drops to 55%. They switch to Build intent and ask for a new feature module. Sentinel reads 55%, classifies Normal band. Temperature jumps to 0.45, output budget goes to 12,000 tokens, full retrieval context. The model produces expansive, complete code.&lt;/p&gt;

&lt;p&gt;Same model. Same weights. Different behavior. Zero downtime between the two requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The Autorouter is the other half of this story. When Sentinel escalates to cloud, the Autorouter decides which cloud tier to hit (and the routing is a pure Rust function, not another LLM call). That's the next post.&lt;/p&gt;

&lt;p&gt;Rada is in closed beta. If you want to see how the co-determination matrix behaves on your specific hardware, the waitlist is at &lt;a href="https://userada.dev?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=closed_beta&amp;amp;utm_content=article_2" rel="noopener noreferrer"&gt;userada.dev&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Eli Hadam Zucker is the founder of Rada. Previously at Wise. Building local-first AI tooling in Rust.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>ai</category>
      <category>rust</category>
      <category>devtools</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why I'm Building a Local-First AI Coding Workspace (And How Behavioral Routing Makes It Work)</title>
      <dc:creator>Eli Hadam Zucker</dc:creator>
      <pubDate>Wed, 29 Apr 2026 19:28:22 +0000</pubDate>
      <link>https://dev.to/radadev/why-im-building-a-local-first-ai-coding-workspace-and-how-behavioral-routing-makes-it-work-cg2</link>
      <guid>https://dev.to/radadev/why-im-building-a-local-first-ai-coding-workspace-and-how-behavioral-routing-makes-it-work-cg2</guid>
      <description>&lt;h1&gt;
  
  
  Why I'm Building a Local-First AI Coding Workspace (And How Behavioral Routing Makes It Work)
&lt;/h1&gt;

&lt;p&gt;There's a pattern forming in the AI coding tool space that I think is worth paying attention to.&lt;/p&gt;

&lt;p&gt;GitHub paused Copilot Pro+ signups because agentic workloads broke their cost model. Cursor Pro+ is $60/mo and climbing. Claude Code might leave the Pro tier entirely. The common thread: these tools are all cloud-only, which means every user interaction is a cost event on someone else's infrastructure. At scale, the math stops working. Prices go up, access gets gated, and developers end up paying more for less.&lt;/p&gt;

&lt;p&gt;I left my role at Wise earlier this year to build a different kind of AI coding tool. One where local inference is the default and cloud is a resource you use intentionally. That tool is called Rada.&lt;/p&gt;

&lt;p&gt;This post is a technical walkthrough of how it works under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core thesis
&lt;/h2&gt;

&lt;p&gt;Most of what developers ask an AI coding assistant to do doesn't need a frontier cloud model. Refactors, explanations, boilerplate, quick fixes. That's maybe 80% of interactions, and all of it can run on a local LLM.&lt;/p&gt;

&lt;p&gt;The remaining 20% (complex architecture decisions, large-scale code generation, multi-file refactors) benefits from cloud models. So the architecture needs to handle both, and it needs to make the transition between them seamless.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with hot-swapping
&lt;/h2&gt;

&lt;p&gt;The naive approach to local AI tooling is to keep multiple models and swap them based on the task. Need a coding model? Load it. Need a general model? Unload the coder, load the general one.&lt;/p&gt;

&lt;p&gt;This is a terrible experience in practice. GGUF models at Q4_K_M quantization run anywhere from 4-11 GB in RAM. Loading and unloading them takes time, spikes memory usage, and creates gaps in responsiveness. If you're in a flow state and the tool needs 30 seconds to swap models, you've already lost the thread.&lt;/p&gt;

&lt;p&gt;Rada takes a fundamentally different approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behavioral Routing
&lt;/h2&gt;

&lt;p&gt;Instead of swapping models, Rada keeps a single model resident in RAM and adjusts how it behaves based on what the developer is doing. We call this Behavioral Routing.&lt;/p&gt;

&lt;p&gt;The system supports three intent modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Refactor&lt;/strong&gt;: tighten existing code, improve naming, reduce complexity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt;: generate new code, scaffold features, implement from scratch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn&lt;/strong&gt;: explain unfamiliar code, walk through logic, teach concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the developer selects an intent (or the system infers it from context), Behavioral Routing adjusts three parameters on the resident model:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System prompt&lt;/strong&gt;: each intent gets a tailored system prompt that shapes the model's approach. A Refactor prompt emphasizes preserving behavior while improving structure. A Build prompt focuses on completeness and best practices. A Learn prompt prioritizes clarity and step-by-step explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temperature&lt;/strong&gt;: Refactor tasks use lower temperature (more deterministic, safer transformations). Build tasks use slightly higher temperature (more creative solutions). Learn tasks sit in the middle (clear but not robotic).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context window&lt;/strong&gt;: the system dynamically adjusts how much context gets sent to the model based on intent. Refactoring a single function needs a narrow window. Building a new feature might need broader project context. Learning about a module needs enough surrounding code to give a complete picture.&lt;/p&gt;

&lt;p&gt;The result: one model, three distinct behaviors. No load/unload cycle. No RAM spikes. The model stays warm and responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The local model roster
&lt;/h2&gt;

&lt;p&gt;Rada uses a tiered model roster, all GGUF Q4_K_M quantizations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Size in RAM&lt;/th&gt;
&lt;th&gt;Primary Intent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 2.5 Coder 7B&lt;/td&gt;
&lt;td&gt;~4.7 GB&lt;/td&gt;
&lt;td&gt;Refactor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 3.1 8B&lt;/td&gt;
&lt;td&gt;~5.3 GB&lt;/td&gt;
&lt;td&gt;Learn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek Coder V2 Lite 16B (MoE)&lt;/td&gt;
&lt;td&gt;~10.6 GB&lt;/td&gt;
&lt;td&gt;Build&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Which model gets loaded depends on your hardware, not your preference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sentinel: RAM-aware model selection
&lt;/h2&gt;

&lt;p&gt;Sentinel is a Rust background process that monitors system memory and determines which model tier your machine can support. The selection is deterministic: Sentinel reads available RAM, checks it against the model ladder, and picks the highest tier that fits without putting the system under pressure.&lt;/p&gt;

&lt;p&gt;On a 16 GB machine, you'll get the 7B or 8B models. On 32 GB+, you can run the DeepSeek MoE. The ladder scales up from there as hardware allows.&lt;/p&gt;

&lt;p&gt;This is a deliberate design choice. Asking users to pick their own model leads to people overloading their systems or underutilizing their hardware. Sentinel removes that friction. You open Rada and it works with whatever machine you have.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Autorouter: when local isn't enough
&lt;/h2&gt;

&lt;p&gt;Some tasks genuinely need cloud models. Complex multi-file refactors, architectural decisions that need broad reasoning, large-scale code generation. For these, Rada has the Autorouter.&lt;/p&gt;

&lt;p&gt;The Autorouter evaluates the incoming request and routes it to the appropriate cloud endpoint based on task complexity and the intent mode. The cloud model roster is tiered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heavyweight&lt;/strong&gt;: Claude Sonnet, DeepSeek V3 (for complex reasoning tasks)&lt;br&gt;
&lt;strong&gt;Workhorse&lt;/strong&gt;: Gemini Flash, Mistral Nemo (for solid general-purpose tasks)&lt;br&gt;
&lt;strong&gt;Micro&lt;/strong&gt;: Qwen 2.5 Coder 32B, Gemini Flash-8B (for lighter cloud tasks that still exceed local capability)&lt;/p&gt;

&lt;p&gt;Cloud routing is managed through OpenRouter, which is already live in production.&lt;/p&gt;

&lt;p&gt;Here's a detail that matters: requests routed through the Autorouter consume at 0.5x the normal daily cloud quota rate. If a user manually selects a cloud model, it burns at 1x. This creates an incentive to trust the Autorouter's judgment rather than always reaching for the biggest model. The system rewards efficient routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The daily cloud burst quota
&lt;/h2&gt;

&lt;p&gt;Every Rada user gets a daily cloud burst quota. Free tier users can bring their own API keys. Pro users ($19/mo) get 20 daily bursts. Ultra users ($55/mo) get 75.&lt;/p&gt;

&lt;p&gt;The quota resets daily (UTC). This is intentional. Monthly quotas create anxiety and hoarding behavior. Daily quotas encourage consistent usage without the fear of burning through your allocation in the first week.&lt;/p&gt;

&lt;p&gt;Combined with the 0.5x Autorouter rate, Pro users effectively get 40 cloud interactions per day when they let the system route. That's enough for a full day of coding where cloud is used for the tasks that actually need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Rust and Tauri
&lt;/h2&gt;

&lt;p&gt;The backend is built in Rust with Tauri as the desktop framework. A few reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory matters&lt;/strong&gt;: when your app is managing local LLM inference, every megabyte of overhead counts. Rust gives predictable, low memory usage. An Electron wrapper eating 500 MB of RAM on top of your model isn't acceptable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentinel needs to be fast&lt;/strong&gt;: the RAM monitoring process runs continuously. It needs to be lightweight and responsive. Rust's performance characteristics make this straightforward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tauri's footprint&lt;/strong&gt;: compared to Electron, Tauri produces significantly smaller binaries and uses the system's native webview. On a tool where local resource management is the core feature, the framework can't be the one wasting resources.&lt;/p&gt;

&lt;p&gt;The frontend is React, which gives us the UI flexibility we need without fighting the framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters now
&lt;/h2&gt;

&lt;p&gt;The AI coding tool market is at an inflection point. Cloud-only architectures worked when usage was lower and providers were subsidizing costs to gain market share. That era is ending.&lt;/p&gt;

&lt;p&gt;GitHub pausing Copilot Pro+ isn't a temporary measure. It's a signal that cloud-only AI tooling at consumer price points doesn't have sustainable unit economics. The cost per agentic session is too high.&lt;/p&gt;

&lt;p&gt;Local-first isn't about being anti-cloud. It's about using cloud intentionally and keeping the majority of interactions local where they belong. The developer gets a faster, more responsive tool. The provider gets margins that actually work. The dependency on any single cloud provider goes away.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Rada is heading into closed beta. We're looking for developers who want to test the local-first approach and help calibrate the system with real-world hardware data. Early testers get first right to a lifetime deal on cloud routing.&lt;/p&gt;

&lt;p&gt;If this architecture interests you, the waitlist is at &lt;a href="https://userada.dev?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=closed_beta&amp;amp;utm_content=article" rel="noopener noreferrer"&gt;userada.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'll be writing more about the technical decisions behind Rada here on dev.to. Next up: how Sentinel's RAM heuristics work in practice across different hardware configurations.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Eli Hadam Zucker is the developer behind Rada. Previously at Wise. Building local-first AI tooling in Rust.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>llm</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
