<?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: Ishank Choudhary</title>
    <description>The latest articles on DEV Community by Ishank Choudhary (@ishank-dev).</description>
    <link>https://dev.to/ishank-dev</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%2F1886713%2F6e03b2e8-4762-4569-9dea-f73f593e8a4a.png</url>
      <title>DEV Community: Ishank Choudhary</title>
      <link>https://dev.to/ishank-dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ishank-dev"/>
    <language>en</language>
    <item>
      <title>NVIDIA Nemotron 3.5 Bolt E4B: Running an Offline Voice Agent With Tool Calling on a CPU</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Wed, 28 Oct 2026 04:46:48 +0000</pubDate>
      <link>https://dev.to/ishank-dev/nvidia-nemotron-35-bolt-e4b-running-an-offline-voice-agent-with-tool-calling-on-a-cpu-3m5g</link>
      <guid>https://dev.to/ishank-dev/nvidia-nemotron-35-bolt-e4b-running-an-offline-voice-agent-with-tool-calling-on-a-cpu-3m5g</guid>
      <description>&lt;p&gt;NVIDIA released Nemotron 3.5 Bolt E4B on October 23. The pitch is a small model tuned for agents: it calls tools, follows instructions, and is small enough for laptops, Jetsons and other edge hardware. The model card's benchmarks are tested on H100s, RTX 5090s and DGX Spark. I wanted to see what happens without any of those.&lt;/p&gt;

&lt;p&gt;So I took the official 4-bit GGUF, ran it on a plain 8-vCPU Xeon VM with 16 GB of RAM and no GPU, and built a small voice assistant around it. It listens to a WAV file, picks a tool, calls it, and speaks the answer back. Everything below is from my own runs. I've kept the raw CSVs for every number.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Bolt E4B actually is
&lt;/h2&gt;

&lt;p&gt;A few facts from the model card and the files themselves, because the name hides some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Architecture:&lt;/strong&gt; Gemma 4 E4B, post-trained by NVIDIA with reinforcement learning (GRPO via NeMo RL) for tool use, instruction following and multi-turn chat. About 8B total parameters and about 4B "effective" ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License:&lt;/strong&gt; OpenMDW-1.1 on NVIDIA's release. The base Gemma 4 weights are Apache 2.0.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context:&lt;/strong&gt; 64K tokens. &lt;strong&gt;Text in, text out.&lt;/strong&gt; There's no audio in the model, so a voice agent still needs separate speech-to-text and text-to-speech.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weights:&lt;/strong&gt; the official repo is &lt;code&gt;nvidia/NVIDIA-Nemotron-3.5-Bolt-E4B-4GB&lt;/code&gt;, with a single &lt;code&gt;Q4_K_M&lt;/code&gt; GGUF. NVIDIA also ships a BF16 checkpoint for vLLM and a DFlash speculative-decoding drafter aimed at GPUs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommended serving:&lt;/strong&gt; llama.cpp with &lt;code&gt;--jinja&lt;/code&gt;, sampling at temperature 1.0 and top_p 0.95, and a chat-template switch for "thinking" on or off.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first surprise: the "4GB" file is &lt;strong&gt;6.18 GB on disk&lt;/strong&gt;. I opened the GGUF and summed the tensors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tensor group&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Per-layer embedding tables (mostly Q8_0)&lt;/td&gt;
&lt;td&gt;3.05 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transformer blocks (Q4_K + Q6_K)&lt;/td&gt;
&lt;td&gt;2.40 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token embeddings&lt;/td&gt;
&lt;td&gt;0.71 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The per-layer embeddings are lookup tables: each token only reads a few rows. That's what makes the "4GB" label fair at run time, as you'll see in the memory section. You still need about 6.2 GB of disk space and download time, though.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hardware:&lt;/strong&gt; 8 vCPU Intel Xeon (AVX-512, VNNI), 16 GB RAM, no swap, no GPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; llama.cpp CPU build b11913, using &lt;code&gt;llama-server&lt;/code&gt; as an OpenAI-compatible endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speech-to-text:&lt;/strong&gt; faster-whisper, &lt;code&gt;base.en&lt;/code&gt; and &lt;code&gt;small.en&lt;/code&gt;, int8 on CPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text-to-speech:&lt;/strong&gt; Piper with the &lt;code&gt;en_US-lessac-medium&lt;/code&gt; voice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server command was nothing special:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llama-server &lt;span class="nt"&gt;-m&lt;/span&gt; Nemotron-3.5-Bolt-E4B-Q4_K_M.gguf &lt;span class="nt"&gt;--alias&lt;/span&gt; nemotron-bolt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--host&lt;/span&gt; 127.0.0.1 &lt;span class="nt"&gt;--port&lt;/span&gt; 8000 &lt;span class="nt"&gt;-c&lt;/span&gt; 8192 &lt;span class="nt"&gt;-np&lt;/span&gt; 1 &lt;span class="nt"&gt;-t&lt;/span&gt; 8 &lt;span class="nt"&gt;--jinja&lt;/span&gt; &lt;span class="nt"&gt;--metrics&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model loaded in 2.5 to 6 seconds. My first sanity check was 17 Ã— 23, and it answered 391.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raw speed on 8 CPU cores
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llama-bench&lt;/code&gt;, 8 threads, 3 repetitions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Tokens/s&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt processing (512 tokens)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;194.6 Â± 32.8&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generation (128 tokens)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10.9 Â± 2.8&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;About 11 tokens per second of generation is slow next to a GPU, but it's enough for an assistant whose replies are one or two sentences. Prefill speed matters more than I expected. My system prompt plus five tool schemas came to about 500 tokens, and the very first request took 6.4 seconds before anything came back. After that, llama.cpp's prompt cache kept the prefix warm, and only the new user message needed processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 1: tool calling, 20 prompts Ã— 3 runs
&lt;/h2&gt;

&lt;p&gt;I defined five mock tools, the kind a voice assistant would have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_weather(city)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;calculate(expression)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create_event(title, date, time, duration_min)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set_timer(minutes, label)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;control_light(room, state, brightness)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system prompt gave the date (Tuesday 2026-10-27, IST) and asked for short spoken replies. I wrote 20 prompts: three per tool, plus five where the right move is not to call any tool. Those were a joke, a definition, a "thanks", a trivia question, and "order me a pizza", which no tool can do.&lt;/p&gt;

&lt;p&gt;Each response was scored on two things: did it pick the right tool (or correctly pick none), and were the arguments exactly right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thinking off&lt;/strong&gt; (the mode I'd use for voice), three full runs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Right tool, or correctly no tool&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60 / 60&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exactly correct arguments&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;57 / 60 (95%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median time to first token&lt;/td&gt;
&lt;td&gt;0.87â€“1.15 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median end-to-end per prompt&lt;/td&gt;
&lt;td&gt;2.1â€“3.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median generated tokens&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Some results I liked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Set a timer for 45 seconds" became &lt;code&gt;minutes: 0.75&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;"An hour and a half" became &lt;code&gt;duration_min: 90&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;"Dim the bedroom to 30%" became &lt;code&gt;state: "on", brightness: 30&lt;/code&gt;. It didn't treat "dim" as "off".&lt;/li&gt;
&lt;li&gt;"18% GST on 4999" became &lt;code&gt;4999 * 0.18&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;None of the five no-tool prompts triggered a tool. For the pizza request it said plainly that it couldn't order food, rather than forcing the request into &lt;code&gt;create_event&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The miss was the same in all three runs. "Put sprint planning on my calendar for Friday at 11 for an hour" got the right title, time and duration, but the date was &lt;strong&gt;2026-11-06, a week too late&lt;/strong&gt;. With today being Tuesday the 27th, "Friday" should be the 30th. Relative-date math is where a 4B model shows its size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thinking on&lt;/strong&gt;, one run of the same 20 prompts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Right tool&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20 / 20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exactly correct arguments&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20 / 20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median end-to-end per prompt&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;13.1 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median generated tokens&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With reasoning on, it got Friday right (2026-10-30). That cost about 350 characters of reasoning and 17.6 seconds for that one prompt. The first token still arrives fast, but it's a reasoning token rather than an answer. Overall that's roughly &lt;strong&gt;5x slower per turn&lt;/strong&gt; for one extra correct argument out of 20. For a voice assistant on CPU, I'd keep thinking off and handle dates in code: pass the model a resolved calendar ("Friday = 2026-10-30") in the prompt, or let the tool parse "Friday" itself.&lt;/p&gt;

&lt;p&gt;One llama.cpp detail if you're measuring this yourself: tool-call output streams in late, once the call has been parsed. So TTFT for a tool call is close to the time the whole call is ready. For plain-text replies, the first token showed up in 0.36 to 0.6 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 2: a full offline voice turn
&lt;/h2&gt;

&lt;p&gt;Next I wired up the whole loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Piper speaks the user's request into a WAV file, as a stand-in for a microphone.&lt;/li&gt;
&lt;li&gt;faster-whisper transcribes it.&lt;/li&gt;
&lt;li&gt;Bolt picks a tool (thinking off).&lt;/li&gt;
&lt;li&gt;The mock tool runs.&lt;/li&gt;
&lt;li&gt;Bolt turns the tool result into a one-sentence reply.&lt;/li&gt;
&lt;li&gt;Piper speaks the reply into another WAV.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Six utterances, timed stage by stage. Medians:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Whisper base.en&lt;/th&gt;
&lt;th&gt;Whisper small.en&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Speech-to-text&lt;/td&gt;
&lt;td&gt;0.35 s&lt;/td&gt;
&lt;td&gt;0.85 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM: choose tool + args&lt;/td&gt;
&lt;td&gt;2.39 s&lt;/td&gt;
&lt;td&gt;1.85 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM: spoken reply from tool result&lt;/td&gt;
&lt;td&gt;1.48 s&lt;/td&gt;
&lt;td&gt;1.51 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text-to-speech (Piper)&lt;/td&gt;
&lt;td&gt;0.08 s&lt;/td&gt;
&lt;td&gt;0.07 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Whole turn&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.08 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.58 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The LLM is nearly all of the turn time. Piper is basically free: it made a 4-second reply in 70 to 100 ms. Whisper is cheap too. That means most of the latency budget goes to two model calls: one to pick the tool and one to phrase the answer.&lt;/p&gt;

&lt;p&gt;What the transcripts showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;base.en heard "Pune" as "Pooner". Bolt still called &lt;code&gt;get_weather(city="Pune")&lt;/code&gt; correctly.&lt;/li&gt;
&lt;li&gt;base.en turned "Tell me a one-line joke about compilers" into "Tell me what you want to do." Bolt sensibly listed its abilities, but the joke never happened. small.en got the sentence right, and Bolt told the joke.&lt;/li&gt;
&lt;li&gt;"Book a dentist appointment tomorrow at four thirty p m" became &lt;code&gt;date: 2026-10-28, time: 16:30&lt;/code&gt;, which is correct.&lt;/li&gt;
&lt;li&gt;The 18%-of-4,999 answer was "about 900" in one run and "899.82" in another. At temperature 1.0 the wording varies, so if exact numbers matter, put them in your reply template.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My takeaway: &lt;strong&gt;small.en is worth its extra half second&lt;/strong&gt;, because recognition errors cost far more than ASR latency. Since the model handles fuzzy input well, I'd spend the speed budget on the ASR side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory: where the "4GB" name comes from
&lt;/h2&gt;

&lt;p&gt;On Linux, llama.cpp memory-maps the GGUF, so &lt;code&gt;top&lt;/code&gt; can show a scary number. Right after load, RSS was about 9.6 GB, because the file pages had just been read. Once the system had been running for a while, the server process looked like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anonymous (actually allocated) memory, 8K context, 1 slot&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.8 GB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSS after the page cache settled&lt;/td&gt;
&lt;td&gt;4.1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same server with 16K context and 4 slots (anonymous)&lt;/td&gt;
&lt;td&gt;3.7 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice stack (Whisper small.en + Piper) in a separate process&lt;/td&gt;
&lt;td&gt;0.66 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So about 4 GB of RAM for the model, plus about 0.7 GB for speech. The large embedding tables mostly stay on disk until a token needs a row. That matches the name, and it's a key reason this model fits small devices. Just plan for the 6.2 GB download and the disk space.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, honestly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU only.&lt;/strong&gt; I didn't test the DFlash speculative drafter or any GPU, so these numbers are a floor, not a ceiling. NVIDIA's GPU numbers will look very different.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small test set.&lt;/strong&gt; 20 prompts Ã— 3 runs is a smoke test, not BFCL. For a fuller picture, NVIDIA reports 67.3 on BFCL-v3 and 74.1 on ToolSandbox for this Q4_K_M build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single tool call per turn.&lt;/strong&gt; I didn't test parallel or chained tool calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthetic audio.&lt;/strong&gt; My "microphone" was Piper's own voice, which is clean speech. Real rooms, accents and background noise will make Whisper's job harder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dates.&lt;/strong&gt; With thinking off, it misread "Friday" in every run. Resolve dates in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variance.&lt;/strong&gt; My first run happened while other jobs were finishing, and its median turn was 3.6 s against 2.1 s in the clean third run. Run your own benchmarks more than once.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Would I use it?
&lt;/h2&gt;

&lt;p&gt;For a local assistant that turns speech into a handful of well-defined actions (timers, lights, calendar, lookups), yes. On a CPU-only VM it picked the right tool 60 out of 60 times, filled the arguments correctly 95% of the time, and completed a whole spoken turn in about four and a half seconds, with no network calls and about 4.7 GB of RAM including speech.&lt;/p&gt;

&lt;p&gt;Where I'd be careful: anything that needs arithmetic on dates or times, long open-ended answers at 11 tokens per second, and noisy audio with a tiny Whisper model. Each of those has a simple fix: resolve dates in code, keep replies short, and use small.en.&lt;/p&gt;

&lt;p&gt;Next I want to run the same loop on a Jetson-class board with the DFlash drafter and see how far that 4.5 seconds drops.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@ishank.iandroid/nvidia-nemotron-3-5-bolt-e4b-running-an-offline-voice-agent-with-tool-calling-on-a-cpu-66ab95a5868a" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>nvidia</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Claude Duet vs Grok Bot vs Muse vs Dots: Always-On AI Agents Compared (2026)</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Sun, 25 Oct 2026 04:47:55 +0000</pubDate>
      <link>https://dev.to/ishank-dev/claude-duet-vs-grok-bot-vs-muse-vs-dots-always-on-ai-agents-compared-2026-526n</link>
      <guid>https://dev.to/ishank-dev/claude-duet-vs-grok-bot-vs-muse-vs-dots-always-on-ai-agents-compared-2026-526n</guid>
      <description>&lt;p&gt;Over six weeks, every big AI lab has shipped the same idea. You don't get a chatbot that waits for you to type. You get an agent with its own computer that works on a schedule, connects to your apps, and asks before it does anything risky.&lt;/p&gt;

&lt;p&gt;I'm a Lead Software Engineer, and I already run one of these every day for my writing workflow. So when Anthropic's Claude Duet launch post passed 41,785 likes and 5.16M views in under a day, I wanted to know how the four actually compare. Hype reels weren't going to answer that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I tested.&lt;/strong&gt; I live in India. I have ChatGPT Go, not Pro, and no Claude subscription. Meta's Muse isn't available in my country. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot (xAI): tested hands-on.&lt;/strong&gt; I've used it daily for weeks, and I ran the specific tests below for this post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Duet (Anthropic): docs-based, not tested.&lt;/strong&gt; I used Anthropic's product page, launch article, help centre and demo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse (Meta): docs-based, not tested.&lt;/strong&gt; I used Meta's newsroom post and help centre.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots (OpenAI): docs-based, not tested.&lt;/strong&gt; I used OpenAI's launch post and help centre.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I checked every price on the official pages on 22 Oct 2026.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "always-on" actually means
&lt;/h2&gt;

&lt;p&gt;All four share the same basic design:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A cloud computer of its own.&lt;/strong&gt; It has a browser and sometimes a shell, so the agent can work while your laptop is shut.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proactive runs.&lt;/strong&gt; Scheduled briefs, monitors and "tell me when" triggers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connectors.&lt;/strong&gt; Mail, calendar, docs and code, all through your own accounts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An approval gate.&lt;/strong&gt; It drafts, and you press the button for anything that sends, pays or deletes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They differ on price, where they're available, and how much of that computer you actually get to use.&lt;/p&gt;




&lt;h2&gt;
  
  
  The comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Price (official pages, checked 22 Oct 2026)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Duet:&lt;/strong&gt; no extra cost on Claude &lt;strong&gt;Pro and Max&lt;/strong&gt; during the research preview. It uses your plan's usage limits, and its background checks count against them. &lt;em&gt;(claude.com, Duet help article)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot:&lt;/strong&gt; &lt;strong&gt;from $30/mo&lt;/strong&gt; (Premium, via X Subscription), with Super at $100 and Ultra at $200. At the 11 Aug 2026 beta launch there was no standalone price. Access came bundled with Cursor Premium Teams ($120/seat), Cursor Ultra ($200) and SuperGrok Heavy ($300), which is where the "$120–300" number in the reels comes from. &lt;em&gt;(x.ai/bot, x.ai news)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse:&lt;/strong&gt; &lt;strong&gt;free tier&lt;/strong&gt; with a weekly limit (card required), &lt;strong&gt;Power $20/mo&lt;/strong&gt; and &lt;strong&gt;Maximum $100/mo&lt;/strong&gt;. &lt;em&gt;(Meta help centre)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots:&lt;/strong&gt; needs &lt;strong&gt;ChatGPT Pro&lt;/strong&gt;, or the Business Premium/Enterprise beta. Free, Go and Plus are excluded. The cheapest Pro tier is $100, which is &lt;strong&gt;₹10,699/mo&lt;/strong&gt; on the Indian App Store. &lt;em&gt;(openai.com, OpenAI help centre)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Availability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duet:&lt;/strong&gt; US-only research preview with a waitlist. Not on Team or Enterprise plans. Works in the iOS/Android apps and on claude.ai.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot:&lt;/strong&gt; generally available on paid plans, and I use it from India.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse:&lt;/strong&gt; US first, plus Canada and Mexico per Meta's coverage. &lt;strong&gt;Not available in India.&lt;/strong&gt; Works in the app, on the web and in WhatsApp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots:&lt;/strong&gt; launched 29 Sep 2026 with a gradual rollout. Pro is excluded only in the EEA, Switzerland and the UK, so India qualifies on paper.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Its own computer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duet:&lt;/strong&gt; a cloud VM with its own browser. You can't yet watch or take over that browser, and it checks in every few hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot:&lt;/strong&gt; a full persistent Linux box with a shell, a browser desktop you can watch or take over, and files that stay between sessions. &lt;em&gt;(Tested, results below.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse:&lt;/strong&gt; the "Muse Secure VM". Logins happen there, and Meta's line is that &lt;strong&gt;Muse never sees your passwords&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots:&lt;/strong&gt; its own cloud computer, running GPT-6 Astra.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approvals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duet:&lt;/strong&gt; asks before it sends, pays, signs or deletes. It &lt;strong&gt;can make payments you approve&lt;/strong&gt; (Anthropic's example is a $640 permit fee), but it &lt;strong&gt;can't move money between accounts&lt;/strong&gt; or trade securities, even with approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot:&lt;/strong&gt; outbound email and messages become a draft card, and nothing leaves until I press Send. Risky actions on its computer get an automatic safety review. &lt;em&gt;(Tested, see below.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse:&lt;/strong&gt; payments go through one-time Link by Stripe cards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots:&lt;/strong&gt; approval before consequential actions, per OpenAI's help centre.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Connectors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duet:&lt;/strong&gt; "more than 6,000 connectors and plugins".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot:&lt;/strong&gt; MCP connectors (Gmail, Notion, GitHub, X and more), plus anything its browser can reach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse:&lt;/strong&gt; Meta apps plus partner integrations (no public count).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots:&lt;/strong&gt; 4,000+ apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Memory
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duet:&lt;/strong&gt; carries over your Claude memory, skills and apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grok Bot:&lt;/strong&gt; persistent memory and saved skills across chats, plus the files on its box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muse:&lt;/strong&gt; personal context across Meta apps (details are thin in the docs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dots:&lt;/strong&gt; builds on your ChatGPT account (memory specifics not spelled out in the launch docs).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What the reels got wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Duet never sees your passwords."&lt;/strong&gt; That's &lt;strong&gt;Meta's claim about Muse&lt;/strong&gt;. Anthropic says logins run in your own cloud computer "so sensitive details stay private", which is close but not the same promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Grok Bot launched at $120–300."&lt;/strong&gt; Those were &lt;strong&gt;bundled plans&lt;/strong&gt;, not a standalone price. It now starts at $30/mo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Duet can't move money."&lt;/strong&gt; Half right. It can't move money between accounts, but it &lt;strong&gt;can&lt;/strong&gt; make a payment you approve.&lt;/li&gt;
&lt;li&gt;Everything else I checked about Duet holds up, including Pro/Max inclusion, the morning brief, meeting prep, follow-ups, 6,000+ connectors and the US-only waitlist. The A/B-test proposal only appears in the demo.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Grok Bot, hands-on
&lt;/h2&gt;

&lt;p&gt;Every test was read-only or sandboxed. Nothing was sent, posted or deleted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Its own computer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed a Python CLI (&lt;code&gt;pip install --user cowsay&lt;/code&gt;) in &lt;strong&gt;0.8 s&lt;/strong&gt;, then ran it again in a later session. &lt;strong&gt;It persisted.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Started a &lt;strong&gt;12-minute background job&lt;/strong&gt; and walked away. Result: all 12 one-minute steps ran and the job finished on its own (started 09:52, done 10:11 IST). Honest caveat: the box sat idle for about 8 minutes mid-run, so the wall-clock time stretched from 12 to about 19 minutes. &lt;strong&gt;Pass, but don't count on exact timing.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Produced a CSV of these results and a PNG chart on the box, ready to hand back in chat. &lt;strong&gt;Pass.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Connectors (read-only)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gmail:&lt;/strong&gt; searched "Medium" over the last 7 days and got back about &lt;strong&gt;201 matching emails&lt;/strong&gt; (25 per page) in about 4 s. &lt;strong&gt;Correct.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notion:&lt;/strong&gt; searched "Medium" and found my "Medium Topics" page at the top in about 4 s. &lt;strong&gt;Correct.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; listed my 5 most recently pushed repos, with push dates, in about 4 s. &lt;strong&gt;Correct.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X:&lt;/strong&gt; read the Claude Duet launch post's public metrics (41,785 likes, 5,155,927 views, 3,174 reposts, 13,141 bookmarks) in about 3 s. &lt;strong&gt;Correct.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's &lt;strong&gt;4/4 connector reads correct&lt;/strong&gt;, each in under 5 s.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Routines (timing)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I scheduled a one-shot routine for &lt;strong&gt;10:05 AM IST&lt;/strong&gt;. It fired at &lt;strong&gt;10:07:58 IST&lt;/strong&gt;, &lt;strong&gt;178 s late&lt;/strong&gt;, and wrote its result to a file on its own. &lt;strong&gt;It fired, but with about a 3-minute drift.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approval before send&lt;/strong&gt;&lt;br&gt;
By design, any outbound email or message becomes a draft card in my chat. It shows the recipient, subject and body, and nothing goes out until I press Send. Declining discards it.&lt;br&gt;
In weeks of daily use, every outgoing email or message has stopped at a draft card that only I can send. When the agent hits a login or a 2FA prompt, it hands me its screen rather than typing a password, and actions it can't undo, like deleting things, wait for my explicit yes. I never saw it send anything on its own.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verdict by use case
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You already pay for Claude Pro/Max and live in the US:&lt;/strong&gt; join the &lt;strong&gt;Duet&lt;/strong&gt; waitlist. You pay nothing extra, your memory carries over, and it has the biggest connector catalogue. The trade-off is preview limits and no control of its browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want a real computer you can watch, script and take over, from anywhere:&lt;/strong&gt; &lt;strong&gt;Grok Bot&lt;/strong&gt;. At $30/mo it's the cheapest paid entry that's available outside the US, and the box behaves like a dev machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want something cheap or free inside WhatsApp and Instagram:&lt;/strong&gt; &lt;strong&gt;Muse&lt;/strong&gt;, if you're in a supported country.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You already pay for ChatGPT Pro:&lt;/strong&gt; &lt;strong&gt;Dots&lt;/strong&gt; is the natural pick. At ₹10,699/mo it's hard to justify just for the agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My honest take: these products have converged fast. Approval gates and cloud computers are standard now. The real differences are &lt;strong&gt;where you live, what you already pay for, and how much of the agent's computer you're allowed to touch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Duet, Muse and Dots sections are docs-based, not tested. Prices checked on official pages 22 Oct 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@ishank.iandroid/claude-duet-vs-grok-bot-vs-muse-vs-dots-always-on-ai-agents-compared-2026-887563c2d19e" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>ScaleDown CDMs: Fast, Cheap Classify, Extract and Summarize Models Tested</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Sat, 24 Oct 2026 04:48:11 +0000</pubDate>
      <link>https://dev.to/ishank-dev/scaledown-cdms-fast-cheap-classify-extract-and-summarize-models-tested-1adp</link>
      <guid>https://dev.to/ishank-dev/scaledown-cdms-fast-cheap-classify-extract-and-summarize-models-tested-1adp</guid>
      <description>&lt;p&gt;Last week ScaleDown launched Constrained Decoding Models (CDMs). The launch post got about 1.8M views. The pitch is simple: most production LLM calls don't need prose. They need a label, a field, or a short summary. So instead of a general model writing an answer token by token, each CDM does one job, reads your input once, and returns a typed result. Pricing is $0.05 per million input tokens (OpenRouter lists $0.04 with a 20% promo), and output is free.&lt;/p&gt;

&lt;p&gt;The launch post made big claims: "200x faster, 467x cheaper than frontier LLM APIs" and "77.2% on DecisionBench". A thread from Bitroot pushed back the next day. Their point was that the 467x has no stated baseline, DecisionBench has no public source, and nobody should trust a classifier result without a few hundred labelled examples and confidence intervals. That's a fair critique, so I built the test around it.&lt;/p&gt;

&lt;p&gt;Here's what I ran, what held up, and what didn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I'm a Lead SWE, so I tested this the way I'd vet any vendor before routing production traffic to it: public labelled data, the same prompts for every engine, and raw results saved to disk.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Classify:&lt;/strong&gt; 300 CLINC150 test utterances (10 intents plus 50 out-of-scope) and 110 Bitext customer-support tickets across 11 categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract:&lt;/strong&gt; 50 SROIE receipts (company, date, address, total) and 30 LinkedIn job posts (company, top of pay range, and work type as an enum).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarize:&lt;/strong&gt; 6 QMSum meeting transcripts (4k to 9k tokens), 2 long ones (31k tokens), and one 369k-token stress doc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Baseline:&lt;/strong&gt; Qwen3 1.7B running locally on Ollama (8-core CPU, no GPU), with the same instructions and JSON-schema-constrained output. I didn't have a frontier API key on this box, so for frontier models I did list-price math from the official pricing pages (checked 22 Oct 2026).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything goes through one OpenAI-compatible base URL. Classify also has a Jev-compatible Decisions endpoint, which is the one I used most:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.scaledown.xyz/v1/scaledown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-api-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SCALEDOWN_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;state&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;how do I reset my pin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;questions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pin_change&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wants to change or reset their PIN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asks for an account balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;none of the above / out of scope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}}},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# {'type': 'choice', 'choice': 'pin_change', 'confidence': 0.979, ...}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each response includes a &lt;code&gt;usage.cost&lt;/code&gt; field. Mine always worked out to exactly $0.05 per million billed input tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Classify: the strongest result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLINC150 (n=300, 10 intents + out-of-scope)   accuracy   95% CI          OOS recall
ScaleDown Decisions (classify-1)              97.3%      94.8 - 98.6%    98%
ScaleDown /classify (rubrics)                 96.7%      94.0 - 98.2%    100%
Qwen3 1.7B local                              90.7%      86.8 - 93.5%    86%

Bitext support tickets (n=110, 11 categories)
ScaleDown Decisions                           92.7%      86.3 - 96.3%
ScaleDown /classify                           90.9%      84.1 - 95.0%
Qwen3 1.7B local                              62.7%      53.4 - 71.2%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The confidence intervals don't overlap with the small local model on either set. On CLINC150 the out-of-scope handling impressed me most. It correctly rejected 49 of 50 out-of-scope queries, and only 6 in-scope queries were wrongly pushed to "oos". That's the failure that hurts in a real router.&lt;/p&gt;

&lt;p&gt;I didn't need any prompt engineering. I wrote one plain-English line per label, and that was it.&lt;/p&gt;

&lt;p&gt;Latency, sequential, measured from a cloud box in India: &lt;strong&gt;p50 162 ms, p95 397 ms&lt;/strong&gt; for Decisions, and p50 134 ms for &lt;code&gt;/classify&lt;/code&gt; with &lt;code&gt;reasoning: false&lt;/code&gt;. The ticket set had a longer tail (p95 about 1.0 s).&lt;/p&gt;

&lt;h2&gt;
  
  
  Extract: good spans, and the misses are interesting
&lt;/h2&gt;

&lt;p&gt;Extract takes a standard &lt;code&gt;response_format&lt;/code&gt; JSON schema. Each property's &lt;code&gt;description&lt;/code&gt; is the search criteria, and every value comes back with a confidence score and character offsets into your input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;the hiring company&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_salary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;the top of the stated salary or pay range&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;work_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Full-time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Contract&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Part-time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;employment type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extract&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;job_post&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;response_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json_schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json_schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="n"&gt;extra_body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;top_n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context_chars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        field acc   valid JSON   spans verbatim   p50 latency
Receipts (50 SROIE)
  ScaleDown Extract     89.5%       100%         100%             1.43 s
  Qwen3 1.7B local      89.5%       100%         94%              3.55 s
Job posts (30)
  ScaleDown Extract     90.0%       100%         n/a              0.60 s
  Qwen3 1.7B local      81.1%       100%         n/a              2.76 s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Per field on receipts, ScaleDown got &lt;strong&gt;100% of totals&lt;/strong&gt; right, compared with 78% for the local model. Totals are the field you actually care about. It was weaker on company names (80% vs 88%).&lt;/p&gt;

&lt;p&gt;Every span ScaleDown returned appeared verbatim in the source text. The citations aren't decoration. You can highlight exactly where a value came from, which is what Bitroot said to check.&lt;/p&gt;

&lt;p&gt;I read every miss, and most were judgment calls rather than hallucinations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The SROIE gold "date" often includes the time (&lt;code&gt;21 MAR 2018 17:59&lt;/code&gt;). ScaleDown returned just the date.&lt;/li&gt;
&lt;li&gt;It returned &lt;code&gt;KING'S CONFECTIONERY S/B&lt;/code&gt; without the registration number the label includes.&lt;/li&gt;
&lt;li&gt;On job posts it sometimes returned the parent company instead of the brand (&lt;code&gt;ManpowerGroup&lt;/code&gt; for an Experis post, &lt;code&gt;HCA Healthcare&lt;/code&gt; for MountainView Hospital).&lt;/li&gt;
&lt;li&gt;One real error: on one bakery delivery receipt it picked the buyer's name and address instead of the seller's. That template appeared 4 times in my random sample, so it cost 8 field points on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Valid JSON was 100% on both engines, but that's partly because I constrained the local model's output with a schema. The bigger difference is that ScaleDown hands back offsets and a confidence score with no extra work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summarize: fast and faithful, but watch the query focus
&lt;/h2&gt;

&lt;p&gt;For summaries I passed the QMSum query as the system instruction and the transcript as the user message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;QMSum meetings, 4k-9k tokens (n=6)   p50       p95       ROUGE-L   summaries w/ invented facts
ScaleDown Summarize                  0.65 s    0.89 s    0.230     0 of 6
Qwen3 1.7B local (CPU)               24.3 s    34.1 s    0.201     2 of 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I checked every number and name in each summary against the transcript. ScaleDown's held up, including the details: a 2.39 average rating, the drop from 15 to 12.50 euros, and the 50 million euro profit target were all there in the source. The local model said one rating used "1 to 5" when the meeting used a seven-point scale. It also called an over-budget prototype "reasonably priced".&lt;/p&gt;

&lt;p&gt;Two weaknesses showed up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query focus.&lt;/strong&gt; In one meeting it summarised the presentation instead of answering "what did the PM question". On both 31k-token transcripts it summarised an adjacent part of the meeting rather than the exact question. It's a summarizer first and a QA model second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The 1M-context claim.&lt;/strong&gt; I sent a 369k-token document made of 12 concatenated meetings and asked for one or two sentences per meeting. It accepted the input and returned in 14.2 s. The summary, though, covered only one of the two distinct meeting series in the document and skipped the other entirely. So it can ingest that much, but don't rely on coverage at that length.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is it really 200x faster?
&lt;/h2&gt;

&lt;p&gt;Not against anything I could measure, and not according to ScaleDown's own docs.&lt;/p&gt;

&lt;p&gt;Against a 1.7B model on my CPU, it was 1.8x faster for short classification, 2.5 to 4.6x for extraction, and about 37x for 6k-token summaries, where CPU prompt processing dominates. A local CPU model isn't a frontier API, though. ScaleDown's own head-to-head benchmark page reports 2.2x to 13.9x faster than each provider's lineup average (2.4x vs OpenAI, 3.8x vs Anthropic). That's a solid speedup, but it's an order of magnitude below the launch post's 200x. I couldn't find what "200x" was measured against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it really 467x cheaper?
&lt;/h2&gt;

&lt;p&gt;The price is real. Every call billed exactly $0.05 per million input tokens, and output was free. The ratio, though, depends entirely on the baseline, and there's a catch: &lt;strong&gt;ScaleDown bills more input tokens than your raw prompt&lt;/strong&gt;. Label criteria, schemas and internal prompts are counted. My classify calls billed about 481 tokens, while the same task as a plain LLM prompt was 172 tokens. Extract calls billed about 1,380 tokens against 571.&lt;/p&gt;

&lt;p&gt;Here's the cost per 1,000 calls at list price, using my measured token counts and leaving out reasoning tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         classify   extract   summarize (6k tok)
ScaleDown CDM            $0.024     $0.069    $0.317
gpt-5-nano               $0.012     $0.057    $0.333     (0.5x - 1.0x)
gpt-5.4-nano             $0.044     $0.204    $1.300     (1.8x - 4.1x)
gpt-5.4-mini             $0.163     $0.752    $4.860     (6.8x - 15x)
Claude Haiku 4.5         $0.210     $0.931    $6.394     (8.7x - 20x)
Claude Sonnet 4.6        $0.631     $2.793    $19.18     (26x - 61x)
gpt-5.5                  $1.089     $5.015    $32.40     (45x - 102x)
Claude Fable 5           $2.102     $9.311    $63.94     (87x - 202x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So against the cheapest small models, ScaleDown costs about the same, and on short classification gpt-5-nano is actually half the price. Against flagship models it's 45x to 200x cheaper. You only reach 467x if the frontier model also spends a few hundred reasoning tokens per call. For example, gpt-5.5 classifying with 500 reasoning tokens works out to roughly 670x. That's realistic for a reasoning model doing routing, but it isn't stated anywhere in the launch post. ScaleDown's own docs are more modest: 89x cheaper than the OpenAI average and 161x cheaper than the Anthropic average.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/classify&lt;/code&gt; endpoint accepts up to 50 &lt;code&gt;chunks&lt;/code&gt; per request and bills the label set once. If you classify at volume, that removes most of the token overhead I measured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; I didn't benchmark Compress or concurrent load this round; my free credits ran out after ~1M input tokens, since the 50M free tokens were a launch-window promo. After that I got &lt;code&gt;402 Insufficient credits&lt;/code&gt;, so budget for a top-up before you run a real eval.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Bitroot got right
&lt;/h2&gt;

&lt;p&gt;The skeptic thread was right on every point I could check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;467x has no stated baseline. I can reproduce it only by assuming an expensive reasoning model.&lt;/li&gt;
&lt;li&gt;I still found no public source for DecisionBench's 77.2%.&lt;/li&gt;
&lt;li&gt;Price is the easy part to verify, and it checks out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their main advice was to build a test set of 300+ labelled examples and report intervals, and that advice is what made this test worth anything. With n=300, the gap between 97% and 91% is real. With n=30 it wouldn't be.&lt;/p&gt;

&lt;h2&gt;
  
  
  My take
&lt;/h2&gt;

&lt;p&gt;I'd route classification traffic to ScaleDown today. It was the most accurate engine I tested, with clean out-of-scope handling, sub-200 ms p50 latency, and no prompt tuning. Extract is a strong default when you need provenance, because every value comes with an offset you can highlight. Summarize is fast and didn't invent facts in my sample, but test its query focus on your own data, and don't trust its coverage of 300k+ token inputs.&lt;/p&gt;

&lt;p&gt;The marketing ratios are a different story. If you already run gpt-5-nano, you won't save much. If you run flagship or reasoning models for routing and extraction, the savings are large and real.&lt;/p&gt;

&lt;p&gt;Test it on your own data. A few hundred labelled examples will tell you more than any launch post, mine included.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>benchmark</category>
    </item>
    <item>
      <title>graphify: Turn Your Codebase into a Knowledge Graph for AI Coding Agents</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Mon, 19 Oct 2026 04:55:12 +0000</pubDate>
      <link>https://dev.to/ishank-dev/graphify-turn-your-codebase-into-a-knowledge-graph-for-ai-coding-agents-kb8</link>
      <guid>https://dev.to/ishank-dev/graphify-turn-your-codebase-into-a-knowledge-graph-for-ai-coding-agents-kb8</guid>
      <description>&lt;p&gt;graphify has been all over my timeline this week: it went past 126k GitHub stars, got into Y Combinator and showed up on the Vercel Marketplace. The pitch is simple. Type &lt;code&gt;/graphify&lt;/code&gt; in Claude Code, Codex or Cursor, and your agent queries a graph of your code instead of reading files one by one.&lt;/p&gt;

&lt;p&gt;"Saves tokens" is an easy claim to make and a hard one to check, so I installed it on a plain Linux box and pointed it at a real repo. No cloud trial, no API keys. Here's what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  What graphify actually is
&lt;/h2&gt;

&lt;p&gt;graphify is an open-source (Apache-2.0) Python CLI plus an agent skill. It parses your project with tree-sitter and writes three files to &lt;code&gt;graphify-out/&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;graph.html&lt;/code&gt;, an interactive force-directed graph you open in a browser&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GRAPH_REPORT.md&lt;/code&gt;, a summary with "god nodes", communities and surprising connections&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;graph.json&lt;/code&gt;, the full graph your agent queries through &lt;code&gt;explain&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code extraction is deterministic and local. An LLM only gets involved for docs, PDFs, images and video, or for naming communities, and only if you configure a backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;My test box runs Debian 13 with Python 3. The PyPI package name has a double y:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
venv/bin/pip &lt;span class="nb"&gt;install &lt;/span&gt;graphifyy      &lt;span class="c"&gt;# installed 0.9.92&lt;/span&gt;
git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 https://github.com/encode/httpx testbed/httpx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the testbed I picked httpx: a real, well-known Python HTTP client with about 17,750 lines of Python plus docs and a changelog. It's big enough to be interesting and small enough that I know roughly what the answers should be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the graph: 2 seconds, 0 tokens
&lt;/h2&gt;

&lt;p&gt;You don't need an assistant for the code-only build. The &lt;code&gt;update&lt;/code&gt; command does it straight from the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;testbed/httpx
graphify update &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Re-extracting code files in . (no LLM needed)...
  AST extraction: 101/101 uncached files (100%) [8 workers]
[graphify watch] Rebuilt: 2233 nodes, 4453 edges, 166 communities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A fresh build took 2.1 seconds. After I edited one file, an incremental rebuild re-parsed only that file and took 1.6 seconds. The report's own footer says &lt;code&gt;Token cost: 0 input · 0 output&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The output is not small: &lt;code&gt;graph.json&lt;/code&gt; is 1.7 MB, &lt;code&gt;graph.html&lt;/code&gt; is 1.9 MB and &lt;code&gt;GRAPH_REPORT.md&lt;/code&gt; is 24 KB. Markdown docs got pulled in as structure too, so &lt;code&gt;CHANGELOG.md&lt;/code&gt; and &lt;code&gt;docs/api.md&lt;/code&gt; show up as nodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwnhumn77yew9usecv44o.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%2Fwnhumn77yew9usecv44o.png" alt="graph.html for httpx" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the report got right
&lt;/h2&gt;

&lt;p&gt;The "god nodes" list is honestly a good first page for a new contributor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Response - 170 edges
2. Request - 111 edges
3. Changelog - 79 edges
4. Client - 69 edges
5. AsyncClient - 51 edges
6. BaseClient - 45 edges
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's httpx's real core. 88% of edges were &lt;code&gt;EXTRACTED&lt;/code&gt; (read directly from the source) and 12% were &lt;code&gt;INFERRED&lt;/code&gt;, with an average confidence of 0.91. I like that every edge carries this tag, because it tells you what to trust.&lt;/p&gt;

&lt;p&gt;"Surprising connections" was less useful. Every entry was a changelog or doc heading linked to &lt;code&gt;Client&lt;/code&gt;, which is true but not surprising.&lt;/p&gt;

&lt;h2&gt;
  
  
  Querying: where the token savings come from
&lt;/h2&gt;

&lt;p&gt;This is what your agent actually runs. I counted every output with tiktoken's cl100k encoding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;graphify explain &lt;span class="s2"&gt;"httpx/_client.py::Client"&lt;/span&gt;
graphify path &lt;span class="s2"&gt;"httpx/_client.py::Client"&lt;/span&gt; &lt;span class="s2"&gt;"DigestAuth"&lt;/span&gt;
graphify query &lt;span class="s2"&gt;"how does a request get sent through the transport"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1573ew9d1tx7w6l98hck.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%2F1573ew9d1tx7w6l98hck.png" alt="explain output" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;explain&lt;/code&gt; on &lt;code&gt;Client&lt;/code&gt; came to 628 tokens. It listed 69 connections with file and line numbers, like &lt;code&gt;--&amp;gt; HTTPTransport [uses] [INFERRED] httpx/_client.py:L731&lt;/code&gt;. Reading &lt;code&gt;_client.py&lt;/code&gt; itself costs 13,659 tokens.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt; returned a 3-hop chain in a single line: &lt;code&gt;Client &amp;lt;-contains- _client.py -imports_from-&amp;gt; _auth.py -contains-&amp;gt; DigestAuth&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;query&lt;/code&gt; came to 1,728 tokens. It ran a BFS that found 536 nodes but showed only 82, and printed a clear &lt;code&gt;TRUNCATED&lt;/code&gt; warning telling me to raise &lt;code&gt;--budget&lt;/code&gt; to 14720 to see everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fscyi5wcg80tgcrziy138.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%2Fscyi5wcg80tgcrziy138.png" alt="path and query output" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So yes, for "where is X and what touches it" questions, a graph lookup is roughly 20x cheaper than dumping the file. What it doesn't do is replace reading the code once the agent has to change a function. The graph points you to the right lines; it doesn't contain them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two rough edges
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ambiguous names.&lt;/strong&gt; &lt;code&gt;graphify explain "Client"&lt;/code&gt; refused to answer, because &lt;code&gt;Client&lt;/code&gt; matched both the class in &lt;code&gt;httpx/_client.py&lt;/code&gt; and a heading in &lt;code&gt;docs/api.md&lt;/code&gt;. The error tells you to use the &lt;code&gt;path::symbol&lt;/code&gt; form, which works, but docs being indexed alongside code means common names collide a lot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Community labels with a small local model.&lt;/strong&gt; Without an API key, the 166 communities are named after a representative file or symbol (&lt;code&gt;test_content.py&lt;/code&gt;, &lt;code&gt;AsyncByteStream&lt;/code&gt;). graphify can rename them with an LLM, Ollama included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;openai     &lt;span class="c"&gt;# the Ollama backend needs it; the first run told me so&lt;/span&gt;
graphify label &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--backend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ollama &lt;span class="nt"&gt;--model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;qwen3:1.7b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On my box, with a 1.7B model on CPU, this ran for more than 11 minutes without finishing, and I killed it. The code graph doesn't need this step at all, but if you want nice labels, give it a real model or an API key. I saw the same kind of small-model limit when I ran &lt;a href="https://medium.com/@ishank.iandroid/i-ran-anatomys-anatomy-skill-on-a-1-7b-local-model-the-kit-passed-every-check-the-figure-was-738-8bdb8bd58cfd" rel="noopener noreferrer"&gt;Anatomy's skill on a 1.7B local model&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it worth installing?
&lt;/h2&gt;

&lt;p&gt;For code, yes. It's free, local and fast, and &lt;code&gt;explain&lt;/code&gt;/&lt;code&gt;path&lt;/code&gt; give an agent a cheap map before it starts opening files. I'd add &lt;code&gt;graphify update .&lt;/code&gt; to a git hook and let the agent use the graph first.&lt;/p&gt;

&lt;p&gt;What I didn't test: the &lt;code&gt;/graphify&lt;/code&gt; skill inside a paid assistant, the semantic pass over PDFs and images, and the hosted Graphify Cloud product with its "80% token savings" claim. My 628-vs-13,659 number is one lookup on one repo, not a benchmark of a whole agent session.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/Graphify-Labs/graphify" rel="noopener noreferrer"&gt;github.com/Graphify-Labs/graphify&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>python</category>
      <category>devtools</category>
    </item>
    <item>
      <title>PlxNative: A Fast Native Plex Client for LG webOS TVs, Built in Rust</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Sat, 17 Oct 2026 04:51:58 +0000</pubDate>
      <link>https://dev.to/ishank-dev/plxnative-a-fast-native-plex-client-for-lg-webos-tvs-built-in-rust-477g</link>
      <guid>https://dev.to/ishank-dev/plxnative-a-fast-native-plex-client-for-lg-webos-tvs-built-in-rust-477g</guid>
      <description>&lt;p&gt;Most smart-TV apps are web pages. On LG's webOS that usually means JavaScript running inside a browser engine, which then hands its output to a compositor before anything reaches the screen. &lt;a href="https://plxnative.com/" rel="noopener noreferrer"&gt;PlxNative&lt;/a&gt; is a Plex client for LG webOS TVs that takes that layer out. Its developer, Gleb Linnik, writes in the &lt;a href="https://github.com/GLinnik21/plx-native" rel="noopener noreferrer"&gt;README&lt;/a&gt;: "No Chromium, no JavaScript, no web view. It just draws."&lt;/p&gt;

&lt;p&gt;This is an explainer, built from the project's README, its docs, its source and its release notes. I don't own an LG TV, so &lt;strong&gt;nothing here was tested on a real television&lt;/strong&gt;. What I did run is the project's own Linux desktop simulator against its mock Plex server, and that section near the end shows exactly what that does and doesn't tell you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What PlxNative is
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An unofficial Plex client for LG webOS TVs.&lt;/strong&gt; It is not made by or affiliated with Plex or LG; the project says so on its site and in &lt;code&gt;TRADEMARKS.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source&lt;/strong&gt; under GPL-3.0-or-later, © 2026 Gleb Linnik. The PlxNative name and brand artwork are excluded from the licence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One person's project.&lt;/strong&gt; The README calls it "one person's spare time".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current release: v0.8.0&lt;/strong&gt;, published on GitHub on 7 October 2026. Nightly builds already report &lt;code&gt;0.9.0-nightly&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Young and active.&lt;/strong&gt; The repository was created on 3 July 2026, and when I checked on 16 October it had 969 stars and 95 forks, with commits landing the same morning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free.&lt;/strong&gt; There's no paid tier. You need a Plex account and a Plex Media Server, and the FAQ confirms a free Plex server works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why it exists
&lt;/h2&gt;

&lt;p&gt;The origin story is short. The developer's 2019 LG TV still had a great picture, but browsing a Plex library on it "felt slower than it needed to." Rather than tune a web app, he wrote a native one. In his words: "I use it every day to watch things off my server in the next room."&lt;/p&gt;

&lt;p&gt;The site makes the argument with a pair of stacks. A typical TV app goes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The app (a web page) -&amp;gt; JavaScript -&amp;gt; Browser engine -&amp;gt; Compositor -&amp;gt; OpenGL -&amp;gt; GPU -&amp;gt; Screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PlxNative goes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The app (native code) -&amp;gt; OpenGL -&amp;gt; GPU -&amp;gt; Screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The claimed result is 60 fps on that 2019 set. I couldn't measure that, and the project itself says the simulator can't either. More on that below.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mostly Rust, with a thin C shell
&lt;/h3&gt;

&lt;p&gt;The repository is overwhelmingly Rust. A rough line count on the current &lt;code&gt;main&lt;/code&gt; gives about 576,000 lines of &lt;code&gt;.rs&lt;/code&gt; files against about 7,300 lines of C and C++. That count includes tests and generated data, so treat it as a ratio, not a measure of features.&lt;/p&gt;

&lt;p&gt;The structure is spelled out in &lt;code&gt;rust-modules/Cargo.toml&lt;/code&gt;. It's a Cargo workspace whose root crate is linked into a small C app as a static library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Static library linked into the C app (hybrid migration): each ported module&lt;/span&gt;
&lt;span class="c"&gt;# exposes the same C ABI its src/*.h declares, so the C code calls it unchanged.&lt;/span&gt;
&lt;span class="nn"&gt;[lib]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"plxnative_modules"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workspace is split into layer crates: &lt;code&gt;base&lt;/code&gt;, &lt;code&gt;machine&lt;/code&gt;, &lt;code&gt;net&lt;/code&gt;, &lt;code&gt;platform&lt;/code&gt;, &lt;code&gt;gfx&lt;/code&gt;, &lt;code&gt;ui&lt;/code&gt;, &lt;code&gt;plex&lt;/code&gt;, &lt;code&gt;telemetry&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;session&lt;/code&gt;, &lt;code&gt;media&lt;/code&gt;, &lt;code&gt;appkit&lt;/code&gt;, &lt;code&gt;screens&lt;/code&gt; and &lt;code&gt;storage&lt;/code&gt;. &lt;code&gt;docs/module-layers.md&lt;/code&gt; describes how they depend on one another.&lt;/p&gt;

&lt;h3&gt;
  
  
  A GPU-drawn interface
&lt;/h3&gt;

&lt;p&gt;The UI goes through SDL2 and OpenGL ES (both are listed in the repo's topics), so there's no DOM and no layout engine. The design language is translucent "glass" panels over your own posters and backdrops, with text sized for reading across a room. The docs folder holds design notes on liquid glass, backdrop blur and a hardware budget for the glass effect, which gives a sense of how much of the work goes into making that look cheap enough for TV silicon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video on the TV's own decoder
&lt;/h3&gt;

&lt;p&gt;Playback doesn't decode video in software. The README says the app "hands video to the same silicon the built-in apps use". In the code, that goes through a video-sink trait in the &lt;code&gt;platform&lt;/code&gt; crate. On the TV it's implemented by a &lt;code&gt;StarfishSink&lt;/code&gt;, which talks to LG's Starfish media APIs, and on the desktop by a &lt;code&gt;HostSink&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What it can direct-play, per the README:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;H.264 and HEVC, including 4K and 10-bit&lt;/li&gt;
&lt;li&gt;Dolby Vision profiles 5 and 8&lt;/li&gt;
&lt;li&gt;E-AC-3 with Atmos&lt;/li&gt;
&lt;li&gt;AV1 or VP9 (10-bit VP9 only on webOS 4 sets), on TVs whose codec table lists that decoder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything else is transcoded by your Plex server. Before you press Play, the detail page shows whether a title will play directly or be converted on the server. The app also ships its own LGPL build of FFmpeg.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;From the README, the site and the 0.8.0 release notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sign in on the TV&lt;/strong&gt; by scanning a QR code with your phone, then pick a Plex Home profile. PIN-protected profiles are supported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browse your own and shared libraries&lt;/strong&gt;, with Continue Watching, Recently Added, sort, filters (including unwatched-only) and an A–Z rail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search across every server you can reach&lt;/strong&gt;, with results grouped by kind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A full player&lt;/strong&gt; with resume, seek and scrub, chapters, audio and subtitle tracks (image subtitles included), Skip Intro, Skip Credits, Up Next with auto-advance, and progress synced back to Plex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New in 0.8.0:&lt;/strong&gt; subtitle search from inside the player, ASS/SSA subtitles that keep their styling, browsing Plex collections, Boost dialog and Normalize loudness on servers with Plex Pass, a Settings section for playback, and Spanish and Belarusian translations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works without internet&lt;/strong&gt; after the first sign-in. The app talks to your server directly, so the library keeps working on your home network when the internet is down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy defaults.&lt;/strong&gt; Crash reports and usage analytics are two separate opt-in questions, both off until you say yes. The README says no title, search term, subtitle line, server name or address can appear in any report. The app talks to your Plex server, to &lt;code&gt;plex.tv&lt;/code&gt; to sign in, and to &lt;code&gt;discover.provider.plex.tv&lt;/code&gt; for cast biographies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;0.8.0 also changes one security behaviour. Some home servers only answer over plain HTTP. Earlier versions refused to send your Plex sign-in that way. 0.8.0 will connect, but only after asking "Connect without encryption?", and only for a server on the same network at a private address after every secure route, Plex's relay included, has failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to install it
&lt;/h2&gt;

&lt;p&gt;PlxNative isn't in the LG Content Store yet; the site says it's "in the process of review" with no confirmed date. There are two routes, and neither needs root.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route 1: LG Developer Mode
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/GLinnik21/plx-native/blob/main/docs/install-and-verify.md" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt; needs an LG TV on webOS 4.0 or newer, a Plex account with a server, and a Mac, Windows or Linux computer on the same network. In short:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create or sign in to an account on LG's developer site.&lt;/li&gt;
&lt;li&gt;Install the &lt;strong&gt;Developer Mode&lt;/strong&gt; app on the TV, sign in, turn on &lt;strong&gt;Dev Mode Status&lt;/strong&gt; (the TV restarts) and then &lt;strong&gt;Key Server&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Note the TV's IP address and passphrase, and connect to it from &lt;strong&gt;webOS Dev Manager&lt;/strong&gt; on your computer.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;.ipk&lt;/code&gt; directly, or install Homebrew Channel first and get PlxNative from its catalogue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a manual download, verify the package first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; ipk.sha256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The catch is renewal. Developer Mode sessions expire, and if one lapses LG removes the apps installed through it. The guide's advice is to open the Developer Mode app and press &lt;strong&gt;EXTEND&lt;/strong&gt; before the remaining time runs out, with a calendar reminder. An expired session can't be extended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route 2: Homebrew Channel
&lt;/h3&gt;

&lt;p&gt;If your TV already runs Homebrew Channel, open it, find &lt;a href="https://repo.webosbrew.org/apps/com.beb.plxnative/" rel="noopener noreferrer"&gt;PlxNative&lt;/a&gt; (a 19.6 MB download, listed as version 0.8.0) and select &lt;strong&gt;Install&lt;/strong&gt;. Updates arrive there too, and the Channel checks the download's checksum before installing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nightlies
&lt;/h3&gt;

&lt;p&gt;Adding &lt;code&gt;https://plxnative.com/nightly/repo.json&lt;/code&gt; to Homebrew Channel installs &lt;strong&gt;PlxNative Nightly&lt;/strong&gt; as a separate app with its own tile and sign-in. The README is blunt about these builds: "It is not tested on a television."&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits and current status
&lt;/h2&gt;

&lt;p&gt;The README has a section titled "The honest scope", and it's worth taking at its word:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Movies and TV shows only.&lt;/strong&gt; No music, no photos, no Live TV or DVR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No typing in server addresses.&lt;/strong&gt; Servers come from your Plex account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relay and secure-only servers&lt;/strong&gt; are supported but "haven't been watched end to end."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not all TVs work.&lt;/strong&gt; It needs webOS 4.0 or newer. A 2016 set on webOS 3.4.3 has been tested and works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The known issues list is specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Some 2019 sets on LG's k5lp or k3lp chip&lt;/strong&gt;, installed through Developer Mode, won't play video. The sandbox withholds a device the video path needs; Kodi and Moonlight hit the same wall. Without root there's no fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2018 sets on webOS 3.9.3&lt;/strong&gt;: sign-in and browsing work, but the prebuilt v0.8.0 never starts video (&lt;a href="https://github.com/GLinnik21/plx-native/issues/249" rel="noopener noreferrer"&gt;#249&lt;/a&gt;). A source build at or after commit &lt;code&gt;60f99c7&lt;/code&gt; fixes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;webOS 3.x&lt;/strong&gt; restarts the stream on every seek instead of jumping in place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sets on the k6hp chip&lt;/strong&gt; show a crash in opt-in reports that the developer can't reproduce without the hardware (&lt;a href="https://github.com/GLinnik21/plx-native/issues/174" rel="noopener noreferrer"&gt;#174&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building the simulator on Linux
&lt;/h2&gt;

&lt;p&gt;Since I couldn't put it on a TV, I built the desktop simulator the docs describe. The box runs Debian 13 on x86_64 with 8 vCPUs and no GPU. The only prerequisites were the SDL2, SDL2_ttf, Mesa, CMake and pkg-config dev packages plus a current stable Rust toolchain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/GLinnik21/plx-native &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;plx-native
make sim-linux &lt;span class="nv"&gt;SIM_TDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rust-modules/target-sim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Compiling plxnative-modules v0.8.0 (/workspace/plxnative/repo/rust-modules)
    Finished `release` profile [optimized] target(s) in 3m 08s
real    3m57.100s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gave a 16 MB &lt;code&gt;plxnative-sim&lt;/code&gt; binary on the first try. The extra 49 seconds went into fetching and building the libass stack (FreeType, FriBidi, HarfBuzz and friends).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft214u6y9hdf8y16dffgr.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%2Ft214u6y9hdf8y16dffgr.png" alt="Building the PlxNative Linux simulator and capturing screens against the mock server" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project's screenshot tool then boots the simulator against &lt;code&gt;tests/mock_pms.py&lt;/code&gt;. That's a synthetic Plex server that also stands in for plex.tv, so no account, token or real library is involved. I ran it headless under Xvfb with software OpenGL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 tools/demo_library.py derive
&lt;span class="nv"&gt;LIBGL_ALWAYS_SOFTWARE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 xvfb-run &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'-screen 0 1920x1080x24'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  python3 tools/screenshots.py &lt;span class="nt"&gt;--bin&lt;/span&gt; rust-modules/target-sim/release/plxnative-sim &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out&lt;/span&gt; shots &lt;span class="nt"&gt;--only&lt;/span&gt; home-shelves,library-grid,search,detail,signin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each scene settled in 2.2 to 4.9 seconds. One hiccup: the &lt;code&gt;home&lt;/code&gt; scene also renders the website's link-preview card, and that step failed because the box lacked the &lt;code&gt;file&lt;/code&gt; utility, so I captured &lt;code&gt;home-shelves&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;The sign-in screen is the QR flow, here pointed at the mock:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi0fkjcucfn6uk843c41v.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%2Fi0fkjcucfn6uk843c41v.png" alt="The PlxNative sign-in screen in the Linux simulator, served by the mock Plex server" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Movies grid, with the sort and filter chips and the A–Z rail, browsing the project's demo library of openly licensed films:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fil4806zl2gzlkn8msn11.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%2Fil4806zl2gzlkn8msn11.png" alt="The Movies library grid in the PlxNative Linux simulator" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And a title page, with the "Direct Play" label next to the runtime:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyvtqoxwn0lj4yoqm8w1.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%2Fkyvtqoxwn0lj4yoqm8w1.png" alt="A title detail page in the PlxNative Linux simulator showing Direct Play" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be clear about what this proves. The simulator runs the same UI and Plex code as the TV build, and it boots, signs in to a fake server and draws every screen I asked for. But &lt;code&gt;docs/building.md&lt;/code&gt; says plainly that it "cannot answer frame rate (different GPU), text rasterization, or anything about LG's decoder and video plane. Those need the set." The Linux build also has no video path at all; the Makefile notes that Play "intentionally reaches the host seam's existing 'no video path' result." So the speed and the hardware decoding, the two things PlxNative exists for, are still unverified by me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who it's for
&lt;/h2&gt;

&lt;p&gt;If you run Plex at home and own a fairly recent LG TV, PlxNative is a well-documented alternative to the official app. Expect a project that tells you about its rough edges in the README. You'll need to be comfortable with Developer Mode renewals or Homebrew Channel until the LG Content Store listing lands. If you need music, Live TV or a set from the known-issues list, the README itself says the official app will serve you better.&lt;/p&gt;

&lt;p&gt;If you're a developer, the repository is interesting on its own terms: a Rust UI stack drawing straight to GPU on TV-grade hardware, with design and performance notes for almost every decision. The simulator builds in a few minutes on plain Linux if you want to look around.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://plxnative.com/" rel="noopener noreferrer"&gt;https://plxnative.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/GLinnik21/plx-native" rel="noopener noreferrer"&gt;https://github.com/GLinnik21/plx-native&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>linux</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Ran Anatomy's /anatomy Skill on a 1.7B Local Model. The Kit Passed Every Check; the Figure Was 738 Bytes.</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Wed, 14 Oct 2026 04:59:13 +0000</pubDate>
      <link>https://dev.to/ishank-dev/i-ran-anatomys-anatomy-skill-on-a-17b-local-model-the-kit-passed-every-check-the-figure-was-512j</link>
      <guid>https://dev.to/ishank-dev/i-ran-anatomys-anatomy-skill-on-a-17b-local-model-the-kit-passed-every-check-the-figure-was-512j</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/wheresryan22/anatomy" rel="noopener noreferrer"&gt;Anatomy&lt;/a&gt; went from a new repo on 8 October to 6,632 GitHub stars by Tuesday morning, 13 October (I checked the GitHub API at 10:31 AM IST). It's an MIT-licensed Agent Skill for Claude Code that also runs in OpenCode, Codex and, as of this week, Antigravity. You type &lt;code&gt;/anatomy&lt;/code&gt; plus an idea, and the agent is supposed to invent a physical machine whose working &lt;em&gt;is&lt;/em&gt; that idea, then build it as an interactive isometric SVG figure out of dozens of small shaded parts.&lt;/p&gt;

&lt;p&gt;The demos are lovely: a Raptor engine that comes apart into 11 assemblies, a ripple tank with WebGL caustics, a dial gauge you can slide. I wanted to know two things the demos can't tell me. Does the machinery underneath actually hold up on a plain Linux box? And how much of the result is the skill, and how much is the model driving it?&lt;/p&gt;

&lt;p&gt;Short version: the kit is real, fast and honest about itself. The skill, though, is written for a strong model, and a small local one doesn't come close. Here's exactly what I ran.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tested and what I didn't
&lt;/h2&gt;

&lt;p&gt;The box is Debian with 8 vCPUs, 16 GB of RAM (about 4 GB free during the test) and no GPU. There was no Claude Code, no Codex and no cloud API key on it. So the agent was &lt;strong&gt;OpenCode 1.19.0&lt;/strong&gt; pointed at a local &lt;strong&gt;qwen3:1.7b&lt;/strong&gt; through Ollama on CPU.&lt;/p&gt;

&lt;p&gt;I tried to pull qwen3:4b as a step up. The download failed on this box's network ("redirect target not allowed"), so 1.7B was the only model I could run.&lt;/p&gt;

&lt;p&gt;That shapes everything below. I tested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The install path, with the &lt;code&gt;skills&lt;/code&gt; CLI the README recommends&lt;/li&gt;
&lt;li&gt;The kit on its own: building the examples, the test suite, the geometry audit, and the headless-Chrome checks&lt;/li&gt;
&lt;li&gt;Three real &lt;code&gt;/anatomy&lt;/code&gt; prompts in OpenCode, taken from the README and the skill's own evals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did &lt;strong&gt;not&lt;/strong&gt; test Claude Code or Codex, or any frontier model. I also skipped the React output, the 3D (beta) mode, the WebGL figures driven by an agent, and the new community-gallery publishing flow. The figures in the README were almost certainly made with a much stronger model than mine, so please read the agent results as "what happens at the bottom end," not as a verdict on the skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install: one Node catch and a different folder
&lt;/h2&gt;

&lt;p&gt;The README's quick start is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add wheresryan22/anatomy &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; opencode &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the box's Node 20.19.2 it crashed immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm WARN EBADENGINE   required: { node: '&amp;gt;=22.20.0' }
SyntaxError: The requested module 'fs/promises' does not provide an export named 'glob'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anatomy itself only needs Node 20.10+, but the &lt;code&gt;skills&lt;/code&gt; CLI (1.7.2 here) needs 22.20+. The README does mention this in a collapsed section, but it's easy to miss. On Node 22.20.0 the same command finished in 7.6 seconds. It showed a security summary ("Gen Safe, Socket 0 alerts, Snyk Low Risk") and copied 13 MB.&lt;/p&gt;

&lt;p&gt;One surprise: it installed to &lt;code&gt;~/.agents/skills/anatomy&lt;/code&gt;, not &lt;code&gt;~/.config/opencode/skills/anatomy&lt;/code&gt; as the README's install table lists for OpenCode. OpenCode found it anyway, since it also reads the &lt;code&gt;.agents&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opencode debug skill
&lt;span class="c"&gt;# ... "name": "anatomy", "location": "/home/box/.agents/skills/anatomy/SKILL.md"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F95jueirxal447v6kfbku.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%2F95jueirxal447v6kfbku.png" alt="Installing Anatomy: the Node 20 crash, then a clean install on Node 22.20" width="799" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The kit on its own: fast, deterministic, and it checks itself
&lt;/h2&gt;

&lt;p&gt;Before involving any model, I ran the parts that don't need one. This is where Anatomy impressed me most.&lt;/p&gt;

&lt;p&gt;The examples rebuild from Node scripts with zero npm dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node examples/dial-indicator/build.mjs
node examples/desk-computer/build.mjs
node examples/arcade-cabinet/build.mjs
git status &lt;span class="nt"&gt;--short&lt;/span&gt;     &lt;span class="c"&gt;# empty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three exited 0, and &lt;code&gt;git status&lt;/code&gt; was clean afterwards. The rebuilt pages were byte-identical to the committed ones, which is exactly what CONTRIBUTING promises. The Raptor engine, the heaviest example, took 115 seconds to build, in line with the README's "a few minutes."&lt;/p&gt;

&lt;p&gt;The test suite ran 225 tests in about 38 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# tests 225
# pass 220
# fail 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All five failures were &lt;code&gt;react-*.test.mjs&lt;/code&gt; files that &lt;code&gt;require&lt;/code&gt; React, which isn't installed. The README says React is only needed for React output, so this is a setup gap rather than a bug. I'd still like those tests to skip cleanly instead of failing.&lt;/p&gt;

&lt;p&gt;The geometry audit is the standout. It doesn't just render the figure. It proves that nothing passes through anything and that every overlap is painted in the right order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ node examples/arcade-cabinet/build.mjs --audit
audit · 15 tubes · 243 solids · 349 items · 1 depth states · 1290 overlaps · 1290 order rules · 11.0 s
audit passed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The headless-Chrome checks worked too, once I set &lt;code&gt;CHROME_PATH&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ node scripts/capture.mjs examples/dial-indicator/dial-indicator-light.html --out dial.png
saved dial.png
clip 395,64 650x485 · readout "block 2 · reads 13.8 px" · scrolls sideways: no
console: clean

$ node scripts/lines.mjs examples/dial-indicator/dial-indicator-light.html
line ends: 0 of 367 ends on 23 lines float
console: clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The capture took about 4 seconds. That readout ("block 2 · reads 13.8 px") comes from the same model that moves the gauge needle, which is the skill's core promise: every number in the figure comes from the figure's own model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4whmjxgtefe67wlvl5y7.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%2F4whmjxgtefe67wlvl5y7.png" alt="The kit on its own: byte-identical builds, 220 of 225 tests, a passing audit" width="799" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what a finished figure looks like, straight from the repo's smallest example and captured by the skill's own script:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F538pd1uxi8eyimzvx7q1.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%2F538pd1uxi8eyimzvx7q1.png" alt="The dial-indicator example rendered by capture.mjs on the test box" width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running /anatomy in OpenCode with a local model
&lt;/h2&gt;

&lt;p&gt;The skill is a 31,600-byte &lt;code&gt;SKILL.md&lt;/code&gt;, plus nine reference guides totalling about 300 KB that the agent is meant to open as needed. When you run the command, OpenCode injects &lt;code&gt;SKILL.md&lt;/code&gt; into the prompt. Ollama's logs put the first request at roughly 7,700 input tokens before the model had written a word. On CPU, just reading that prompt took 45 to 70 seconds, and generation ran at about 4 to 5.5 tokens per second.&lt;/p&gt;

&lt;p&gt;I hit two snags before any figure work began.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;opencode run&lt;/code&gt; sat at "init" for 13 minutes.&lt;/strong&gt; It was waiting on stdin. Adding &lt;code&gt;&amp;lt; /dev/null&lt;/code&gt; fixed it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opencode run &lt;span class="nt"&gt;--model&lt;/span&gt; ollama/qwen3:1.7b &lt;span class="nt"&gt;--command&lt;/span&gt; anatomy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"explain how a token bucket rate limiter works, interactive. Standalone HTML, light theme."&lt;/span&gt; &amp;lt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. The first real run died after five minutes:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ProviderHeaderTimeoutError: Provider response headers timed out after 300000ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenCode waits 300 seconds for response headers by default, and a slow local model with a big prompt can blow past that. Setting &lt;code&gt;headerTimeout: false&lt;/code&gt; and &lt;code&gt;timeout: false&lt;/code&gt; in the provider's options fixed it. That was the only fix I tried.&lt;/p&gt;

&lt;p&gt;Then I ran three prompts from the README and the evals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token bucket rate limiter (standalone HTML, light).&lt;/strong&gt; This one ran for 16 minutes and exited 0, but it wrote no file. The model handed the whole prompt to OpenCode's &lt;code&gt;explore&lt;/code&gt; subagent, which came back empty. It then spent 1,560 tokens thinking and never answered. By the end, the context was 15.8k tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CDN edge cache, hit vs miss, TTL 60 s (just the SVG).&lt;/strong&gt; This one took 8 minutes 23 seconds and two turns, and it did write a file. The file was 738 bytes: three plain circles, two of them labelled "Hit" and "Miss", plus two "60s" labels. It never opened the kit, an example, or a reference. It ran no build or check, even though the skill's workflow ends with "verify it like a critic." It used CSS-style &lt;code&gt;rotateX(-30deg)&lt;/code&gt; inside an SVG &lt;code&gt;transform&lt;/code&gt; attribute, which SVG doesn't support. Chrome ignored those transforms, so the Hit and Miss circles landed stacked on top of each other in the top-left corner, mostly off the canvas. It also wrote the file into the skill's own install folder (&lt;code&gt;~/.agents/skills/anatomy/examples/cdn-cache.svg&lt;/code&gt;), not the project directory. Its closing message: "File written successfully... No further action required."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database connection pool: 10 connections, a queue when all are busy (standalone HTML, dark).&lt;/strong&gt; This one took 10 minutes 37 seconds and again wrote into the skill's &lt;code&gt;examples/&lt;/code&gt; folder. The page is a plain 2D SVG on a black background. The "pool of 10 connections" is two circles drawn at the same spot, followed by the comment &lt;code&gt;&amp;lt;!-- ... (add 10 circles) --&amp;gt;&lt;/code&gt;. The queue is one circle and &lt;code&gt;&amp;lt;!-- ... (add 5 circles) --&amp;gt;&lt;/code&gt;. No isometric camera, no kit, no readout, no motion, and no check. Its last line: "The file was written successfully."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F96uefmfbnqe062jmgjma.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%2F96uefmfbnqe062jmgjma.png" alt="Three /anatomy runs in OpenCode with qwen3:1.7b: timings and results" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's that CDN file as Chrome renders it, at the same size it was written:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsof4xbojlj4k6ft3m6wv.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%2Fsof4xbojlj4k6ft3m6wv.png" alt="The 738-byte CDN SVG the local model wrote, as rendered by Chrome" width="440" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be fair, this is a 1.7-billion-parameter model on CPU being asked to follow a 7,700-token craft manual. The skill tells the model to collect true numbers, invent an object, write a parts list, build the geometry with the kit, and then audit and screenshot every joint. That's a long agentic loop, and a model this small doesn't hold onto it. What the runs do show is that nothing in the skill makes up for a weak model. The kit only helps if the agent actually calls it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked and what broke
&lt;/h2&gt;

&lt;p&gt;Worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The kit: zero dependencies, examples rebuild byte for byte, the Raptor builds in under two minutes&lt;/li&gt;
&lt;li&gt;The geometry audit: 1,290 overlaps checked against 1,290 order rules in 11 seconds, and it passed&lt;/li&gt;
&lt;li&gt;The Chrome checks: screenshots with live readouts, a line-end check, clean consoles&lt;/li&gt;
&lt;li&gt;Skill discovery: OpenCode listed &lt;code&gt;anatomy&lt;/code&gt; right after install, even in an unexpected folder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Broke or surprised me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npx skills add&lt;/code&gt; crashes on Node 20, even though Anatomy itself supports Node 20.10+&lt;/li&gt;
&lt;li&gt;The CLI installs to &lt;code&gt;~/.agents/skills/anatomy&lt;/code&gt;, which differs from the README's OpenCode row&lt;/li&gt;
&lt;li&gt;5 of 225 tests fail without React, instead of skipping&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;opencode run&lt;/code&gt; hangs without &lt;code&gt;&amp;lt; /dev/null&lt;/code&gt;, and its 300-second header timeout kills slow local runs. Both are OpenCode issues, not Anatomy ones&lt;/li&gt;
&lt;li&gt;With qwen3:1.7b, none of the three runs produced a real figure. One wrote nothing. One wrote a 738-byte SVG with invalid transforms. One wrote a 1,049-byte page whose pool of 10 connections is two circles and a comment saying "add 10 circles". Both files landed in the skill's own install folder, and the agent never ran a single check&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Should you use it?
&lt;/h2&gt;

&lt;p&gt;If you write docs or technical posts and you already run Claude Code or Codex with a strong model, yes, it's worth trying. The best part isn't the prompt. It's the kit underneath, which is deterministic and checks itself in ways I haven't seen in other "make me a diagram" tools. Start by building &lt;code&gt;examples/dial-indicator&lt;/code&gt; and reading its roughly 300 lines. That tells you more about the output than any screenshot.&lt;/p&gt;

&lt;p&gt;If you were hoping a local model could drive it, not at 1.7B. The skill is long, and the workflow is long, and the README says it's "slow on purpose." Budget a long session with a capable model, and expect to read the PNGs it makes.&lt;/p&gt;

&lt;p&gt;Not tested here: Claude Code, Codex, any frontier model, the React output, the 3D mode, agent-built WebGL figures, and gallery publishing. If you've run it on a strong model, I'd love to hear how long one figure took you and what it cost in tokens. The new community gallery says it records both.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>svg</category>
      <category>claude</category>
    </item>
    <item>
      <title>I Pointed REA at a 100 MB Electron App. Here's What It Found and the Two Preload Files It Missed.</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Mon, 12 Oct 2026 04:58:58 +0000</pubDate>
      <link>https://dev.to/ishank-dev/i-pointed-rea-at-a-100-mb-electron-app-heres-what-it-found-and-the-two-preload-files-it-missed-502p</link>
      <guid>https://dev.to/ishank-dev/i-pointed-rea-at-a-100-mb-electron-app-heres-what-it-found-and-the-two-preload-files-it-missed-502p</guid>
      <description>&lt;p&gt;On Sunday morning, 11 October, &lt;a href="https://github.com/morluto/rea" rel="noopener noreferrer"&gt;REA&lt;/a&gt; was number one on GitHub's daily trending page, with 25,793 stars gained in a single day. The repo showed 76,998 stars and 16,440 forks. The pitch is simple: "Reverse engineer anything with agents." You install an MCP server, and your coding agent can take apart native binaries, Electron apps, websites, Android APKs and more, then show you the evidence.&lt;/p&gt;

&lt;p&gt;I'm wary of anything that gets that famous that fast, so I skipped the README demos. I installed it on a plain Linux box, pointed it at a real 100 MB Electron app, and then built a tiny app where I know every right answer, to see how well it grades itself.&lt;/p&gt;

&lt;p&gt;Short version: the static JavaScript analysis is genuinely good and fast. It also missed something I could see with grep, and what it asks of an agent is heavy. Details below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tested and what I didn't
&lt;/h2&gt;

&lt;p&gt;The box is Debian 13 with 8 vCPUs and no GPU. There was no Claude Code, Codex or cloud API key on it, so no agent drove REA. I called it from its own CLI and from a small script that speaks raw MCP over stdio. That tests the tools, not an agent's judgment about when to use them.&lt;/p&gt;

&lt;p&gt;REA lists a lot of targets: native binaries, .NET, APKs, firmware, websites, process capture. Native work needs Hopper, Ghidra or IDA, and I had none of the three on this Linux box (the Hopper features are Mac-only). So I stuck to the one target that needs only Node: &lt;strong&gt;JavaScript and Electron apps&lt;/strong&gt;, analyzed statically.&lt;/p&gt;

&lt;p&gt;The real target was PI-Desktop v0.16.1, the Electron app from my previous article. Its &lt;code&gt;app.asar&lt;/code&gt; is 100 MB and holds 459 relevant files. I also built a five-file toy Electron app, because I can't grade a tool on an app whose source I haven't read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install: fast, with one Node catch
&lt;/h2&gt;

&lt;p&gt;REA wants Node 22.19+, 24.11+ or 26+. The box shipped Node 20, so I grabbed 22.20 from nodejs.org. The box has no &lt;code&gt;xz&lt;/code&gt;, so I unpacked the tarball with Python. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;rea-agents@latest
&lt;span class="c"&gt;# added 144 packages, and audited 145 packages in 3s   (node_modules: 96 MB)&lt;/span&gt;
npx rea &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# 6.4.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The version matters. npm lists 31 versions since the package appeared in July, and GitHub shows releases 6.1, 6.2 and 6.3 all on 9 October. 6.4.0 landed on 11 October, the day I tested. The README itself says it "changes quickly", so pin a version.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;rea doctor&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;healthy: false
  node     ok    22.20.0
  host     FAIL  unsupported_host   debian 13
  hopper   FAIL  missing_analysis_engine
  ghidra   FAIL  GHIDRA_INSTALL_DIR is not set
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdzupp6wppcfq2br6byyi.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%2Fdzupp6wppcfq2br6byyi.png" alt="Install, doctor and sandboxed setup output" width="799" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The supported hosts are macOS 12+, Ubuntu 24.04+, Fedora 41+, Nobara, Arch, CachyOS and Omarchy, so Debian 13 gets a red mark. It didn't stop anything I ran. Static JavaScript analysis worked fine on the "unsupported" host. I also ran it once under Node 20, where &lt;code&gt;doctor&lt;/code&gt; flagged the version, and the analysis still ran. I wouldn't rely on that, but it's good to know the check is stricter than the code.&lt;/p&gt;

&lt;p&gt;I didn't want setup touching the box's real config, so I ran it against a throwaway home directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/fakehome npx rea setup &lt;span class="nt"&gt;--client&lt;/span&gt; claude_code &lt;span class="nt"&gt;--dry-run&lt;/span&gt;   &lt;span class="c"&gt;# prints the plan&lt;/span&gt;
&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/fakehome npx rea setup &lt;span class="nt"&gt;--client&lt;/span&gt; claude_code &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;span class="c"&gt;# appliedActions[2]: configured_claude_code, installed_skill&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dry run listed exactly two changes before anything was written. The result was a small &lt;code&gt;mcpServers.rea&lt;/code&gt; entry (&lt;code&gt;npx -y rea-agents@6.4.0 mcp&lt;/code&gt;) and a skill folder with a &lt;code&gt;SKILL.md&lt;/code&gt; and references. Small, clear and reversible. That's how I like setup to behave.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scan: 52 seconds, 3.1 million AST nodes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;time &lt;/span&gt;npx rea analyze-javascript-application app.asar &lt;span class="nt"&gt;--format&lt;/span&gt; json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; out.json
&lt;span class="c"&gt;# real 0m52.2s     out.json: 59.2 MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;REA read 459 files (24.2 MB of text), parsed 421 JavaScript files, walked 3,114,427 AST nodes and had zero parse failures. For a 100 MB bundle, 52 seconds is fine.&lt;/p&gt;

&lt;p&gt;Then I checked its Electron summary against the unpacked source, using plain &lt;code&gt;grep&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fccrnz87ufaqtudgu8ujv.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%2Fccrnz87ufaqtudgu8ujv.png" alt="REA's summary on the real app next to what grep finds" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is where it matched:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser windows:&lt;/strong&gt; REA said 5. There are five &lt;code&gt;new BrowserWindow(&lt;/code&gt; calls (four in one chunk, one in &lt;code&gt;index.js&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;contextBridge APIs:&lt;/strong&gt; REA said 2. The preload scripts call &lt;code&gt;exposeInMainWorld&lt;/code&gt; for &lt;code&gt;piDesktop&lt;/code&gt; and &lt;code&gt;pluginBridge&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPC:&lt;/strong&gt; REA said 4 main-process handlers, 6 renderer transmissions and 5 renderer listeners. My grep counts for &lt;code&gt;ipcMain.handle/on&lt;/code&gt;, &lt;code&gt;ipcRenderer.invoke/send/sendSync&lt;/code&gt; and &lt;code&gt;ipcRenderer.on&lt;/code&gt; come to the same numbers: 4, 6 and 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sender checks:&lt;/strong&gt; it reported 4 places where the main process looks at the sender of an IPC message. I didn't verify each of those by hand, so I'm only passing the number along.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here is what it got wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preload entrypoints: REA said 0.&lt;/strong&gt; The app has two preload files, &lt;code&gt;preload/index.cjs&lt;/code&gt; and &lt;code&gt;preload/plugin-panel.js&lt;/code&gt;. The windows load them through code like &lt;code&gt;join(getModuleDirectory(import.meta.url), "../preload/index.cjs")&lt;/code&gt;. My guess is that this helper call is the reason REA couldn't resolve the path statically, but I haven't confirmed that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposed API members: REA said 0.&lt;/strong&gt; Both bridges obviously expose members, so this zero follows from the missing preload link.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;REA is also candid about what it dropped. The result carries 744 limitations. For 365 of them, the text says: "Expanded application relationships for [file] exceed the parent's result budget; complete static facts were retained on the file node." In plain terms, on a big app it keeps counts and per-file facts but throws away some of the connections between them.&lt;/p&gt;

&lt;p&gt;That cost me the most useful feature on the real app. I asked it to trace anything touching the channel &lt;code&gt;pi-plugin-panel&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;seed_matches: []
coverage.status: no-match
"No graph entity matched the literal seed; this is not evidence that the feature is absent."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The string &lt;code&gt;pi-plugin-panel-drop&lt;/code&gt; is right there in the source. The graph just didn't have channel nodes for it. The tool says so, which I respect, but you'd still be stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  The toy app: where it shines
&lt;/h2&gt;

&lt;p&gt;So I wrote a five-file Electron app (&lt;code&gt;main.js&lt;/code&gt;, &lt;code&gt;preload.js&lt;/code&gt;, &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;renderer.js&lt;/code&gt;, &lt;code&gt;package.json&lt;/code&gt;) with known contents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one window with a preload script&lt;/li&gt;
&lt;li&gt;one &lt;code&gt;contextBridge&lt;/code&gt; API with four members&lt;/li&gt;
&lt;li&gt;three literal IPC channels: &lt;code&gt;notes:read&lt;/code&gt;, &lt;code&gt;notes:write&lt;/code&gt;, &lt;code&gt;open-external&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;one loop that registers &lt;code&gt;job:sync&lt;/code&gt; and &lt;code&gt;job:export&lt;/code&gt; from a variable, and a preload call that builds &lt;code&gt;"job:" + topic&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;two handlers that check the sender, through a small helper function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I analyzed it as written, then again after &lt;code&gt;esbuild --minify&lt;/code&gt;, which squashes &lt;code&gt;main.js&lt;/code&gt; into one 732-byte line with one-letter variable names.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr4oy8qy5ovasep1l6lsv.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%2Fr4oy8qy5ovasep1l6lsv.png" alt="The same toy app, plain and minified, against known ground truth" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On both versions, REA's counts were identical, and nearly all of them were right: 1 window, 1 preload, 1 bridge API with 4 members, 3 literal channels, 2 dynamic channel operations, 4 main handlers, 4 renderer transmissions, 3 of them paired with their handlers (the fourth is the dynamic one). Each run took about two seconds.&lt;/p&gt;

&lt;p&gt;The tracer is the highlight. I fed the evidence back in with &lt;code&gt;trace-application-feature&lt;/code&gt; and a seed of &lt;code&gt;channel: "notes:read"&lt;/code&gt;. It returned the chain I wanted, on the minified bundle: &lt;code&gt;preload.js&lt;/code&gt; invokes the channel &lt;code&gt;notes:read&lt;/code&gt;, and the channel is handled by the &lt;code&gt;notes:read&lt;/code&gt; handler. It even kept the dynamic channel honest. In the minified code the label is &lt;code&gt;"job:"+e&lt;/code&gt;, the actual expression with the renamed variable, rather than a made-up string.&lt;/p&gt;

&lt;p&gt;The one miss on the toy: &lt;strong&gt;sender validation.&lt;/strong&gt; I wrote two handlers that call a &lt;code&gt;checkSender(e)&lt;/code&gt; helper, which looks at &lt;code&gt;e.senderFrame.url&lt;/code&gt;. REA reported 0 sender-validation observations. That's the kind of check you'd want a security-minded tool to notice. A check hidden behind a helper function got past it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part nobody puts in the README: what it costs an agent
&lt;/h2&gt;

&lt;p&gt;REA exposes 170 MCP tools. I opened a stdio session, sent &lt;code&gt;initialize&lt;/code&gt; and &lt;code&gt;tools/list&lt;/code&gt;, and measured the reply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init: 1.4 s    serverInfo: {"name":"rea","version":"6.4.0"}
tools/list: 170 tools in 0.3 s
payload: 1,954,704 bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's about 1.95 MB of JSON before the agent does anything. By the usual rule of thumb of four characters per token, that's roughly half a million tokens, though that's my estimate and clients may defer or trim tool lists. For scale, I run the local model I use for tests with a 16k context. The project's own docs mention a related problem: GitHub Copilot CLI with &lt;code&gt;gpt-4.1&lt;/code&gt; can block chat with REA's full schema profile, and they suggest a "compact" profile. I tried it with &lt;code&gt;REA_MCP_INPUT_SCHEMA_PROFILE=compact&lt;/code&gt;. The list shrank to 1,772,775 bytes, which is 9% smaller. Helpful, not a cure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frs3u5kffyztlaxk9bqqn.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%2Frs3u5kffyztlaxk9bqqn.png" alt="MCP tool list size, summary call and the native-binary error" width="799" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why I didn't try to drive it with a small local model. The tool list alone wouldn't fit in the context window, so any result would say more about my setup than about REA.&lt;/p&gt;

&lt;p&gt;The tool call itself is heavy too. I called &lt;code&gt;analyze_javascript_application&lt;/code&gt; on the same &lt;code&gt;app.asar&lt;/code&gt; over MCP with &lt;code&gt;detail: "summary"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;call: 60.5 s    response: 1,350,868 bytes (text part: 672 KB)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A "summary" that is 672 KB of text is a lot for an agent to read. If you use REA through an agent, I'd expect the agent to spend a lot of its budget on REA's output. I'd test it with your exact client before you commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native binaries: stopped at the door
&lt;/h2&gt;

&lt;p&gt;I did try the native path, to see how it fails. Pointing &lt;code&gt;rea analyze&lt;/code&gt; at PI-Desktop's 20 MB Rust host binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code: provider_unavailable
candidate_ids: ghidra, hopper, ida
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a clear message with a clear fix, and I'd have been disappointed by anything vaguer. &lt;code&gt;rea inspect-artifact&lt;/code&gt; on the same file still worked without a provider. In 1.7 seconds it returned the format (ELF) and a SHA-256 that matches what &lt;code&gt;sha256sum&lt;/code&gt; printed, plus a suggested next step: &lt;code&gt;open_binary&lt;/code&gt;, which needs one of the three engines. So you get identification, not understanding, until you install a disassembler. I didn't, so I can't tell you how good the native side is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked and what didn't
&lt;/h2&gt;

&lt;p&gt;What worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install in 3 seconds, and a setup that shows its plan before writing anything&lt;/li&gt;
&lt;li&gt;Static analysis of a 100 MB Electron app in about 52 seconds, with zero parse failures&lt;/li&gt;
&lt;li&gt;Counts for windows, bridges and IPC that matched my grep on the real app&lt;/li&gt;
&lt;li&gt;Identical, correct results on plain and minified code in my toy app&lt;/li&gt;
&lt;li&gt;An honest evidence trail: limitations listed, "no match" is not claimed as "absent"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What didn't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missed both preload files on the real app, which zeroed out the exposed-API count&lt;/li&gt;
&lt;li&gt;Dropped connections on 365 files because of its own result budget, so the trace on a real channel found nothing&lt;/li&gt;
&lt;li&gt;Missed a sender check hidden behind a helper function&lt;/li&gt;
&lt;li&gt;A 1.95 MB tool list and a 672 KB "summary", which an agent has to carry&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;doctor&lt;/code&gt; goes red on Debian 13 even though the JavaScript path ran fine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I didn't test: Hopper, Ghidra or IDA, websites and browser capture, APKs, firmware, runtime capture, and above all an agent actually using the tools to "build a similar feature", which is the headline pitch. That claim needs a frontier model and a real session, and I didn't have one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you try it?
&lt;/h2&gt;

&lt;p&gt;If you work with Electron or bundled JavaScript, yes. The pairing of fast static analysis and a graph you can trace is useful, and the toy-app result on minified code impressed me more than any star count. Run it on an app you already understand first, the way I did, so you learn where it's blind before you trust it on one you don't.&lt;/p&gt;

&lt;p&gt;If you plan to hand it to an agent, go in with care. Count the tokens in the tool list, try the compact profile, and keep an eye on how much an analysis result takes from the context window.&lt;/p&gt;

&lt;p&gt;As for the trending page: stars tell you people are curious, not whether the tool matches a given job. I couldn't check the claim that it jumped from about 9k stars in four days, because GitHub only gives star timestamps to signed-in API calls. What I could check is that on Sunday morning it was real, MIT-licensed, released four times in three days (6.1 to 6.4), and good at most of the job I gave it. It also missed two files that grep found in a second.&lt;/p&gt;

&lt;p&gt;I'd like to see this on a Mac with Hopper and a frontier model driving it. If you've run REA that way, tell me what held up.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Ran PI-Desktop's Plan, Goal and Subagent Modes on a 1.7B Local Model. Here's What Broke.</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Sat, 10 Oct 2026 04:59:13 +0000</pubDate>
      <link>https://dev.to/ishank-dev/i-ran-pi-desktops-plan-goal-and-subagent-modes-on-a-17b-local-model-heres-what-broke-403f</link>
      <guid>https://dev.to/ishank-dev/i-ran-pi-desktops-plan-goal-and-subagent-modes-on-a-17b-local-model-heres-what-broke-403f</guid>
      <description>&lt;p&gt;Pi, the open-source coding agent engine, reached 1.0 on 1 October. Three days later, on 4 October, &lt;a href="https://github.com/vastsa/PI-Desktop" rel="noopener noreferrer"&gt;PI-Desktop&lt;/a&gt; shipped v0.16.1, the first release built on Pi 1.0.0. PI-Desktop is a desktop GUI for that engine: Electron on the front, a Rust "host core" underneath, and the Pi agent packages running in a Node sidecar.&lt;/p&gt;

&lt;p&gt;One thing to clear up first. PI-Desktop is a &lt;strong&gt;community project by vastsa&lt;/strong&gt;, not something from the Pi team. It's LGPL-3.0, has about 6.4k GitHub stars, and its README calls the 0.16.x line an "Early Preview". Several other projects use the "pi-desktop" name, so if you go looking, start from the repo and the &lt;a href="https://pi-docs.aiuo.net/" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I didn't want to write a feature list. I wanted to know what actually happens when you install it on a plain Linux box and run the three things that set it apart from a terminal agent: &lt;strong&gt;Plan mode, Goal mode and subagents&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest caveat up front
&lt;/h2&gt;

&lt;p&gt;There was no cloud API key on my test machine. So I ran everything against &lt;strong&gt;qwen3:1.7b through Ollama, on CPU only&lt;/strong&gt;: Debian 13, 8 vCPUs, no GPU. That model managed about 250 tokens/s on prompt processing and about 8 tokens/s on generation.&lt;/p&gt;

&lt;p&gt;That is a stress test, not a fair benchmark. A 1.7B model is the weakest setup the app would ever see. Some of what broke is the model's fault, and I'll say which parts. Other things broke regardless of the model, and those are the more useful findings.&lt;/p&gt;

&lt;p&gt;The test project was lukeed/clsx v2.1.1: 21 files and 32 passing tests. Small enough for a tiny model to have a chance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install: fast and uneventful
&lt;/h2&gt;

&lt;p&gt;Linux gets an AppImage, a .deb and an .rpm (glibc 2.35+, so Ubuntu 22.04+, Debian 12+ or Fedora 36+). I used the AppImage, extracted it instead of mounting it so libfuse2 wasn't needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/vastsa/PI-Desktop/releases/download/v0.16.1/PI-Desktop-0.16.1-linux-x86_64.AppImage
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x PI-Desktop-0.16.1-linux-x86_64.AppImage
./PI-Desktop-0.16.1-linux-x86_64.AppImage &lt;span class="nt"&gt;--appimage-extract&lt;/span&gt;
./squashfs-root/AppRun &lt;span class="nt"&gt;--no-sandbox&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I measured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Download:&lt;/strong&gt; 164.8 MB, and the SHA-512 matched &lt;code&gt;latest-linux.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract:&lt;/strong&gt; about 3 seconds, 414 MB on disk. No missing shared libraries according to &lt;code&gt;ldd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First launch:&lt;/strong&gt; the window appeared in &lt;strong&gt;1.56 s&lt;/strong&gt; cold and 0.54 s warm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; about &lt;strong&gt;630 MB RSS&lt;/strong&gt; across the Electron, host-core and sidecar processes, before the agent did anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--no-sandbox&lt;/code&gt;&lt;/strong&gt; was needed only because the extracted tree's &lt;code&gt;chrome-sandbox&lt;/code&gt; isn't setuid. The installed packages shouldn't need it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside the bundle you get Chromium 150, the Rust &lt;code&gt;pi-desktop-host-core&lt;/code&gt; binary, the Pi sidecar, a bundled models.dev catalog of 8,344 models, and two built-in plugins (a browser and a file manager).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fetmfchs5v0jipxc7mbsx.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%2Fetmfchs5v0jipxc7mbsx.png" alt="First launch: the " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first screen is a calm "What can I help you build?" with a Get started checklist. The composer has three chips that matter for this test: the &lt;strong&gt;mode&lt;/strong&gt; (Agent / Plan / Goal), the &lt;strong&gt;permission&lt;/strong&gt; (Ask every time / accept edits / Auto) and the &lt;strong&gt;model&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hooking up a local model
&lt;/h2&gt;

&lt;p&gt;There's no dedicated Ollama tile in 0.16.1. Local models go in through &lt;strong&gt;Settings → Agent → Models → Add provider → Custom endpoint&lt;/strong&gt;, which takes "any OpenAI- or Anthropic-compatible URL".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Base URL:   http://127.0.0.1:11434/v1
API key:    ollama        (dummy)
API format: OpenAI Chat Completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fetch list&lt;/strong&gt; found the model and the provider showed "Connected · 1 model found". The provider list is long, too: subscription sign-ins (Claude Pro/Max, ChatGPT, GitHub Copilot, SuperGrok/X Premium and others) plus around 30 API-key providers.&lt;/p&gt;

&lt;p&gt;A smoke test ("Reply with exactly: PI-Desktop smoke test OK") worked, but it took &lt;strong&gt;1 minute 54 seconds&lt;/strong&gt;, and it showed me the first real number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app's &lt;strong&gt;system prompt plus tool schemas came to about 4.1k tokens&lt;/strong&gt; (Ollama cached 4,098 of 4,717 prompt tokens).&lt;/li&gt;
&lt;li&gt;The context ring in the composer read &lt;strong&gt;96% after one turn&lt;/strong&gt;, because I'd set Ollama to a 16k context and the custom model's context window showed as "— —" in the UI.&lt;/li&gt;
&lt;li&gt;The reasoning setting appended &lt;code&gt;/think&lt;/code&gt; to my prompt (Qwen's reasoning switch), and the model echoed it back in its answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lesson one: when you add a local model, open the model's &lt;strong&gt;Advanced&lt;/strong&gt; settings and set the Context Window yourself. With 16k of context, the harness takes a quarter of it before you type anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plan mode: it worked, but the plan was fiction
&lt;/h2&gt;

&lt;p&gt;I opened the clsx folder as a project, set the chip to &lt;strong&gt;Plan&lt;/strong&gt; with "Ask every time", and asked it to plan a test for nested arrays and falsy values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0me4p8adyatys0yaxlko.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%2F0me4p8adyatys0yaxlko.png" alt="Plan mode result: a plan card with Approve/Reject next to the saved plan file" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mechanics were solid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The plan was saved as a real file, &lt;code&gt;.pi/plan/add-nested-array-falsy-values-tests-for-clsx-20261007-1108.md&lt;/code&gt; (315 bytes).&lt;/li&gt;
&lt;li&gt;A plan card appeared with &lt;strong&gt;Open plan&lt;/strong&gt;, &lt;strong&gt;Reject&lt;/strong&gt; and &lt;strong&gt;Approve (Ask)&lt;/strong&gt;, and the File Manager pane opened showing the markdown.&lt;/li&gt;
&lt;li&gt;The chat got an automatic, sensible title.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The content was not. The plan said to add test files in &lt;code&gt;/work/clsx/tests&lt;/code&gt;, a path that doesn't exist. The run log showed "3 issues · 4 tools": a search failed, a read failed, the first &lt;code&gt;SubmitPlan&lt;/code&gt; failed and the second one succeeded. The app reported "Processed for 5m 19s", but wall-clock time from sending the prompt to seeing the card was about 17 minutes. The context meter sat at 95%.&lt;/p&gt;

&lt;p&gt;That's mostly the model. A 1.7B model with a quarter of its context taken by instructions invents paths. But the workflow around it (a separate artifact, an explicit approval gate) is exactly what I'd want to put in front of a stronger model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal mode: the permission chip changed on its own
&lt;/h2&gt;

&lt;p&gt;Goal mode is meant to write a &lt;code&gt;.pi/goal/*.md&lt;/code&gt; file with an outcome and acceptance criteria, wait for approval, then switch to Agent and work until it can report which criteria it verified.&lt;/p&gt;

&lt;p&gt;I clicked the mode chip twice to get to &lt;strong&gt;Goal&lt;/strong&gt;. Then I noticed the permission chip next to it had &lt;strong&gt;silently switched from "Ask every time" to "Auto"&lt;/strong&gt;. I hadn't touched it. For a mode whose whole job is to run autonomously toward a target, that's the one setting I'd expect it never to loosen on its own.&lt;/p&gt;

&lt;p&gt;The run didn't go well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first model call took 4 min 26 s.&lt;/li&gt;
&lt;li&gt;No goal file and no acceptance criteria were ever written.&lt;/li&gt;
&lt;li&gt;The model went looking in &lt;code&gt;/work/tests&lt;/code&gt; again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbsmunbc7a2nz043f4rta.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%2Fbsmunbc7a2nz043f4rta.png" alt="Goal mode: even under Auto, a Grep on a path outside the workspace triggered a permission prompt" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The safety net did work: even under Auto, a Grep on &lt;code&gt;/work/tests&lt;/code&gt; stopped with "Accesses a path outside the session workspace", rated LOW RISK. I denied it. The model then tried to Edit &lt;code&gt;/work/tests/new-test.js&lt;/code&gt;, which failed. I stopped it at about 12 minutes with nothing verified, and the chat had been auto-renamed in Chinese ("新增嵌套假值测试用例", roughly "add nested falsy value test cases").&lt;/p&gt;

&lt;p&gt;The failed run is the model's fault. The permission flip and the Chinese title happen in the app, and they're worth reporting to the maintainers. Fairly, the docs do say Plan and Goal are "contract modes, not strict read-only security profiles". I'd still check that chip every time you switch modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subagents: the one clean win
&lt;/h2&gt;

&lt;p&gt;PI-Desktop ships five built-in subagents, each with a defined tool set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explorer:&lt;/strong&gt; Read, Glob, Grep, Bash&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code reviewer:&lt;/strong&gt; Read, Glob, Grep (read-only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test runner:&lt;/strong&gt; Read, Glob, Grep, Bash&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixer:&lt;/strong&gt; adds Edit and Write&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI designer:&lt;/strong&gt; adds BrowserPreview, Edit and Write&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhopemr3y9ed0wusi0tpe.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%2Fhopemr3y9ed0wusi0tpe.png" alt="The five built-in subagents in Settings, each with its own tool set" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can add your own as markdown files in &lt;code&gt;~/.agents/subagents/&lt;/code&gt; (up to 16). Delegation uses a &lt;code&gt;Task&lt;/code&gt; tool that runs in the background and returns a delegation ID, with &lt;code&gt;TaskWait&lt;/code&gt;, &lt;code&gt;TaskList&lt;/code&gt; and &lt;code&gt;TaskStop&lt;/code&gt; alongside it, and up to 10 at once per session. Subagents only work in Agent mode.&lt;/p&gt;

&lt;p&gt;In Agent mode I asked: "Use the test-runner subagent to run npm test and report the result."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzie1qcodojr5cyib4t1x.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%2Fzie1qcodojr5cyib4t1x.png" alt="The test-runner subagent asks for approval before running npm test" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This went well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UI drew a small delegation graph: &lt;strong&gt;Main agent → test-runner&lt;/strong&gt;, "Coordinating 1 delegated task".&lt;/li&gt;
&lt;li&gt;The permission prompt said clearly that it was &lt;strong&gt;"Asked by the test-runner subagent"&lt;/strong&gt;, showed the exact command (&lt;code&gt;npm test&lt;/code&gt;) and labelled it &lt;strong&gt;HIGH RISK&lt;/strong&gt;. Running a shell command is the right thing to flag.&lt;/li&gt;
&lt;li&gt;After Allow once, the subagent finished in &lt;strong&gt;2 min 44 s&lt;/strong&gt; (3 steps). The whole turn took 5 min 55 s.&lt;/li&gt;
&lt;li&gt;The result was exit 0, &lt;strong&gt;32/32 passed&lt;/strong&gt;, which matches what I got running &lt;code&gt;npm test&lt;/code&gt; in a shell myself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The subagent's own transcript opened in a side pane marked read-only ("Subagents are driven by the main agent"). And the chat was renamed again, to "npm测试成功" ("npm test succeeded").&lt;/p&gt;

&lt;p&gt;The lesson: give a small model a narrow, well-defined job and the harness carries it. Ask it to plan open-ended work and it falls apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two findings that have nothing to do with the model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. "OS keychain" isn't quite true yet.&lt;/strong&gt; The landing page and the README say credentials live in the OS keychain. I ran gnome-keyring with Secret Service available, saved the Ollama provider, and &lt;strong&gt;zero items&lt;/strong&gt; went into the keyring. Instead, two files appeared:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.pi-desktop/secrets/&amp;lt;sha&amp;gt;.bin    48 B   mode 644
~/.pi-desktop/secrets/.machine-key 32 B   mode 600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project's own storage spec explains it: the shipped backend is an AES-256-GCM file store keyed by a machine key that "host-core generates once and keeps beside them", and the OS keychain backend is one "that neither host-core nor Electron main implements today, so a same-user process that can read the data directory can also decrypt the secrets." The spec is honest about this. The marketing isn't. If you put real cloud keys in it, treat the &lt;code&gt;~/.pi-desktop&lt;/code&gt; folder as sensitive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The window only redraws when the mouse moves.&lt;/strong&gt; On my Xvfb/xfwm4 desktop, timers and streaming output froze until I moved the cursor. That could be specific to my headless setup, but it made the long local runs feel even longer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest, briefly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP Market:&lt;/strong&gt; Settings → Agent → MCP has a Market tab that merges a built-in catalog with the official MCP registry. It listed Memory, Sequential Thinking, Filesystem, Playwright, Context7, Fetch, Git, Time, Serena and others, most marked Verified, each with its npx/uvx command. Some descriptions showed up in Chinese. As of v0.16.1, tools from user-added MCP servers need approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session import:&lt;/strong&gt; it can import sessions from Claude Code, Codex, OpenCode and Pi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled tasks:&lt;/strong&gt; hourly, daily or weekly, but they only run while the app is open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No telemetry and no required account&lt;/strong&gt;, according to the README.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What a bigger cloud model would likely change
&lt;/h2&gt;

&lt;p&gt;I didn't test this, so treat it as an expectation, not a result. With a capable cloud model and a large context window, I'd expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The 4.1k-token system prompt to stop mattering. At 128k+ context it's a rounding error, not 25%.&lt;/li&gt;
&lt;li&gt;Plan mode to produce real paths, since a stronger model would actually read the repo before planning.&lt;/li&gt;
&lt;li&gt;Goal mode to write its acceptance criteria and run through them in minutes, not stall after 12.&lt;/li&gt;
&lt;li&gt;Total time per turn to fall from minutes to seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I don't expect to change: the permission chip flipping to Auto, the keychain wording, the Chinese auto-titles and the redraw bug. Those are in the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;PI-Desktop v0.16.1 installs in seconds, starts in under two, and its Plan, Goal and subagent workflows are thought through: separate artifacts, approval gates, clear risk labels, a visible delegation graph. Subagents did their job even on a 1.7B model on CPU.&lt;/p&gt;

&lt;p&gt;It's also clearly an early preview. Check the permission chip when you switch to Goal, don't trust the "OS keychain" line yet, and set your local model's context window by hand.&lt;/p&gt;

&lt;p&gt;If you run it with a frontier model, I'd like to know whether Goal mode holds up. That's the test I want to see next.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@ishank.iandroid/i-ran-pi-desktops-plan-goal-and-subagent-modes-on-a-1-7b-local-model-here-s-what-broke-f22c7fba6752" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I Pointed Matryoshka's MCP Server at War and Peace and a 10k-Line Log, With No LLM Key</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Wed, 07 Oct 2026 04:54:30 +0000</pubDate>
      <link>https://dev.to/ishank-dev/i-pointed-matryoshkas-mcp-server-at-war-and-peace-and-a-10k-line-log-with-no-llm-key-4f9g</link>
      <guid>https://dev.to/ishank-dev/i-pointed-matryoshkas-mcp-server-at-war-and-peace-and-a-10k-line-log-with-no-llm-key-4f9g</guid>
      <description>&lt;p&gt;When a coding agent needs something from a file that is too big for its context window, it usually does one of two things. It reads the file in slices and hopes the answer is in one of them, or someone has already built a RAG index with chunks and embeddings. Both lose information at the seams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yogthos/Matryoshka" rel="noopener noreferrer"&gt;Matryoshka&lt;/a&gt; takes a third route. It is an open-source TypeScript project by Dmitri Sotnikov (yogthos, the author of the Luminus Clojure framework). It keeps the whole document on the server and gives the agent a small query language to work on it. Results stay server-side, and the agent gets back short "handles" instead of the raw text. The README says it is based on the &lt;a href="https://arxiv.org/abs/2512.24601" rel="noopener noreferrer"&gt;Recursive Language Models paper&lt;/a&gt; by Alex L. Zhang, Tim Kraska and Omar Khattab of MIT CSAIL. Matryoshka is an independent implementation of that idea, not the authors' own code.&lt;/p&gt;

&lt;p&gt;When I checked on 4 October 2026, the repo had 149 stars, 20 forks and no open issues. It is Apache-2.0 licensed, and the latest npm release was &lt;code&gt;matryoshka-rlm&lt;/code&gt; 0.2.40 from 17 May 2026. It's a small project, so I wanted to see how it holds up on real files.&lt;/p&gt;

&lt;p&gt;One constraint shaped the whole test: there was no LLM API key on my machine and no local Ollama. Matryoshka ships an MCP server, &lt;code&gt;lattice-mcp&lt;/code&gt;, that needs no LLM at all. So I played the agent myself and wrote every query by hand. This tests the engine and the tool interface. It says nothing about how well a model would drive them.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works, in one paragraph
&lt;/h3&gt;

&lt;p&gt;The model doesn't write JavaScript or Python. It writes commands in &lt;strong&gt;Nucleus&lt;/strong&gt;, a small S-expression language: &lt;code&gt;(grep "ERROR")&lt;/code&gt;, &lt;code&gt;(filter RESULTS ...)&lt;/code&gt;, &lt;code&gt;(count RESULTS)&lt;/code&gt;, &lt;code&gt;(sum RESULTS)&lt;/code&gt;. The &lt;strong&gt;Lattice&lt;/strong&gt; engine parses and type-checks each command and runs it against the document. Results go into an in-memory SQLite store, and the client gets a stub like &lt;code&gt;$grep_error: Array(1000) [preview...]&lt;/code&gt;. It only pulls real lines with &lt;code&gt;lattice_expand&lt;/code&gt; when it needs them. The README claims this gives "97%+ token savings", and "80%+ token savings compared to reading files directly" for the MCP server. Those are the project's numbers, and I didn't benchmark them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;The box was Linux x86_64 with 8 vCPUs, about 15 GB of RAM, Node 20.19.2 and pnpm 10.33.4. The README suggests &lt;code&gt;pnpm add -g matryoshka-rlm&lt;/code&gt;. I installed it locally in a small Node/TS project instead, next to the official MCP SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add matryoshka-rlm@0.2.40 @modelcontextprotocol/sdk tsx typescript @types/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It finished in 2.5 seconds and took 220 MB of &lt;code&gt;node_modules&lt;/code&gt;. pnpm 10 skipped the native build scripts for the tree-sitter grammars. I left them unbuilt, and symbol listing still worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 1: don't run plain &lt;code&gt;npx lattice-mcp&lt;/code&gt;.&lt;/strong&gt; From a folder where Matryoshka isn't installed, &lt;code&gt;npx lattice-mcp&lt;/code&gt; downloaded an &lt;em&gt;unrelated&lt;/em&gt; npm package called &lt;code&gt;lattice-mcp&lt;/code&gt; (1.6.2), which asked for &lt;code&gt;LATTICE_API_URL&lt;/code&gt; and &lt;code&gt;LATTICE_API_TOKEN&lt;/code&gt;. Use the binary that comes with &lt;code&gt;matryoshka-rlm&lt;/code&gt; (&lt;code&gt;node_modules/.bin/lattice-mcp&lt;/code&gt;, or &lt;code&gt;npx -p matryoshka-rlm lattice-mcp&lt;/code&gt;). The real one prints &lt;code&gt;lattice-mcp v0.2.40&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The client is a few lines of TypeScript with the MCP SDK's stdio transport:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioClientTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioClientTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/workspace/matryoshka-test/client/node_modules/.bin/lattice-mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/workspace/matryoshka-test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// lattice_load only accepts files under this folder&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ishank-test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lattice_load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs/war-and-peace.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lattice_query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(grep "NatÃ¡sha")&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It connected in 409 ms and reported the server as &lt;code&gt;lattice&lt;/code&gt; 0.2.40, with 12 tools: &lt;code&gt;lattice_load&lt;/code&gt;, &lt;code&gt;lattice_query&lt;/code&gt;, &lt;code&gt;lattice_expand&lt;/code&gt;, &lt;code&gt;lattice_close&lt;/code&gt;, &lt;code&gt;lattice_status&lt;/code&gt;, &lt;code&gt;lattice_bindings&lt;/code&gt;, &lt;code&gt;lattice_reset&lt;/code&gt;, &lt;code&gt;lattice_memo&lt;/code&gt;, &lt;code&gt;lattice_memo_delete&lt;/code&gt;, &lt;code&gt;lattice_help&lt;/code&gt;, &lt;code&gt;lattice_llm_respond&lt;/code&gt; and &lt;code&gt;lattice_llm_batch_respond&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The test documents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;War and Peace&lt;/strong&gt; from &lt;a href="https://www.gutenberg.org/ebooks/2600" rel="noopener noreferrer"&gt;Project Gutenberg&lt;/a&gt; (Maude translation): 3.36 MB, 66,041 lines, 566,333 words, about &lt;strong&gt;770,000 tokens&lt;/strong&gt; (769,825 with tiktoken's o200k_base). That is far more than most models' context windows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A real Apache access log&lt;/strong&gt; from &lt;a href="https://github.com/elastic/examples" rel="noopener noreferrer"&gt;Elastic's examples repo&lt;/a&gt;: 10,000 lines (2.37 MB) of traffic from May 2015.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matryoshka's own source files&lt;/strong&gt;, for the code features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before asking Matryoshka anything, I worked out the true answers separately with &lt;code&gt;grep&lt;/code&gt; and a short Python script.&lt;/p&gt;

&lt;h3&gt;
  
  
  War and Peace: facts, counts and quotes
&lt;/h3&gt;

&lt;p&gt;Loading the novel took about 0.75â€“0.8 seconds. Every query after that took between 1 and 430 ms.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What I asked&lt;/th&gt;
&lt;th&gt;Nucleus command&lt;/th&gt;
&lt;th&gt;Matryoshka&lt;/th&gt;
&lt;th&gt;Ground truth&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chapter headings&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(grep "^CHAPTER [IVXLC]+$")&lt;/code&gt; â†’ &lt;code&gt;(count RESULTS)&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;365&lt;/td&gt;
&lt;td&gt;365 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Book headings&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(grep "^BOOK [A-Z]+")&lt;/code&gt; â†’ count&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15 âŒ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mentions of NatÃ¡sha&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(grep "NatÃ¡sha")&lt;/code&gt; â†’ count&lt;/td&gt;
&lt;td&gt;1,213&lt;/td&gt;
&lt;td&gt;1,213 matches âœ… (on 1,197 lines)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pierre lines that also mention NatÃ¡sha&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(filter RESULTS (lambda x (match x "NatÃ¡sha" 0)))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;44 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where is "Genoa"?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(grep "Genoa")&lt;/code&gt; â†’ expand&lt;/td&gt;
&lt;td&gt;lines 840, 1573, 9153&lt;/td&gt;
&lt;td&gt;same âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quote the opening&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(lines 840 846)&lt;/code&gt; â†’ expand&lt;/td&gt;
&lt;td&gt;exact 7-line "Well, Prince, so Genoa and Luccaâ€¦"&lt;/td&gt;
&lt;td&gt;âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mentions of BorodinÃ³&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(grep "BorodinÃ³")&lt;/code&gt; â†’ count&lt;/td&gt;
&lt;td&gt;108&lt;/td&gt;
&lt;td&gt;108 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 2: &lt;code&gt;grep&lt;/code&gt; is case-insensitive and counts matches, not lines.&lt;/strong&gt; The 17 books threw me until I expanded the handle. Two of the hits were ordinary sentences starting with a lowercase "book" ("book from the high desk."). The source confirms that &lt;code&gt;grep&lt;/code&gt; runs with the &lt;code&gt;gmi&lt;/code&gt; flags. It also returns one item per match, so 1,213 is the number of times "NatÃ¡sha" appears, not the 1,197 lines she appears on. Once I knew that, every count matched &lt;code&gt;grep -oi&lt;/code&gt; exactly. A tighter pattern, &lt;code&gt;(grep "^BOOK [A-Z]+: ")&lt;/code&gt;, returned the correct 15.&lt;/p&gt;

&lt;p&gt;The ranked searches showed where the "no RAG" approach has its limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(bm25 "battle of Borodino" 5)&lt;/code&gt; returned five lines that just said "battle." The translation spells it &lt;em&gt;BorodinÃ³&lt;/em&gt;. With the accent, &lt;code&gt;(bm25 "BorodinÃ³ battle" 5)&lt;/code&gt; returned five lines that all contain "battle of BorodinÃ³".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(fuzzy_search "Natasha Rostova" 3)&lt;/code&gt; found nothing. &lt;code&gt;(fuzzy_search "NatÃ¡sha RostÃ³va" 3)&lt;/code&gt; found her straight away.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(semantic "wounded at Austerlitz looking at the sky" 5)&lt;/code&gt; didn't return the famous lines where Prince Andrew lies wounded under "the lofty sky". Its closest hit was "been looking at." on line 15862, seven lines before. Plain &lt;code&gt;(grep "lofty sky")&lt;/code&gt; found the passage at line 15869. The README describes &lt;code&gt;semantic&lt;/code&gt; as TF-IDF cosine similarity, not embeddings, so this isn't surprising.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 3: spell it the way the document does.&lt;/strong&gt; Lexical ranking does not fold accents, so with translated or non-English text an agent should check the document's spelling before trusting a ranked search.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 4: &lt;code&gt;lattice_expand&lt;/code&gt; needs a named handle.&lt;/strong&gt; &lt;code&gt;RESULTS&lt;/code&gt; works inside queries, but &lt;code&gt;lattice_expand&lt;/code&gt; with &lt;code&gt;RESULTS&lt;/code&gt; returns "Invalid handle: RESULTS". &lt;code&gt;lattice_bindings&lt;/code&gt; lists the real names, such as &lt;code&gt;$grep_genoa&lt;/code&gt;. Patterns full of quotes get generic names (&lt;code&gt;$grep&lt;/code&gt;, &lt;code&gt;$grep_2&lt;/code&gt;), so &lt;code&gt;lattice_bindings&lt;/code&gt; is worth calling often.&lt;/p&gt;

&lt;p&gt;Two smaller things worked as documented. Loading &lt;code&gt;/etc/hostname&lt;/code&gt; was refused with "Path outside working directory is not allowed." And a memo I saved with &lt;code&gt;lattice_memo&lt;/code&gt; while the novel was loaded could still be expanded after I switched to the log file.&lt;/p&gt;

&lt;p&gt;How much text actually reached my "agent"? My first session made 27 tool calls against the 3.36 MB novel, and the tool responses added up to 5,625 characters. That's my own count, not a benchmark. A real agent wouldn't read the whole book either, but it shows the design: the document stays on the server and only stubs and the lines you ask for come back.&lt;/p&gt;

&lt;h3&gt;
  
  
  The access log: counting and summing
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What I asked&lt;/th&gt;
&lt;th&gt;Matryoshka&lt;/th&gt;
&lt;th&gt;Ground truth&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;404 responses, &lt;code&gt;(grep "\" 404 ")&lt;/code&gt; â†’ count&lt;/td&gt;
&lt;td&gt;213&lt;/td&gt;
&lt;td&gt;213 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Googlebot requests&lt;/td&gt;
&lt;td&gt;543&lt;/td&gt;
&lt;td&gt;543 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200 responses&lt;/td&gt;
&lt;td&gt;9,126&lt;/td&gt;
&lt;td&gt;9,126 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bytes served with 200, &lt;code&gt;(sum RESULTS)&lt;/code&gt; on the grep result&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,067,060.464&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;âŒ meaningless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same, after &lt;code&gt;(map RESULTS (lambda x (match x "\" 200 (\\d+)" 1)))&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2,735,455,845&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,735,455,845 âœ…&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Gotcha 5: &lt;code&gt;sum&lt;/code&gt; on raw lines adds up the wrong number.&lt;/strong&gt; When you call &lt;code&gt;sum&lt;/code&gt; on grep results, it takes the first number on each line. In an access log, that's the start of the client IP (83.149â€¦), so you get a confident, meaningless total. Pull out the field first with &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;match&lt;/code&gt;, and &lt;code&gt;sum&lt;/code&gt; returns the exact byte count.&lt;/p&gt;

&lt;p&gt;I also tried the sub-LLM path without an LLM. My client doesn't support MCP sampling, so &lt;code&gt;(llm_batch RESULTS (lambda x (llm_query "Is this request from a bot or a human? {item}" (item x) (one_of "bot" "human"))))&lt;/code&gt; over the three 500-error lines returned a single &lt;code&gt;[LLM_BATCH_REQUEST id=â€¦ count=3]&lt;/code&gt; message. It held three ready-made prompts, each with its log line and an "answer with exactly one" instruction. I typed the answers myself (&lt;code&gt;["bot","bot","human"]&lt;/code&gt;) and sent them back with &lt;code&gt;lattice_llm_batch_respond&lt;/code&gt;. Matryoshka stored them as a new handle, and filtering on "bot" counted 2. So the protocol works with any MCP client. To be clear, no model judged those lines. I did.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code files: symbols yes, graph no
&lt;/h3&gt;

&lt;p&gt;On Matryoshka's own &lt;code&gt;lc-solver.ts&lt;/code&gt; (2,658 lines), &lt;code&gt;(list_symbols "function")&lt;/code&gt; returned 20 functions, the same count grep gives for top-level &lt;code&gt;function&lt;/code&gt; declarations. Each came with its line range and signature. &lt;code&gt;(get_symbol_body "evaluate")&lt;/code&gt; returned the function's source, but inline and 64,311 characters long. Unlike search results, it isn't returned as a handle, so a big function goes straight into the agent's context.&lt;/p&gt;

&lt;p&gt;The knowledge graph didn't work for me. &lt;code&gt;(callers ...)&lt;/code&gt; and &lt;code&gt;(god_nodes ...)&lt;/code&gt; returned "No symbol graph available" on all four source files I tried. Each time the server's stderr showed &lt;code&gt;Graph.addEdge: source &amp;amp; target are the same (...)&lt;/code&gt;, with names like &lt;code&gt;evaluate&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt;. The graph library rejects self-loops, so a recursive function or a same-name call seems to stop the graph from being built. That's on 0.2.40 with these four files. I can't say how widespread it is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The REPL and the full RLM CLI
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;lattice-repl docs/war-and-peace.txt&lt;/code&gt; is useful for trying commands out: &lt;code&gt;(grep "Austerlitz")&lt;/code&gt; then &lt;code&gt;(count RESULTS)&lt;/code&gt; gave 51, matching &lt;code&gt;grep -oi&lt;/code&gt;. Piping &lt;code&gt;:load&lt;/code&gt; and a query in together failed, because the load hadn't finished when the query arrived. Passing the file as an argument worked.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rlm&lt;/code&gt; CLI is the part where the LLM writes the Nucleus itself. With no config, it defaults to Ollama on localhost, retried three times, and stopped after about 9 seconds with &lt;code&gt;[aborted: llm 3 consecutive LLM call failures: fetch failed]&lt;/code&gt;. That's expected. It needs a model.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I didn't test
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A real agent choosing Nucleus commands. That is the main promise, and I wrote every command by hand.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rlm&lt;/code&gt; / &lt;code&gt;rlm-mcp&lt;/code&gt; with a model, recursive &lt;code&gt;rlm_query&lt;/code&gt; / &lt;code&gt;rlm_batch&lt;/code&gt;, MCP sampling, compaction and resource limits.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lattice-setup&lt;/code&gt; (Claude Code wiring), the HTTP and pipe adapters, program synthesis, &lt;code&gt;fuse&lt;/code&gt; / &lt;code&gt;dampen&lt;/code&gt; / &lt;code&gt;rerank&lt;/code&gt;, and multi-document loading.&lt;/li&gt;
&lt;li&gt;Any of the README's token-savings figures or the paper's benchmark results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The engine was exact on literal tasks.&lt;/strong&gt; Every count, lookup and quote matched ground truth once I understood the semantics. Most of the work happens on the server, and only stubs come back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The semantics matter more than the syntax.&lt;/strong&gt; Case-insensitive, per-match &lt;code&gt;grep&lt;/code&gt; and first-number &lt;code&gt;sum&lt;/code&gt; are reasonable defaults, but an agent that doesn't know them will report 17 books and a nonsense byte total with full confidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ranked searches are lexical.&lt;/strong&gt; BM25, fuzzy and "semantic" (TF-IDF) depend on exact spelling. Don't expect embedding-style recall.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The code graph is the weak spot in 0.2.40.&lt;/strong&gt; Symbol listing worked, but the call graph failed on every file I tried.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's worth a try if your agent works over big logs, transcripts or books&lt;/strong&gt; and you want answers you can check, not chunk retrieval. Next I want to put a real model in the loop and see whether it avoids these gotchas on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've wired &lt;code&gt;lattice-mcp&lt;/code&gt; into Claude Code or another agent, I'd like to hear whether your model figured out the case-insensitive &lt;code&gt;grep&lt;/code&gt; by itself.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@ishank.iandroid/i-pointed-matryoshkas-mcp-server-at-war-and-peace-and-a-10k-line-log-with-no-llm-key-bcfc95cc81dc" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>typescript</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>I Gave Two TypeScript Agent Sessions One Shared Memory With Hindsight (No LLM Key)</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Mon, 05 Oct 2026 04:50:59 +0000</pubDate>
      <link>https://dev.to/ishank-dev/i-gave-two-typescript-agent-sessions-one-shared-memory-with-hindsight-no-llm-key-1621</link>
      <guid>https://dev.to/ishank-dev/i-gave-two-typescript-agent-sessions-one-shared-memory-with-hindsight-no-llm-key-1621</guid>
      <description>&lt;p&gt;Most of my coding-agent sessions start the same way. The agent rediscovers that the repo uses pnpm, gets told again not to touch the legacy payment file, and trips over the test that only passes in UTC. None of that is in the code. It lives in someone's head, or in a previous session that is gone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt; by Vectorize is built for that gap. It is an open-source agent memory server (MIT) that agents write to and read from across sessions. When I checked on 3 October 2026 its &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; had 44,886 stars, sat second on GitHub's weekly trending page with 16,183 stars that week, and its latest release was v0.10.2 from 29 September.&lt;/p&gt;

&lt;p&gt;I wanted to see what it does in practice, so I installed it on a Linux box and called it from a small Node/TypeScript project. One constraint shaped the whole test: I didn't have an LLM API key on that machine. Hindsight documents a mode for exactly that, so this is a test of its no-LLM floor, not of everything it can do. I've marked clearly which parts I ran and which parts I only read about.&lt;/p&gt;

&lt;h3&gt;
  
  
  The setup
&lt;/h3&gt;

&lt;p&gt;The box was Linux x86_64 with 8 vCPUs, about 15 GB of RAM and Node 20. There was no Docker, so I used the bare-metal path from the README (&lt;code&gt;pip install hindsight-api&lt;/code&gt;), through uv:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv venv .venv-hs &lt;span class="nt"&gt;--python&lt;/span&gt; 3.12
uv pip &lt;span class="nb"&gt;install &lt;/span&gt;hindsight-api&lt;span class="o"&gt;==&lt;/span&gt;0.10.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It resolved 227 packages and finished in 11.6 seconds, including the PyTorch download. The catch is size: the virtual environment came to 6.3 GB, mostly torch and CUDA wheels. Plan disk space accordingly.&lt;/p&gt;

&lt;p&gt;The configuration docs describe &lt;code&gt;HINDSIGHT_API_LLM_PROVIDER=none&lt;/code&gt; as "chunk storage + semantic search only, no API key needed." In this mode retain stores your text as chunks without LLM fact extraction, recall still works, reflect returns HTTP 400, and observations are switched off.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HINDSIGHT_API_LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none
hindsight-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The startup banner showed v0.10.2 with an embedded PostgreSQL (&lt;code&gt;pg0&lt;/code&gt;, started automatically), LLM &lt;code&gt;none / none&lt;/code&gt;, local embeddings (&lt;code&gt;BAAI/bge-small-en-v1.5&lt;/code&gt;), a local reranker (&lt;code&gt;cross-encoder/ms-marco-MiniLM-L-6-v2&lt;/code&gt;), and MCP enabled at &lt;code&gt;/mcp&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first start took about 38 seconds to reach "Uvicorn running", including model downloads from Hugging Face.&lt;/li&gt;
&lt;li&gt;A warm restart took about 19 seconds to a healthy &lt;code&gt;/health&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The worker process used roughly 1.35 GB of resident memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Session 1: one agent writes down what it learned
&lt;/h3&gt;

&lt;p&gt;For the Node/TypeScript side I installed the official client (version 0.10.2) and ran the scripts with &lt;code&gt;tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @vectorize-io/hindsight-client typescript tsx @types/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scenario was a fictional &lt;code&gt;shop-api&lt;/code&gt; repo. The first script plays "Agent A" at the end of a session. It creates a bank, which is Hindsight's isolated memory store, and retains five project facts that aren't obvious from the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/agentA.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HindsightClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vectorize-io/hindsight-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BANK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shop-api-repo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HindsightClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HINDSIGHT_URL&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8888&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;learnings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The shop-api repo uses pnpm, not npm. Run `pnpm test` with Vitest; Jest was removed in March.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tooling&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All money values are stored as integer cents in Postgres (column type bigint). Never use floats for prices.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data model convention&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Route handlers live in src/routes/*.ts and must validate request bodies with zod schemas from src/schemas.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;code convention&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The flaky test checkout.spec.ts fails when TZ is not UTC; CI sets TZ=UTC, so set it locally too.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;debugging note&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Do not touch src/legacy/paypal.ts; it is scheduled for deletion and has no tests.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;team decision&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BANK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;reflectMission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Long-term memory for coding agents working on the shop-api TypeScript repo.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;learnings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BANK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;repo:shop-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`retain: &lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; ms`&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;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The five retains took 184, 42, 46, 56 and 41 ms. Every response reported zero LLM tokens, which is expected with no model. &lt;code&gt;listMemories&lt;/code&gt; showed five memories, all with &lt;code&gt;fact_type: "world"&lt;/code&gt;. In chunks mode that means the text is stored as written: no extracted entities and no restructuring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session 2: a fresh process asks what it should know
&lt;/h3&gt;

&lt;p&gt;The second script is a separate process with a new client and no shared state apart from the bank name. It asks four questions an agent would plausibly ask on day one, then tries &lt;code&gt;reflect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/agentB.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HindsightClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vectorize-io/hindsight-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BANK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shop-api-repo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HindsightClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HINDSIGHT_URL&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8888&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;How do I run the tests in this repo?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;How should I store a product price?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Why does checkout.spec.ts fail on my machine?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Can I refactor the PayPal integration?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BANK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;repo:shop-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Q: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; ms)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;  -&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BANK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;What should a new agent know before editing this repo?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reflect error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what came back:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Query&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;Top result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;How do I run the tests in this repo?&lt;/td&gt;
&lt;td&gt;227 ms&lt;/td&gt;
&lt;td&gt;the pnpm / Vitest note ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How should I store a product price?&lt;/td&gt;
&lt;td&gt;150 ms&lt;/td&gt;
&lt;td&gt;the integer-cents note ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why does checkout.spec.ts fail on my machine?&lt;/td&gt;
&lt;td&gt;62 ms&lt;/td&gt;
&lt;td&gt;the TZ=UTC note ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can I refactor the PayPal integration?&lt;/td&gt;
&lt;td&gt;68 ms&lt;/td&gt;
&lt;td&gt;the legacy/paypal.ts note ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The right memory came first on all four questions. Two caveats keep that in proportion. The bank had five entries, so every query returned all five, and what I was really seeing was ranking, not filtering. The second result was sometimes unrelated: the price question had the TZ note in second place. That's fine for a toy, but on a real bank you would want the &lt;code&gt;maxTokens&lt;/code&gt; budget or the &lt;code&gt;minScores&lt;/code&gt; floors the client exposes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reflect&lt;/code&gt; failed exactly as documented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reflect requires an LLM provider. Current provider is set to 'none'.
Set HINDSIGHT_API_LLM_PROVIDER to a real provider (e.g., openai, anthropic, gemini).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I stopped the server, started it again and re-ran Agent B. The top results didn't change (201 ms and 91 ms on the first two queries), so the memories live on disk in the embedded Postgres, not just in the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  A third client over MCP
&lt;/h3&gt;

&lt;p&gt;Every Hindsight server exposes a Model Context Protocol endpoint per bank at &lt;code&gt;/mcp/{bank_id}/&lt;/code&gt;. I talked to it with plain curl. You send an &lt;code&gt;initialize&lt;/code&gt; request, read back the &lt;code&gt;mcp-session-id&lt;/code&gt; header, and send that header with each later call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; hdr.txt &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8888/mcp/shop-api-repo/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: application/json, text/event-stream'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'&lt;/span&gt;

&lt;span class="nv"&gt;SID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; mcp-session-id hdr.txt | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'\r'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8888/mcp/shop-api-repo/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: application/json, text/event-stream'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"mcp-session-id: &lt;/span&gt;&lt;span class="nv"&gt;$SID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"recall","arguments":{"query":"which package manager and test runner?"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server identified itself as &lt;code&gt;hindsight-mcp-server 0.10.2&lt;/code&gt;, and &lt;code&gt;tools/list&lt;/code&gt; returned 36 tools. They cover retain and recall, reflect, mental models, directives, memory and document management, operations, tags, bank settings and knowledge-page CRUD. The recall call returned the pnpm/Vitest memory that Agent A had written through the TypeScript SDK. The SDK and MCP both work against the same bank, so a TypeScript service and any MCP-capable agent can share one memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the coding-agent installer actually wires up
&lt;/h3&gt;

&lt;p&gt;Coding agents are the headline use case. Vectorize ships &lt;code&gt;@vectorize-io/hindsight-coding-agents&lt;/code&gt;, and the version I tried (0.8.0) lists 20 harnesses in its installer: Claude Code, Codex, Cursor CLI, GitHub Copilot CLI, opencode, Grok Build, Cline CLI, Devin CLI, Antigravity CLI, Qwen Code, Kimi Code, DeepSeek Harness and more.&lt;/p&gt;

&lt;p&gt;I did &lt;strong&gt;not&lt;/strong&gt; run a real coding-agent session. The only agent the installer detected on the box was a Cursor CLI install that other tools share, and I didn't want to change its config. I installed the integration into a throwaway home directory instead and inspected what it writes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./fakehome npx &lt;span class="nt"&gt;-y&lt;/span&gt; @vectorize-io/hindsight-coding-agents &lt;span class="nb"&gt;install &lt;/span&gt;cursor-cli &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--server&lt;/span&gt; self-hosted &lt;span class="nt"&gt;--api-url&lt;/span&gt; http://localhost:8888
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reported hooks merged into &lt;code&gt;~/.cursor/hooks.json&lt;/code&gt;, an MCP server added to &lt;code&gt;~/.cursor/mcp.json&lt;/code&gt;, and a skill installed under &lt;code&gt;~/.cursor/skills/hindsight-coding-agent&lt;/code&gt;. Here are the hooks it wrote (paths shortened):&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;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sessionStart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.../cursor-sessionstart-hook.js&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"beforeSubmitPrompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.../cursor-hook.js&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.../cursor-stop-hook.js&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP entry runs a local stdio server, &lt;code&gt;node ~/.hindsight/coding-agents/dist/mcp-server.js ${workspaceFolder}&lt;/code&gt;. I started that server myself with my Node project as the workspace and listed its tools. It has eight: &lt;code&gt;hindsight_sync_status&lt;/code&gt;, &lt;code&gt;hindsight_diagnose&lt;/code&gt;, &lt;code&gt;hindsight_search_knowledge_pages&lt;/code&gt;, &lt;code&gt;hindsight_list_knowledge_pages&lt;/code&gt;, &lt;code&gt;hindsight_read_knowledge_page&lt;/code&gt;, &lt;code&gt;hindsight_reflect&lt;/code&gt;, &lt;code&gt;hindsight_capture_initiative&lt;/code&gt; and &lt;code&gt;hindsight_ingest_document&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hindsight_diagnose&lt;/code&gt; resolved the project to a bank called &lt;code&gt;coding-agent::node-agents&lt;/code&gt; on my local server. &lt;code&gt;hindsight_sync_status&lt;/code&gt; reported &lt;code&gt;synced: false&lt;/code&gt;, no git log and zero knowledge pages. That fits the docs, which say ingestion of git history and past sessions starts from the session-start hook, and I never fired that hook with a real agent. So I can show you the wiring, but not how it behaves inside an agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I could not test
&lt;/h3&gt;

&lt;p&gt;All of the following needs an LLM, so I can only describe it from Vectorize's docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fact extraction on retain.&lt;/strong&gt; With a model, retain pulls out facts, entities, relationships and dates instead of storing raw chunks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observations.&lt;/strong&gt; Related facts are consolidated in the background into deduplicated beliefs that keep their supporting evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflect.&lt;/strong&gt; A slower, reasoning pass over the bank, as opposed to a lookup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mental models and knowledge pages.&lt;/strong&gt; Standing answers and wiki-like pages that the bank rewrites as it learns. The coding-agent integration builds on these.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The LLM wrapper&lt;/strong&gt; (&lt;code&gt;hindsight-litellm&lt;/code&gt;), which recalls and retains automatically around each model call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks.&lt;/strong&gt; The README says Hindsight is state of the art on LongMemEval and that Virginia Tech's Sanghani Center and The Washington Post independently reproduced its results. I didn't benchmark anything, and five memories prove nothing about accuracy at scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Should you try it?
&lt;/h3&gt;

&lt;p&gt;Here is what I can say from what I ran. The install is quick but large. The server starts with no external services and no API key. The TypeScript client is simple. Memories persist across restarts. One bank serves both SDK calls and MCP tool calls, and on my small, deliberately easy set of questions recall put the right note first every time.&lt;/p&gt;

&lt;p&gt;Without a model, though, Hindsight is a well-packaged local vector-plus-keyword store with an MCP front end. The "learning" in its tagline (extraction, observations, reflect, knowledge pages) is the part that needs an LLM, and that is the part I haven't verified. If you have a key, or a local model through Ollama or LM Studio (both are supported providers), that is where I'd point the next test. If you don't, the &lt;code&gt;none&lt;/code&gt; mode is still an honest, quick way to see whether the API and the bank model fit your agent setup before you spend tokens.&lt;/p&gt;

&lt;p&gt;Have you put Hindsight or another memory layer behind your coding agents? I'd like to hear in the comments what actually stuck between sessions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@ishank.iandroid/i-gave-two-typescript-agent-sessions-one-shared-memory-with-hindsight-no-llm-key-481d81426bd2" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>mcp</category>
      <category>agents</category>
    </item>
    <item>
      <title>ChatGPT Dots: What OpenAI's Always-On Agents Mean for How I Work as a Lead SWE</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Wed, 30 Sep 2026 04:04:38 +0000</pubDate>
      <link>https://dev.to/ishank-dev/chatgpt-dots-what-openais-always-on-agents-mean-for-how-i-work-as-a-lead-swe-2103</link>
      <guid>https://dev.to/ishank-dev/chatgpt-dots-what-openais-always-on-agents-mean-for-how-i-work-as-a-lead-swe-2103</guid>
      <description>&lt;p&gt;Have you ever closed your laptop at night knowing that three things will quietly rot while you sleep? A flaky test nobody owns. A customer complaint that will sit in a Slack thread until someone has "a minute". A proposal doc that is already out of date because the requirements changed at 6 PM. As a Lead Software Engineer, most of my job isn't writing code. It's keeping a dozen half-finished threads from falling on the floor.&lt;/p&gt;

&lt;p&gt;So when OpenAI published "Introducing dots" on September 29, 2026, I didn't skim it. I read it the way I read an RFC: slowly, looking for the parts that are concrete and the parts that are just vibes. This post is my breakdown. Everything here about the product comes straight from OpenAI's announcement. Where I'm speculating or giving my own opinion, I'll say so clearly.&lt;/p&gt;

&lt;h3&gt;
  
  
  So What Exactly Are Dots?
&lt;/h3&gt;

&lt;p&gt;In OpenAI's words, dots are "remarkably capable, always-on agents" that live in ChatGPT. The pitch is simple: an assistant that gets to know what matters to you, keeps working on your behalf, and takes work off your plate so you get your time and attention back.&lt;/p&gt;

&lt;p&gt;The concrete details are what caught my eye as an engineer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; Dots are powered by &lt;strong&gt;GPT-6 Astra&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute:&lt;/strong&gt; Each dot has &lt;strong&gt;its own cloud computer&lt;/strong&gt; and its own browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always on:&lt;/strong&gt; Dots can work toward your goals &lt;strong&gt;24/7&lt;/strong&gt;, and they learn from your feedback over time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrations:&lt;/strong&gt; Through OpenAI's plugin ecosystem, dots can connect to &lt;strong&gt;over 4,000 apps&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You start with a single &lt;strong&gt;primary dot&lt;/strong&gt;. You give it a name and make it your own. OpenAI says that over time they envision &lt;em&gt;teams&lt;/em&gt; of dots working together for you, but today the starting point is one dot per person.&lt;/p&gt;

&lt;p&gt;That's the part that matters to me. This isn't a chat window that forgets you when you close the tab. It's a persistent worker with its own machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dot as a Coworker, Not a Chatbot
&lt;/h3&gt;

&lt;p&gt;The mental model shift here is bigger than it looks. With a normal chat assistant, I'm the scheduler. I decide when it runs, I paste in context, and I babysit every step.&lt;/p&gt;

&lt;p&gt;OpenAI describes dots differently. Your dot can take a project and run with it, even while it's working on several others. You can keep handing it new tasks and ideas without juggling separate threads or directing every step. The more you work together, the more it learns your preferences, how you think, and, in OpenAI's phrase, "what good looks like to you."&lt;/p&gt;

&lt;p&gt;There's also a proactive side. OpenAI says the magic is when a dot brings you work done the way you would do it, "sometimes before you even think to ask." They share a few internal examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bug shows up in Slack, and dots immediately start investigating.&lt;/li&gt;
&lt;li&gt;A new design arrives, and dots turn it into a working app while the team focuses on customer feedback.&lt;/li&gt;
&lt;li&gt;A planning cycle starts, and dots keep everyone moving in sync toward the deadline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My favourite example is the least flashy one. An early tester's dot noticed he had forgotten to invoice a publication. It prepared the invoice and sent it &lt;strong&gt;after his approval&lt;/strong&gt;. That last bit matters, and I'll come back to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Actually Works Under the Hood
&lt;/h3&gt;

&lt;p&gt;Here's what the announcement says about mechanics. No speculation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Its own computer.&lt;/strong&gt; Dots can do nearly anything using their own cloud computer, their own browser, and the apps you've connected. You can open your dot's computer at any time to inspect its work. As someone who has debugged plenty of "the agent said it did it" situations, being able to look at the actual machine is the feature I care about most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your devices, if you allow it.&lt;/strong&gt; Dots can connect to other devices besides their own. You can also give your dot permission to connect to and use your laptop, so it can work directly alongside you. That's opt-in. Your computer stays separate unless you choose to connect it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proactive research.&lt;/strong&gt; When you aren't actively working with it, your dot looks for ways to help in the background. OpenAI calls this "proactive research." The important constraint is that this runs on the apps you've already connected, using tools that are &lt;strong&gt;restricted to be read-only&lt;/strong&gt;. In background mode it can't send messages, change app content, or control your browser or computer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where you talk to it.&lt;/strong&gt; You can message &lt;em&gt;or call&lt;/em&gt; your dot in ChatGPT on desktop, web, and mobile. You can also message it in &lt;strong&gt;Slack and Teams&lt;/strong&gt;, and OpenAI says texting is coming soon. Dots carry context across every channel. So I could start something in ChatGPT, drop context in a team Slack channel, and the dot follows through with the full picture. It can also message &lt;em&gt;you&lt;/em&gt; with progress, questions, or decisions that need you.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Scenario That Made Me Sit Up
&lt;/h3&gt;

&lt;p&gt;OpenAI lists several "extension of you" scenarios: a launch lead, a scientist, a sales lead, a content creator. The first one describes my world almost exactly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're a developer working on an app. Your dot watches customer feedback for recurring requests, scopes smaller improvements and bugfixes, builds and tests them, and brings you complete PRs to review with attached videos showing the changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read that again as a tech lead. The long tail of small fixes, like the copy tweak, the edge-case crash, or the "can we add a sort option" request, is exactly the work that never makes it into a sprint. It isn't hard. It just never beats the big feature for priority.&lt;/p&gt;

&lt;p&gt;If a dot can really turn that backlog into reviewable PRs with videos attached, my role moves further toward reviewer and editor. I'd keep building the next major feature, and the dot would work the queue. The key word in OpenAI's description is &lt;strong&gt;review&lt;/strong&gt;. The dot brings me PRs. It doesn't merge them.&lt;/p&gt;

&lt;p&gt;To be clear, I haven't benchmarked this, and OpenAI doesn't publish benchmarks or success rates for it in the announcement. I'm treating it as a stated design goal, not a proven throughput number.&lt;/p&gt;

&lt;h3&gt;
  
  
  You're Always in Control (and This Is the Part I Read Twice)
&lt;/h3&gt;

&lt;p&gt;Any agent with its own computer and access to 4,000+ apps should make an engineer nervous. OpenAI spends a big chunk of the announcement on safeguards, and they're more specific than I expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolation by default.&lt;/strong&gt; Each dot works on its own cloud computer. Your computer and its contents stay separate unless you connect it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Passwords stay hidden from the model.&lt;/strong&gt; For signing into supported websites, dots can use saved passwords &lt;strong&gt;without exposing them to the model&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring.&lt;/strong&gt; Built-in security safeguards help defend against malicious instructions and watch for potentially harmful behaviour. If monitoring detects a safety concern, it can pause or stop the dot's work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions you already know.&lt;/strong&gt; You choose which apps your dot can access and manage those permissions through your existing ChatGPT app controls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Rules.&lt;/strong&gt; Dots start with built-in rules for when to act on their own and when to ask for approval. Custom Rules let you allow specific actions, require approval, or block them. Built-in safety requirements always apply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activity View.&lt;/strong&gt; You can follow progress, including background work, and redirect your dot as needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-review.&lt;/strong&gt; Actions that could affect your accounts or share information are checked against your instructions, Custom Rules, and safety requirements. This decides what can proceed, what needs your approval, and what you have to do yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some things never leave your hands.&lt;/strong&gt; Certain sensitive tasks, such as &lt;strong&gt;changing a password&lt;/strong&gt;, always stay with you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On data, OpenAI says it doesn't use content from ChatGPT Business, Enterprise, or Edu workspaces to improve its models by default. On personal plans, you can control whether your dot's conversations and work are used for training. They also say they don't train directly on proactive research or your dot's notes to itself.&lt;/p&gt;

&lt;p&gt;And there's one line I want every engineer to tattoo somewhere: &lt;strong&gt;"Dots can still make mistakes, so always review consequential work."&lt;/strong&gt; OpenAI points to a dedicated dots safety blog, its Help Center, and a system card for more detail.&lt;/p&gt;

&lt;p&gt;My take: this is the right shape. Default-deny for risky actions, read-only background mode, human approval for anything consequential, and a visible audit trail. It's basically how I'd want a new junior engineer onboarded: broad read access, narrow write access, and a reviewer on every merge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specialist Dots: The Enterprise Angle
&lt;/h3&gt;

&lt;p&gt;Beyond your personal dot, OpenAI is previewing &lt;strong&gt;specialist dots&lt;/strong&gt;. These take on dedicated responsibilities inside an organization rather than working on behalf of one person.&lt;/p&gt;

&lt;p&gt;Per the announcement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your company sets up each specialist dot with its &lt;strong&gt;own identity&lt;/strong&gt;, credentials, and access to the systems it needs.&lt;/li&gt;
&lt;li&gt;The preview includes identity for access management, &lt;strong&gt;IT-provisioned hardware&lt;/strong&gt;, and deep integrations with a company's systems of record.&lt;/li&gt;
&lt;li&gt;The dot adapts to new information and improves with feedback from your team.&lt;/li&gt;
&lt;li&gt;OpenAI is building on internal testing across &lt;strong&gt;procurement, invoice processing, email marketing, customer support, and commercial contracting&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is starting with &lt;strong&gt;focused enterprise pilots&lt;/strong&gt;, where OpenAI's engineering teams work directly with organizations to define each dot's responsibilities, the tools it can use, and how people review and approve its work.&lt;/p&gt;

&lt;p&gt;OpenAI is also working with &lt;strong&gt;Microsoft&lt;/strong&gt; to integrate specialist dots with Microsoft's enterprise governance and security controls in &lt;strong&gt;Agent 365&lt;/strong&gt;, so businesses can manage dots with the Microsoft tools they already use.&lt;/p&gt;

&lt;p&gt;For those of us who've fought with service accounts and shared credentials, giving an agent its &lt;em&gt;own identity&lt;/em&gt; is a big deal. It means the audit logs can say "the procurement dot did this" instead of "someone using Dave's token did this."&lt;/p&gt;

&lt;h3&gt;
  
  
  Availability, Pricing, and Limits
&lt;/h3&gt;

&lt;p&gt;Here's the practical part, straight from the announcement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Who gets it now:&lt;/strong&gt; Dots are rolling out in ChatGPT to &lt;strong&gt;Pro and Business Premium&lt;/strong&gt; users in eligible markets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise:&lt;/strong&gt; Enterprise users (including Edu and Healthcare) can try the &lt;strong&gt;beta&lt;/strong&gt; once their workspace admin enables it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More users:&lt;/strong&gt; OpenAI says it plans to expand dots to more users soon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; Your first dot is included in Pro or Business Premium at &lt;strong&gt;no extra cost&lt;/strong&gt;. It's available 24/7 to talk and help you think.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deeper work:&lt;/strong&gt; Your plan includes an allowance for deeper work, with &lt;strong&gt;extended limits for the first month&lt;/strong&gt; after launch. OpenAI doesn't publish specific numbers for that allowance in the announcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage limits:&lt;/strong&gt; Conversations with your dot &lt;strong&gt;don't count toward your ChatGPT usage limits&lt;/strong&gt;. But when you ask your dot to start or manage tasks in &lt;strong&gt;Codex or ChatGPT Work&lt;/strong&gt;, those tasks count toward your limits as usual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Later:&lt;/strong&gt; OpenAI says you'll eventually be able to add more dots and scale each one's output by increasing its speed or the total amount of work it can take on per month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup:&lt;/strong&gt; Create your first dot in the ChatGPT &lt;strong&gt;desktop app or a desktop browser&lt;/strong&gt;, connect your apps, and let it introduce itself. After that initial setup, you can message it from the ChatGPT mobile app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That usage-limit detail is easy to miss and worth planning around. Chatting with your dot is "free" against limits, but delegating real Codex work isn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I'm Planning My First Week With a Dot
&lt;/h3&gt;

&lt;p&gt;This is my own plan, not an OpenAI recommendation. If you lead a team, it might be a useful starting template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Week 1 — dot onboarding plan (my notes)
Day 1: Create the dot on desktop, name it, connect only Slack + GitHub + calendar
Day 2: Set Custom Rules — require approval for anything that posts, merges, or emails
Day 3: Let proactive research run; check Activity View at end of day
Day 4: Hand it one small, well-scoped bugfix from the feedback backlog
Day 5: Review the PR like a junior's PR; write feedback, not just approve/reject
Weekend: Decide what to widen (or narrow) next week
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The principle is the same one I use with any new teammate: start narrow, watch closely, widen access based on evidence. OpenAI has given us the controls (Custom Rules, Activity View, app permissions, auto-review). It's on us to actually use them instead of clicking "allow all."&lt;/p&gt;

&lt;h3&gt;
  
  
  My Honest Reflection as a Lead SWE
&lt;/h3&gt;

&lt;p&gt;I've been burned by agent hype before, so here's where I land.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm genuinely excited about:&lt;/strong&gt; persistence and isolation. An agent with its own inspectable computer, context that carries across ChatGPT, Slack, and Teams, and a read-only proactive mode is a real architectural step. It's not just a smarter prompt box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm cautious about:&lt;/strong&gt; everything that depends on the dot learning "what good looks like" for me. That's the hardest part to evaluate from an announcement. It will only prove itself through weeks of real review cycles. OpenAI's own advice to always review consequential work tells me they know that too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm not claiming:&lt;/strong&gt; I don't have numbers on speed, accuracy, or cost per task, and OpenAI didn't publish any in the launch post. Anyone quoting benchmarks for dots right now should show their source.&lt;/p&gt;

&lt;p&gt;The shift I expect is this: my job gets less about &lt;em&gt;doing&lt;/em&gt; the long tail and more about &lt;em&gt;defining standards and reviewing output&lt;/em&gt;. That was always the job of a good lead. Dots just make it hard to pretend otherwise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaways for Fellow Developers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dots are persistent agents, not chat sessions.&lt;/strong&gt; GPT-6 Astra, their own cloud computer and browser, 24/7 operation, 4,000+ app connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control is built in. Use it.&lt;/strong&gt; Custom Rules, Activity View, auto-review, and ChatGPT app permissions exist so you can start narrow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background work is read-only.&lt;/strong&gt; Proactive research can look, but it can't send, edit, or control your machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mind the limits.&lt;/strong&gt; Dot conversations don't count against ChatGPT limits, but Codex and ChatGPT Work tasks it kicks off do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability is staged.&lt;/strong&gt; Pro and Business Premium first, Enterprise beta via admins, specialist dots via pilots, and Microsoft Agent 365 integration in the works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What would you hand your dot first: the bug backlog, the inbox, or the planning doc nobody updates? Tell me in the comments. I'm genuinely curious how other teams plan to onboard their first always-on teammate.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@ishank.iandroid/chatgpt-dots-how-im-weaving-openai-s-latest-features-into-my-projects-eecbe6c1dafc" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>chatgpt</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Supercharging Your Security Audits: My Deep Dive into a Game-Changing AI Skill</title>
      <dc:creator>Ishank Choudhary</dc:creator>
      <pubDate>Mon, 28 Sep 2026 05:00:45 +0000</pubDate>
      <link>https://dev.to/ishank-dev/supercharging-your-security-audits-my-deep-dive-into-a-game-changing-ai-skill-5efe</link>
      <guid>https://dev.to/ishank-dev/supercharging-your-security-audits-my-deep-dive-into-a-game-changing-ai-skill-5efe</guid>
      <description>&lt;p&gt;Have you ever stared at a complex codebase, knowing there are hidden security vulnerabilities lurking, but feeling overwhelmed by the sheer scale of manual auditing? Or perhaps you've wished for a way to scale your security efforts without scaling your human team linearly? If so, you're not alone. As a Lead SWE, I constantly grapple with the challenge of building secure applications at speed. This past week, something truly remarkable caught my attention: a particular security-audit-skill from Cloudflare that absolutely &lt;em&gt;exploded&lt;/em&gt; on GitHub Trending, racking up roughly +15.4k stars in just 7 days. While the repository itself has been around since June, this sudden surge in interest is the real story, and it immediately sent me down a rabbit hole.&lt;/p&gt;

&lt;p&gt;My initial thought was, "Another security tool? What makes this one different?" But as I dug deeper, I realized this isn't just another scanner. This is a paradigm shift in how we approach security audits, leveraging the power of AI agents to perform structured, multi-phase vulnerability discovery. Imagine turning a coding agent like Claude Code or Codex into a structured, six-phase security auditor with one &lt;code&gt;npx&lt;/code&gt; install and a one-line prompt, with a separate verifier re-checking every finding. That's precisely what this skill promises, and the design behind it holds up to scrutiny.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Why" Behind the Explosive Growth: A Developer's Perspective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The recent surge in popularity isn't just hype; it reflects a genuine need in our industry. We're all under pressure to deliver features faster, but security can't be an afterthought. Traditional security audits are often slow, expensive, and require specialized expertise that isn't always readily available. Automated scanners exist, of course, but they often struggle with context, complex logic, and the nuanced understanding required to uncover truly subtle vulnerabilities.&lt;/p&gt;

&lt;p&gt;What I've found so compelling about this &lt;code&gt;security-audit-skill&lt;/code&gt; is its intelligent orchestration. It doesn't just run a static analysis; it emulates a structured audit process, much like a human auditor would, but at machine speed and with a tireless attention to detail. The idea that a single &lt;code&gt;npx&lt;/code&gt; install can set up such a comprehensive, AI-driven process for my codebase is incredibly appealing. It’s like having a team of specialized security agents working around the clock, systematically dissecting every layer of my application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Deep Dive: Unpacking the Six Phases of an AI-Powered Audit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What truly sets this skill apart is its structured, multi-phase approach. It’s not a black box; it's a transparent, methodical process that mirrors best practices in security auditing. I spent some time dissecting each phase, and here’s what I learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconnaissance: Mapping the Digital Landscape&lt;/strong&gt;&lt;br&gt;
This is where it all begins. Just like a human auditor, the AI agent first maps out the architecture of the target system. It identifies trust boundaries, input surfaces, and any prior evidence or known issues. It even attempts to determine deterministic coverage, creating an &lt;code&gt;architecture.md&lt;/code&gt; and &lt;code&gt;coverage-ledger.json&lt;/code&gt;. This initial mapping is crucial because it provides the foundational context for the entire audit. Without a clear understanding of the system's layout, any subsequent hunting would be akin to stumbling in the dark. I appreciate that it generates a coverage ledger from the start, setting a baseline for what's been explored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Coverage-led Hunting: Intelligent Exploration&lt;/strong&gt;&lt;br&gt;
Once the reconnaissance is complete, the skill assigns "isolated hunters" based on units defined in the coverage ledger. These hunters are individual AI agents, each tasked with exploring specific parts of the codebase. They record their checks, and critically, "coverage critics" are used to find gaps in their exploration. This isn't just random fuzzing; it's a directed, intelligent exploration designed to maximize the chances of finding vulnerabilities by ensuring comprehensive coverage. It's like having multiple specialists each focusing on their domain, but with an overarching supervisor making sure no stone is left unturned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Candidate Validation: The Art of Disproving&lt;/strong&gt;&lt;br&gt;
This phase is brilliant. Every unique potential finding – or "candidate" – is handed off to a &lt;em&gt;fresh&lt;/em&gt;, independent verifier agent. This verifier's job isn't to confirm the finding, but to &lt;em&gt;try and disprove it&lt;/em&gt;. This adversarial validation process is a cornerstone of robust security testing. It minimizes false positives and ensures that only genuinely problematic candidates proceed. As a developer, few things are more frustrating than chasing down a "vulnerability" that turns out to be a false alarm. This built-in skepticism is a huge win for efficiency and accuracy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Structured Output: Machine-Readable Insights&lt;/strong&gt;&lt;br&gt;
After validation, the skill doesn't just spew out raw text. It writes confirmed, &lt;code&gt;needs_validation&lt;/code&gt;, and rejected records into a &lt;code&gt;findings.json&lt;/code&gt; file. What's more, these findings are validated against a &lt;code&gt;report-schema.json&lt;/code&gt;. This structured, machine-readable output is invaluable. It means the results aren't just for human consumption; they can be easily integrated into other tools, dashboards, or CI/CD pipelines. For me, this is a critical feature, as it allows for automation downstream and better tracking of security posture over time. A &lt;code&gt;needs_validation&lt;/code&gt; verdict, for instance, means there's an exact unresolved fact that needs human attention, without assigning a premature severity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Independent Record Verification: Trust, But Verify (Again)&lt;/strong&gt;&lt;br&gt;
Even after structured output, the process isn't over. Fresh, independent agents are brought in to verify the final source claims. If any material replacements occur during this phase (e.g., a finding's details are updated), another independent verifier is dispatched. This double-checking mechanism is a testament to the skill's commitment to accuracy and reliability. It reinforces the principle of "adversarial validation" and ensures that the final reports are as trustworthy as possible. This is where the "separate verifier re-checks every finding" promise truly shines, adding an extra layer of confidence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Target-Neutral Reporting: Actionable Intelligence&lt;/strong&gt;&lt;br&gt;
Finally, all the verified records and the coverage ledger are used to derive comprehensive reports: &lt;code&gt;REPORT.md&lt;/code&gt;, &lt;code&gt;FINDINGS-DETAIL.md&lt;/code&gt;, and &lt;code&gt;NEEDS-VALIDATION.md&lt;/code&gt;. These reports are "target-neutral," meaning they focus on the vulnerabilities themselves rather than being tied to a specific tool or framework. This makes the findings universally understandable and actionable. Having distinct reports for confirmed issues, detailed findings, and items requiring further human validation is incredibly helpful for prioritizing and allocating resources.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Beyond the Phases: Core Principles That Resonate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My deep dive also revealed some fundamental design principles that I believe are crucial for any effective security tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Only confirm established boundary failures:&lt;/strong&gt; This means it focuses on genuine security flaws, not just "could be bad" scenarios.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Adversarial validation:&lt;/strong&gt; As mentioned, the agent that checks a finding is never the agent that found it. This dramatically reduces bias.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Severity requires impact:&lt;/strong&gt; A deviation from a checklist isn't a vulnerability unless it has a measurable impact. This helps prioritize real risks.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Defense-in-depth gaps are not vulnerabilities:&lt;/strong&gt; If one layer of security prevents an attack, the absence of another layer is a hardening note, not a critical vulnerability. This is a nuanced but important distinction for practical security.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These principles show a maturity in design that goes beyond simple pattern matching, aiming for a more intelligent and context-aware assessment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting Started: Bringing AI to Your Codebase&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What truly excites me as a Lead SWE is how accessible this technology is. Getting started with the &lt;code&gt;security-audit-skill&lt;/code&gt; is surprisingly straightforward. It integrates with existing coding agents that support tool use and parallel sub-agents (like the aforementioned Claude Code or Codex).&lt;/p&gt;

&lt;p&gt;First, you install the skill using &lt;code&gt;npx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add https://github.com/cloudflare/security-audit-skill &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--skill&lt;/span&gt; security-audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a user-level installation, you can add &lt;code&gt;--global&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add https://github.com/cloudflare/security-audit-skill &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--skill&lt;/span&gt; security-audit &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, you simply point your coding agent at your codebase and ask it to perform an audit. The skill activates automatically when your request matches its triggers (e.g., "security audit," "find vulnerabilities," "pen-test the code").&lt;/p&gt;

&lt;p&gt;For instance, if you're working on a Node.js or TypeScript repository, you might instruct your agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;security audit this codebase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, to focus on a specific directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find security vulnerabilities in ./src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even specify an output directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;do a security review, output to ~/audits/my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool requires Node.js for its zero-dependency validators and, critically, an OS-enforced sandbox for executing target code safely. This sandbox is essential for preventing any malicious code within the audited project from affecting your system. Without it, the workflow wisely keeps findings as &lt;code&gt;needs_validation&lt;/code&gt; rather than executing potentially unsafe target code, which is a fantastic safety measure.&lt;/p&gt;

&lt;p&gt;One detail I liked for Node/TS monorepos: in full audit mode the output defaults to &lt;code&gt;~/security-audit-skill/&amp;lt;repo-name&amp;gt;/run-&amp;lt;N&amp;gt;&lt;/code&gt;, outside your repository. It only writes inside the target repo when you explicitly pick a directory that version control ignores, so your working tree stays clean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Power of Repetition: Continuous Improvement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One insight from my deep dive that really stuck with me is the concept of additive runs. The documentation suggests that multiple runs against the same repository are not redundant; they actually improve coverage. The skill uses prior ledgers and findings to target gaps, revalidate changed source, and carry forward current-source evidence. Cloudflare is candid about why: in their own test runs, a single run found roughly half of the vulnerabilities that repeated runs found in total. My experience tells me that security isn't a one-time check; it's a continuous process. A tool that learns and improves its coverage with each iteration is a significant advantage in a rapidly evolving threat landscape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honest Ship/Skip: Is This For You?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, is this the silver bullet for all security woes? Not necessarily. It's a powerful tool, but like any technology, it has its best use cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ship it if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You're working on complex codebases where manual audits are time-consuming and prone to human error.&lt;/li&gt;
&lt;li&gt;  You need to scale your security efforts and provide systematic, structured vulnerability discovery.&lt;/li&gt;
&lt;li&gt;  You're looking to integrate advanced AI capabilities into your CI/CD pipeline for continuous security assessment.&lt;/li&gt;
&lt;li&gt;  You appreciate a methodical approach with independent verification, aiming for high-quality, low-false-positive findings.&lt;/li&gt;
&lt;li&gt;  You have access to powerful AI agents (like Claude Code or Codex) and are comfortable setting up a secure sandboxed environment for execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Skip it (or use with caution) if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You're working on extremely small, simple projects where a quick manual review or a basic linter might suffice.&lt;/li&gt;
&lt;li&gt;  You don't have the infrastructure or expertise to set up an OS-enforced sandbox, which is a critical requirement for safely executing target code.&lt;/li&gt;
&lt;li&gt;  You expect it to magically fix all your security problems without any human oversight or understanding of its findings. It's an assistant, not a replacement for human intelligence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a Lead SWE like myself, navigating enterprise-grade applications with intricate logic and numerous dependencies, this &lt;code&gt;security-audit-skill&lt;/code&gt; feels like a genuine game-changer. It packages audit methodology that was once the domain of specialized security teams, and it seeded the much larger fleet-wide harness Cloudflare describes in its &lt;a href="https://blog.cloudflare.com/build-your-own-vulnerability-harness/" rel="noopener noreferrer"&gt;Build your own vulnerability harness&lt;/a&gt; post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion: A New Horizon for Developer Security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The explosion of interest in Cloudflare's &lt;a href="https://github.com/cloudflare/security-audit-skill" rel="noopener noreferrer"&gt;security-audit-skill&lt;/a&gt; on GitHub Trending is a clear signal: developers are hungry for smarter, more efficient ways to secure their code. My deep dive into its architecture and methodology has convinced me that this isn't just a fleeting trend; it's a significant step forward in making advanced security auditing accessible and actionable for every engineering team.&lt;/p&gt;

&lt;p&gt;Here are my key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Structured &amp;amp; Systematic:&lt;/strong&gt; The six-phase audit process provides a level of methodical rigor often missing in automated tools.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;AI-Powered Precision:&lt;/strong&gt; Leveraging AI agents for reconnaissance, hunting, and especially adversarial validation leads to higher accuracy and fewer false positives.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Independent Verification:&lt;/strong&gt; The repeated, independent checks on findings instill a high degree of confidence in the results.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Actionable Output:&lt;/strong&gt; Machine-readable findings and clear reports (&lt;code&gt;confirmed&lt;/code&gt;, &lt;code&gt;needs_validation&lt;/code&gt;, &lt;code&gt;rejected&lt;/code&gt;) streamline the remediation process.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Accessible Power:&lt;/strong&gt; With a simple &lt;code&gt;npx&lt;/code&gt; command, developers can tap into a sophisticated auditing harness that was once an internal Cloudflare innovation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I encourage you to explore this skill for your own projects. Start with one repo, read the &lt;code&gt;NEEDS-VALIDATION.md&lt;/code&gt; file as carefully as the confirmed findings, and run it more than once. What are your thoughts on AI-driven security auditing? Have you experimented with similar tools, or are you ready to take the plunge? Share your experiences in the comments below! The future of secure software development is here, and it's worth getting hands-on with now.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Connect with me:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://ishankdev.github.io/" rel="noopener noreferrer"&gt;https://ishankdev.github.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this deep-dive helped, you can &lt;a href="https://www.buymeacoffee.com/ishankchoudhary" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt; — totally optional.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>claude</category>
      <category>cloudflare</category>
    </item>
  </channel>
</rss>
