<?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: Alan West</title>
    <description>The latest articles on DEV Community by Alan West (@alanwest).</description>
    <link>https://dev.to/alanwest</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%2F3834047%2F6413d0cf-9d90-4ccc-80a9-123656fd78ba.png</url>
      <title>DEV Community: Alan West</title>
      <link>https://dev.to/alanwest</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alanwest"/>
    <language>en</language>
    <item>
      <title>How to Run Mage-VL-Cowork Locally: Microsoft's 4B Agent Beats Sonnet 4.5</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Sun, 01 Nov 2026 13:30:03 +0000</pubDate>
      <link>https://dev.to/alanwest/how-to-run-mage-vl-cowork-locally-microsofts-4b-agent-beats-sonnet-45-3dh4</link>
      <guid>https://dev.to/alanwest/how-to-run-mage-vl-cowork-locally-microsofts-4b-agent-beats-sonnet-45-3dh4</guid>
      <description>&lt;p&gt;Microsoft's Mage-VL-Cowork is a 4B computer-use model that scores 66.0% on OSWorld-Verified. That's ahead of Claude Sonnet 4.5 (62.9%, and Sonnet got twice the step budget) and of an open 72B model that manages 44.9%. The BF16 weights are 9.48 GB and the license is Apache-2.0, so a 16 GB GPU is enough to run it locally. A 4-bit GGUF fits in 8 GB. Before you point it at anything, though, read the part of the model card that tells you to keep it in a disposable VM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/microsoft/Mage-VL-Cowork" rel="noopener noreferrer"&gt;microsoft/Mage-VL-Cowork&lt;/a&gt; showed up on Hugging Face at the end of October. The "Cowork" in the name makes it sound like a friendly screen buddy that watches you work. What you actually get is an agent policy that takes a screenshot and emits either a GUI action or a shell command. Everything below comes from the model card, the config, and the community ports. I haven't run it myself, and I'll say where the published numbers stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Mage-VL-Cowork is (and how it differs from Phi vision)
&lt;/h2&gt;

&lt;p&gt;Microsoft's earlier small VLMs were general models. &lt;a href="https://huggingface.co/microsoft/Phi-4-multimodal-instruct" rel="noopener noreferrer"&gt;Phi-4-multimodal&lt;/a&gt; is about 5.6B params, takes text, images and audio, has a 128K context and ships under MIT. You ask it about an image and it answers.&lt;/p&gt;

&lt;p&gt;Mage-VL-Cowork does a different job. Every turn has the same output format: a &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; block, a one-line &lt;code&gt;Action:&lt;/code&gt; summary, then a &lt;code&gt;&amp;lt;tool_call&amp;gt;&lt;/code&gt;. There are two tool channels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;computer_use&lt;/code&gt;: 11 GUI primitives with coordinates normalized to [0, 999]&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bash&lt;/code&gt;: arbitrary shell commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project page's tagline is "One 4B policy that knows when to click—and when to code." That claim holds up best in the training mix: 68.19% of the 318,837 hybrid trajectories are GUI tool calls and 31.81% are terminal calls. The model learned to stop dragging the mouse around LibreOffice when a Python one-liner will do the job.&lt;/p&gt;

&lt;p&gt;It's also not a Phi descendant. The language backbone is Qwen3-4B-Instruct-2507 and the vision encoder is Microsoft's own Mage-ViT. The closer Microsoft relative is &lt;a href="https://huggingface.co/microsoft/Fara-7B" rel="noopener noreferrer"&gt;Fara-7B&lt;/a&gt; (Qwen2.5-VL base, MIT, released November 2025), which is built for web tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mage-VL-Cowork specs: 4B or 4.7B parameters?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Mage-VL-Cowork&lt;/th&gt;
&lt;th&gt;Phi-4-multimodal&lt;/th&gt;
&lt;th&gt;Fara-7B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Params&lt;/td&gt;
&lt;td&gt;4B (card), 4.74B (Hub metadata)&lt;/td&gt;
&lt;td&gt;~5.6B&lt;/td&gt;
&lt;td&gt;7B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backbone&lt;/td&gt;
&lt;td&gt;Qwen3-4B-Instruct-2507 + Mage-ViT&lt;/td&gt;
&lt;td&gt;Phi-4-mini&lt;/td&gt;
&lt;td&gt;Qwen2.5-VL-7B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;32,768 active (262,144 max in config)&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Desktop + terminal agent&lt;/td&gt;
&lt;td&gt;General multimodal&lt;/td&gt;
&lt;td&gt;Web agent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;About the mismatch: the card says 4B, but the Hub's safetensors metadata counts 4.74B parameters. That matches 9.48 GB divided by 2 bytes per BF16 weight. The config has 36 text layers, hidden size 2560, and 8 KV heads. The vision side is 24 layers at 1024 hidden.&lt;/p&gt;

&lt;p&gt;The context number trips people up. The architecture supports 262,144 tokens, but Microsoft trained and evaluated at 32,768 and runs a sliding window that keeps the 3 latest screenshots and 4 full assistant turns. Older turns get folded into their &lt;code&gt;Action:&lt;/code&gt; lines. Don't push it to 262K and expect it to behave.&lt;/p&gt;

&lt;h2&gt;
  
  
  OSWorld-Verified: where 66.0% actually sits
&lt;/h2&gt;

&lt;p&gt;The headline number is OSWorld-Verified: 361 tasks with Google Drive tasks excluded and a 50-step budget. The 66.0% is the mean of two runs, 65.33% and 66.75%.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Params&lt;/th&gt;
&lt;th&gt;OSWorld-Verified&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4-mini&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;69.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ScaleCUA-Qwen3.5-9B&lt;/td&gt;
&lt;td&gt;9B&lt;/td&gt;
&lt;td&gt;68.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mage-VL-Cowork&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;66.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Muse Glimmer-30B&lt;/td&gt;
&lt;td&gt;30B&lt;/td&gt;
&lt;td&gt;65.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.6-27B&lt;/td&gt;
&lt;td&gt;27B&lt;/td&gt;
&lt;td&gt;63.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.5 (100 steps)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;62.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenCUA-72B&lt;/td&gt;
&lt;td&gt;72B&lt;/td&gt;
&lt;td&gt;44.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fara1.5-4B&lt;/td&gt;
&lt;td&gt;4B&lt;/td&gt;
&lt;td&gt;13.9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The frontier models are still well ahead. GPT-5.5 is at 78.7 and Claude Opus 4.7 at 78.0, and the card's human reference is 72.4. The 66.0 mostly shows how much a small model gets out of a task-specific curriculum. The RL stage alone took it from 55.84% to 66.04% while cutting output tokens per task from 7,374 to 5,499.&lt;/p&gt;

&lt;p&gt;Two things I'd flag before anyone quotes these numbers in a pitch deck:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The WebVoyager-Static figure (58.6%) comes from the SFT checkpoint, not the released RL model, and Microsoft's own Fara1.5-4B beats it there with 68.0%.&lt;/li&gt;
&lt;li&gt;The web results use offline replicas. The card has no live-web number for Mage-VL-Cowork.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How much VRAM Mage-VL-Cowork needs
&lt;/h2&gt;

&lt;p&gt;The card does not state a minimum VRAM. Here's what the published files and config let you work out.&lt;/p&gt;

&lt;p&gt;Start with the weights. BF16 is 9.48 GB across 2 safetensors shards. The community &lt;a href="https://huggingface.co/Hansda/Mage-VL-Cowork-GGUF" rel="noopener noreferrer"&gt;Q4_K_M GGUF&lt;/a&gt; is 2.72 GB plus a 0.35 GB Q8_0 mmproj. The &lt;a href="https://huggingface.co/pratikgx/Mage-VL-Cowork-MLX-4bit" rel="noopener noreferrer"&gt;MLX 4-bit&lt;/a&gt; build is about 3.14 GB.&lt;/p&gt;

&lt;p&gt;Then the KV cache. I worked this out from config.json and haven't measured it: 36 layers × 8 KV heads × 128 head dim × 2 (K and V) × 2 bytes comes to about 144 KB per token. At the full 32,768 window that's roughly 4.8 GB in FP16.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Weights&lt;/th&gt;
&lt;th&gt;+ KV at 32K&lt;/th&gt;
&lt;th&gt;Card to plan for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BF16 (Transformers/SGLang)&lt;/td&gt;
&lt;td&gt;9.48 GB&lt;/td&gt;
&lt;td&gt;~4.8 GB&lt;/td&gt;
&lt;td&gt;16 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q8_0 GGUF + mmproj&lt;/td&gt;
&lt;td&gt;5.05 GB&lt;/td&gt;
&lt;td&gt;~4.8 GB&lt;/td&gt;
&lt;td&gt;12 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q4_K_M GGUF + mmproj&lt;/td&gt;
&lt;td&gt;3.07 GB&lt;/td&gt;
&lt;td&gt;~4.8 GB&lt;/td&gt;
&lt;td&gt;8 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MLX 4-bit (Apple Silicon)&lt;/td&gt;
&lt;td&gt;3.14 GB&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;16 GB unified memory Mac&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Screenshots are the other big cost. Microsoft recommends &lt;code&gt;SGLANG_MAX_PIXELS=4000000&lt;/code&gt; so a 1920×1080 capture keeps its full detail, which means a lot of vision tokens per turn. If you're tight on memory, lower the screenshot resolution before you drop to Q2_K. Grounding is what I'd expect quantization to break first. In the MLX port's tiny 3-task demo, the 4-bit build missed a Dark Mode toggle by 42px while the BF16 build hit it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which runtimes load it today: SGLang, Transformers, vLLM, llama.cpp, Ollama, MLX
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Transformers
&lt;/h3&gt;

&lt;p&gt;Works, needs &lt;code&gt;trust_remote_code=True&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;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"transformers&amp;gt;=4.57.3"&lt;/span&gt; accelerate pillow torch torchvision qwen-vl-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;torch&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoProcessor&lt;/span&gt;

&lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;microsoft/Mage-VL-Cowork&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&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="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;microsoft/Mage-VL-Cowork&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;torch_dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bfloat16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&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="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the card's sampling settings (temperature 0.7, top_p 0.8, max_new_tokens 4096) and its full &lt;code&gt;MAGE_HYBRID_SYSTEM_PROMPT&lt;/code&gt;. That prompt is where the tool schemas and the reply format are defined, so don't skip it.&lt;/p&gt;

&lt;h3&gt;
  
  
  SGLang
&lt;/h3&gt;

&lt;p&gt;This is the path the card's Quick Start recommends, and the one I'd pick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; sglang.launch_server &lt;span class="nt"&gt;--model-path&lt;/span&gt; microsoft/Mage-VL-Cowork &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--trust-remote-code&lt;/span&gt; &lt;span class="nt"&gt;--dtype&lt;/span&gt; bfloat16 &lt;span class="nt"&gt;--context-length&lt;/span&gt; 32768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also a prebuilt image, &lt;code&gt;xiaoyizhang/mage-vl-cowork:0.1.0&lt;/code&gt; (SGLang 0.5.2, PyTorch 2.8.0+cu128). Screenshots go through the native &lt;code&gt;POST /generate&lt;/code&gt; endpoint with &lt;code&gt;image_data&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  vLLM
&lt;/h3&gt;

&lt;p&gt;The Hub's "Use this model" panel suggests &lt;code&gt;vllm serve "microsoft/Mage-VL-Cowork"&lt;/code&gt;, but the card doesn't test that path. With a custom &lt;code&gt;llava_onevision2&lt;/code&gt; architecture, I wouldn't count on it until someone posts a working run.&lt;/p&gt;

&lt;h3&gt;
  
  
  llama.cpp
&lt;/h3&gt;

&lt;p&gt;Only through a fork. The GGUF repo points to &lt;code&gt;ch686/llama.cpp-locateanything-magevl&lt;/code&gt; at commit &lt;code&gt;e07bdc8&lt;/code&gt;, and the upstream PR (#26796) was closed without being merged. Loading the text side is easy enough; the fork exists because of the custom Mage-ViT projector.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ollama and LM Studio
&lt;/h3&gt;

&lt;p&gt;The Hub lists &lt;code&gt;ollama run hf.co/Hansda/Mage-VL-Cowork-GGUF:Q4_K_M&lt;/code&gt;, but the GGUF author says outright: "Stock llama.cpp, Ollama and LM Studio have not been validated for this projector." Maybe it works fine. For an agent that has to click within a few pixels, though, I'd treat it as broken until someone posts grounding results.&lt;/p&gt;

&lt;h3&gt;
  
  
  MLX on Apple Silicon
&lt;/h3&gt;

&lt;p&gt;Works with &lt;code&gt;mlx-vlm&lt;/code&gt; 0.7.11, which has a built-in &lt;code&gt;mage_vl&lt;/code&gt; model:&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; &lt;span class="nt"&gt;-U&lt;/span&gt; mlx-vlm
python &lt;span class="nt"&gt;-m&lt;/span&gt; mlx_vlm.generate &lt;span class="nt"&gt;--model&lt;/span&gt; pratikgx/Mage-VL-Cowork-MLX-4bit &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--image&lt;/span&gt; screenshot.png &lt;span class="nt"&gt;--prompt&lt;/span&gt; &lt;span class="s2"&gt;"Turn on Dark Mode."&lt;/span&gt; &lt;span class="nt"&gt;--max-tokens&lt;/span&gt; 512
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;None of the community quants has an OSWorld score. The only published numbers are for Microsoft's BF16 checkpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part nobody reads: Microsoft's sandbox rules
&lt;/h2&gt;

&lt;p&gt;The card isn't vague about deployment. Run the agent inside an isolated container or VM with no access to host filesystems, local networks or personal environment variables. Require human confirmation before irreversible actions like external submissions, account logins, payments and privilege changes. Don't mount SSH keys, cloud tokens, browser cookies or password stores. Restrict outbound network access when the model handles untrusted web pages.&lt;/p&gt;

&lt;p&gt;So the "cowork" fantasy, a local model watching your real desktop and helping out, is exactly what Microsoft tells you not to do. The model has a &lt;code&gt;bash&lt;/code&gt; channel, and a web page with injected instructions is just more pixels to it. A local model keeps your data off someone else's server, but it doesn't stop the model from running &lt;code&gt;rm&lt;/code&gt; on your files.&lt;/p&gt;

&lt;p&gt;What I'd do with it today: spin up a snapshot-reverted Ubuntu VM with no credentials in it, serve the model with SGLang on a 16 GB card, and use the &lt;code&gt;osworld_eval/&lt;/code&gt; harness in the repo as a starting point for your own agent loop. That setup gives you a 4B agent that beats several 27–72B open models on OSWorld-Verified, and the worst it can do is wreck a VM you'll throw away anyway.&lt;/p&gt;

&lt;p&gt;Would you let a local vision model watch your screen and act on it, as long as nothing leaves your machine? Or does a &lt;code&gt;bash&lt;/code&gt; tool make "local" irrelevant? Tell me where you draw the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/microsoft/Mage-VL-Cowork" rel="noopener noreferrer"&gt;microsoft/Mage-VL-Cowork model card&lt;/a&gt; and &lt;a href="https://huggingface.co/microsoft/Mage-VL-Cowork/blob/main/config.json" rel="noopener noreferrer"&gt;config.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microsoft.github.io/Mage/cowork/" rel="noopener noreferrer"&gt;Mage-VL-Cowork project page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/Hansda/Mage-VL-Cowork-GGUF" rel="noopener noreferrer"&gt;Hansda/Mage-VL-Cowork-GGUF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/pratikgx/Mage-VL-Cowork-MLX-4bit" rel="noopener noreferrer"&gt;pratikgx/Mage-VL-Cowork-MLX-4bit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/microsoft/Phi-4-multimodal-instruct" rel="noopener noreferrer"&gt;microsoft/Phi-4-multimodal-instruct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/microsoft/Fara-7B" rel="noopener noreferrer"&gt;microsoft/Fara-7B&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>How to Run LFM3-Omni-2B GGUF Locally (Only llama.cpp Makes It Talk Back)</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Sat, 31 Oct 2026 20:20:01 +0000</pubDate>
      <link>https://dev.to/alanwest/how-to-run-lfm3-omni-2b-gguf-locally-only-llamacpp-makes-it-talk-back-1fm4</link>
      <guid>https://dev.to/alanwest/how-to-run-lfm3-omni-2b-gguf-locally-only-llamacpp-makes-it-talk-back-1fm4</guid>
      <description>&lt;p&gt;LFM3-Omni-2B is Liquid AI's new 2B model that takes text, images, video and audio in and answers in text or 24 kHz speech. The Q4_K_M GGUF is 1.1 GB, plus a 292 MB mmproj file, and llama.cpp v0.8.0 runs all of it, voice output included. Ollama and LM Studio load it too, but neither of them makes it speak. If you just want it running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llama serve &lt;span class="nt"&gt;-hf&lt;/span&gt; LiquidAI/LFM3-Omni-2B-GGUF:Q4_K_M &lt;span class="nt"&gt;--reasoning&lt;/span&gt; off &lt;span class="nt"&gt;--temp&lt;/span&gt; 0 &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I covered d1-Omni-2B earlier this week, my main complaint was that it listens to audio but can only answer with a typed probability. LFM3-Omni-2B is the model it was built on, and it still has the speech output. The &lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B-GGUF" rel="noopener noreferrer"&gt;GGUF repo&lt;/a&gt; picked up 69,967 downloads in the few days since launch, so I'm clearly not the only one curious.&lt;/p&gt;

&lt;p&gt;This post covers which quant to pick, the llama.cpp commands for ASR, image, video and TTS, the realtime voice endpoint, which apps can make it speak, and where it loses to LFM3-VL-2B and Gemma 4. I haven't run it myself yet. Everything here comes from Liquid's cards, the llama.cpp release notes and the PR that added realtime voice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What LFM3-Omni-2B actually is
&lt;/h2&gt;

&lt;p&gt;It came out on October 27, 2026, as part of the &lt;a href="https://www.liquid.ai/blog/lfm3" rel="noopener noreferrer"&gt;LFM3 family&lt;/a&gt;: six roughly 2B models, all built on LFM3-1.7B-Base. The Omni model combines four parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the LFM3-1.7B backbone&lt;/li&gt;
&lt;li&gt;an LFM3 vision encoder (native resolution, each 2×2 patch block becomes one token)&lt;/li&gt;
&lt;li&gt;a causal audio encoder that takes 16 kHz input&lt;/li&gt;
&lt;li&gt;a "depthformer" plus the Liquid Audio Codec for speech output at 24 kHz&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That adds up to 2.17B parameters. Input can be text, images, video (with or without the soundtrack) and audio. Output can be text, speech, or both interleaved. Text works in 16 languages. Speech covers 19 languages and locales, including British and American English as separate voices.&lt;/p&gt;

&lt;p&gt;The context window is 32K tokens. That's the spec I'd worry about, since the two sibling models below get 128K.&lt;/p&gt;

&lt;h2&gt;
  
  
  LFM3-Omni-2B vs LFM3-VL-2B vs d1-Omni-2B
&lt;/h2&gt;

&lt;p&gt;All three are from the same family and were built for different jobs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;LFM3-Omni-2B&lt;/th&gt;
&lt;th&gt;LFM3-VL-2B&lt;/th&gt;
&lt;th&gt;d1-Omni-2B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Params&lt;/td&gt;
&lt;td&gt;2.17B&lt;/td&gt;
&lt;td&gt;1.92B&lt;/td&gt;
&lt;td&gt;2.17B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;text, image, video, audio&lt;/td&gt;
&lt;td&gt;text, image, video&lt;/td&gt;
&lt;td&gt;text/JSON state, image, video, audio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;text + 24 kHz speech&lt;/td&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;typed answers with probabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning&lt;/td&gt;
&lt;td&gt;no (&lt;code&gt;enable_thinking&lt;/code&gt; unsupported)&lt;/td&gt;
&lt;td&gt;yes, &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; block&lt;/td&gt;
&lt;td&gt;single forward pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;LFM Open v1.0&lt;/td&gt;
&lt;td&gt;LFM Open v1.0&lt;/td&gt;
&lt;td&gt;LFM Open v1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sources: &lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B" rel="noopener noreferrer"&gt;Omni card&lt;/a&gt;, &lt;a href="https://huggingface.co/LiquidAI/LFM3-VL-2B" rel="noopener noreferrer"&gt;VL card&lt;/a&gt;, &lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B" rel="noopener noreferrer"&gt;d1-Omni card&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B" rel="noopener noreferrer"&gt;d1-Omni-2B&lt;/a&gt; is a decision model built on top of LFM3-Omni-2B, and its card says plainly that there are "no generated tokens or speech". It's useful for classifying a camera feed, but you can't hold a conversation with it.&lt;/p&gt;

&lt;p&gt;The comparison with LFM3-VL is less flattering. Both cards publish the same four vision benchmarks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;LFM3-Omni-2B&lt;/th&gt;
&lt;th&gt;LFM3-VL-2B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MMStar&lt;/td&gt;
&lt;td&gt;55.67&lt;/td&gt;
&lt;td&gt;74.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCRBench&lt;/td&gt;
&lt;td&gt;806 / 1000&lt;/td&gt;
&lt;td&gt;86.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DocVQA&lt;/td&gt;
&lt;td&gt;92.47&lt;/td&gt;
&lt;td&gt;96.7 (val)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RealWorldQA&lt;/td&gt;
&lt;td&gt;66.54&lt;/td&gt;
&lt;td&gt;79.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cards don't say whether the two models were evaluated the same way, and only VL reasons before answering, so treat these as rough numbers. The gap is still big enough that for screenshots, PDFs and charts I'd stick with LFM3-VL-2B and its 128K context. Pick Omni when the input or output is a voice.&lt;/p&gt;

&lt;h2&gt;
  
  
  LFM3-Omni-2B vs Qwen2.5-Omni, Gemma 4 and Phi-4 MM
&lt;/h2&gt;

&lt;p&gt;Liquid compares Omni with Qwen2.5-Omni 3B, Gemma 4 E2B and E4B, and Phi-4 MM, all bigger in total parameters. These are Liquid's own measurements from the &lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B" rel="noopener noreferrer"&gt;base card&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;LFM3-Omni 2B&lt;/th&gt;
&lt;th&gt;Qwen2.5-Omni 3B&lt;/th&gt;
&lt;th&gt;Gemma 4 E2B&lt;/th&gt;
&lt;th&gt;Gemma 4 E4B&lt;/th&gt;
&lt;th&gt;Phi-4 MM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Daily-Omni&lt;/td&gt;
&lt;td&gt;70.09&lt;/td&gt;
&lt;td&gt;58.81&lt;/td&gt;
&lt;td&gt;50.63&lt;/td&gt;
&lt;td&gt;54.14&lt;/td&gt;
&lt;td&gt;48.87&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;English ASR WER ↓&lt;/td&gt;
&lt;td&gt;6.36&lt;/td&gt;
&lt;td&gt;6.30&lt;/td&gt;
&lt;td&gt;8.26&lt;/td&gt;
&lt;td&gt;7.82&lt;/td&gt;
&lt;td&gt;5.14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;English TTS UTMOSv2 ↑&lt;/td&gt;
&lt;td&gt;3.80&lt;/td&gt;
&lt;td&gt;3.42&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VoiceBench ↑&lt;/td&gt;
&lt;td&gt;64.73&lt;/td&gt;
&lt;td&gt;66.37&lt;/td&gt;
&lt;td&gt;63.28&lt;/td&gt;
&lt;td&gt;72.90&lt;/td&gt;
&lt;td&gt;64.97&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool calling (internal) ↑&lt;/td&gt;
&lt;td&gt;52.20&lt;/td&gt;
&lt;td&gt;44.30&lt;/td&gt;
&lt;td&gt;55.60&lt;/td&gt;
&lt;td&gt;72.40&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The audio-plus-video results are strong for its size, and ASR is close to Qwen2.5-Omni 3B. On the vision benchmarks it roughly ties Qwen2.5-Omni 3B too, so the gap to LFM3-VL is a specialist-vs-generalist thing. VoiceBench and tool calling are where it falls short: Gemma 4 E4B beats it by about 8 points on VoiceBench and 20 on Liquid's internal tool-calling test, and even the smaller Gemma 4 E2B edges it on tool calling. Those two scores are the ones that matter for a voice assistant. Most voice tasks are some version of "set a timer", and that is a tool call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which quant to download: file sizes and RAM
&lt;/h2&gt;

&lt;p&gt;Liquid doesn't publish RAM figures per quant, so file size is the best estimate available. You need the main model plus an &lt;code&gt;mmproj&lt;/code&gt; file. The multimodal parts live in that mmproj file, and the repo's commit history shows the speech codec decoder is in there as well ("Quantize the codec decoder in mmproj"). Both lists below come from the &lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B-GGUF/tree/main" rel="noopener noreferrer"&gt;file listing&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quant&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;mmproj (same quant)&lt;/th&gt;
&lt;th&gt;Total on disk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Q4_0&lt;/td&gt;
&lt;td&gt;1.05 GB&lt;/td&gt;
&lt;td&gt;271 MB&lt;/td&gt;
&lt;td&gt;~1.3 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q4_K_M&lt;/td&gt;
&lt;td&gt;1.1 GB&lt;/td&gt;
&lt;td&gt;292 MB&lt;/td&gt;
&lt;td&gt;~1.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q8_0&lt;/td&gt;
&lt;td&gt;1.85 GB&lt;/td&gt;
&lt;td&gt;507 MB&lt;/td&gt;
&lt;td&gt;~2.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BF16 / F16&lt;/td&gt;
&lt;td&gt;3.47 GB&lt;/td&gt;
&lt;td&gt;950 MB&lt;/td&gt;
&lt;td&gt;~4.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Add the KV cache and audio buffers on top of that. Liquid's blog says the hybrid LFM3 backbone needs only 1.6 GB of KV cache at 128K context for the text model, and Omni stops at 32K. On paper, an 8 GB laptop handles Q8_0 without trouble, though that's my estimate and I haven't measured it.&lt;/p&gt;

&lt;p&gt;Someone on the repo has already asked whether the Q4 file uses QAD (quantization-aware distillation), as the text model's Q4_0 does. &lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B-GGUF/discussions/2" rel="noopener noreferrer"&gt;Nobody has answered yet&lt;/a&gt;. Until Liquid says so, I'd assume it doesn't and go with Q8_0 if you can fit it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to run LFM3-Omni-2B GGUF with llama.cpp
&lt;/h2&gt;

&lt;p&gt;Support arrived in llama.cpp b11960 (v0.8.0), released October 28. That release also added a &lt;code&gt;POST /tts&lt;/code&gt; endpoint and a &lt;code&gt;/v1/realtime&lt;/code&gt; endpoint to the server (&lt;a href="https://github.com/ggml-org/llama.cpp/releases/tag/v0.8.0" rel="noopener noreferrer"&gt;release notes&lt;/a&gt;). The commands below are copied from the model card. They use the &lt;code&gt;llama serve&lt;/code&gt; / &lt;code&gt;llama cli&lt;/code&gt; front-end, plus the separate &lt;code&gt;llama-tts&lt;/code&gt; binary for speech. If your build is older than b11960, update first. Older builds don't support the model at all.&lt;/p&gt;

&lt;p&gt;Start the web UI and the OpenAI-compatible API. &lt;code&gt;-hf&lt;/code&gt; also downloads the projector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llama serve &lt;span class="nt"&gt;-hf&lt;/span&gt; LiquidAI/LFM3-Omni-2B-GGUF:Q4_K_M &lt;span class="nt"&gt;--reasoning&lt;/span&gt; off &lt;span class="nt"&gt;--temp&lt;/span&gt; 0 &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;--reasoning off&lt;/code&gt;. It's a non-reasoning model, and the card says &lt;code&gt;enable_thinking=True&lt;/code&gt; isn't supported.&lt;/p&gt;

&lt;p&gt;Speech-to-text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llama cli &lt;span class="nt"&gt;-hf&lt;/span&gt; LiquidAI/LFM3-Omni-2B-GGUF:Q4_K_M &lt;span class="nt"&gt;--audio&lt;/span&gt; speech.wav &lt;span class="nt"&gt;-sys&lt;/span&gt; &lt;span class="s2"&gt;"Perform ASR in English."&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;__media__&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;--temp&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llama cli &lt;span class="nt"&gt;-hf&lt;/span&gt; LiquidAI/LFM3-Omni-2B-GGUF:Q4_K_M &lt;span class="nt"&gt;--image&lt;/span&gt; photo.png &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Describe this image."&lt;/span&gt; &lt;span class="nt"&gt;--temp&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Video input works with &lt;code&gt;--video file.mp4&lt;/code&gt;. It needs &lt;code&gt;ffmpeg&lt;/code&gt; in your &lt;code&gt;PATH&lt;/code&gt;, and the base card says the model samples at 2 fps by default, between 4 and 384 frames. Long clips use up the 32K window fast.&lt;/p&gt;

&lt;p&gt;Text-to-speech, the feature d1-Omni didn't have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;llama-tts &lt;span class="nt"&gt;-m&lt;/span&gt; LFM3-Omni-2B-Q4_K_M.gguf &lt;span class="nt"&gt;-mm&lt;/span&gt; mmproj-LFM3-Omni-2B-Q8_0.gguf &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Hello world"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; out.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--tts-voice&lt;/code&gt; accepts &lt;code&gt;female&lt;/code&gt; (the default) or &lt;code&gt;male&lt;/code&gt;, and &lt;code&gt;--tts-lang&lt;/code&gt; defaults to &lt;code&gt;en&lt;/code&gt;. Liquid recommends audio temperature 0.4 and repetition penalty 1.2. The card says both values are already stored in the GGUF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Realtime voice, the reason I'd download this
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ggml-org/llama.cpp/pull/31269" rel="noopener noreferrer"&gt;PR #31269&lt;/a&gt; was merged on October 28. It adds voice chat with streaming audio in and out, plus live transcription, to the server's &lt;code&gt;/v1/realtime&lt;/code&gt; endpoint. The GGUF card advertises tool calls over the same endpoint. You choose the reply type with &lt;code&gt;output_modalities&lt;/code&gt;: &lt;code&gt;["text"]&lt;/code&gt;, &lt;code&gt;["audio"]&lt;/code&gt;, or &lt;code&gt;["audio", "text"]&lt;/code&gt; for interleaved voice chat. Leave it unset and the model decides. The PR includes &lt;code&gt;examples/realtime_client.py&lt;/code&gt; to test with. It was smoke-tested on Mac and CUDA with F32, Q8_0 and Q4_0. The PR doesn't give latency numbers, so I'm not repeating the time-to-first-audio claims going around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ollama, LM Studio or llama.cpp: which ones make it speak
&lt;/h2&gt;

&lt;p&gt;The GGUF card lists a lot of apps, but speech output is only available in a few of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;llama.cpp v0.8.0+: image, audio and video input, plus speech output via &lt;code&gt;llama-tts&lt;/code&gt;, &lt;code&gt;/tts&lt;/code&gt; and &lt;code&gt;/v1/realtime&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Llama.app (macOS, Windows): image, audio and video input&lt;/li&gt;
&lt;li&gt;Ollama v0.40.12+ (macOS): image and audio input&lt;/li&gt;
&lt;li&gt;LM Studio (llama.cpp engine 2.65.1+): image input only&lt;/li&gt;
&lt;li&gt;SGLang: text output only, according to the base card&lt;/li&gt;
&lt;li&gt;Transformers &lt;code&gt;&amp;gt;=5.20.2&lt;/code&gt;: everything, in BF16&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only llama.cpp and Transformers document speech output. Everywhere else you get a vision-language model with a microphone, at best.&lt;/p&gt;

&lt;h2&gt;
  
  
  The license: free until $10M revenue
&lt;/h2&gt;

&lt;p&gt;The license is the &lt;a href="https://www.liquid.ai/lfm-license" rel="noopener noreferrer"&gt;LFM Open License v1.0&lt;/a&gt;. It's free for commercial use until your company reaches $10M in annual revenue. Past that point you need to &lt;a href="https://docs.liquid.ai/lfm/help/model-license" rel="noopener noreferrer"&gt;contact Liquid for a paid license&lt;/a&gt;. The threshold still applies to fine-tunes and other derivatives. Qualifying nonprofits are exempt for non-commercial and research use. That's fine for hobby projects and startups, but a bigger company can't ship it without talking to Liquid's sales team first.&lt;/p&gt;

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

&lt;p&gt;This is the first 2B model I'd test as a fully local voice loop: ASR, a language model and TTS in one roughly 1.4 GB download, served over a WebSocket by a tool I already use. The 32K context, the drop in vision quality compared with LFM3-VL, and a tool-calling score 20 points behind Gemma 4 E4B are what you give up. For a kitchen-counter assistant that reads timers and the weather, I think it's enough. For an agent that has to remember a long conversation and pick the right tool reliably, I doubt it.&lt;/p&gt;

&lt;p&gt;Would you use a 2B omni model as your local voice assistant, or is 2B still too small to trust with tool calls? If you've already tested &lt;code&gt;/v1/realtime&lt;/code&gt;, tell me what latency you're getting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B-GGUF" rel="noopener noreferrer"&gt;LiquidAI/LFM3-Omni-2B-GGUF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/LFM3-Omni-2B" rel="noopener noreferrer"&gt;LiquidAI/LFM3-Omni-2B model card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/LFM3-VL-2B" rel="noopener noreferrer"&gt;LiquidAI/LFM3-VL-2B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B" rel="noopener noreferrer"&gt;LiquidAI/d1-Omni-2B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.liquid.ai/blog/lfm3" rel="noopener noreferrer"&gt;Liquid AI: LFM3 announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ggml-org/llama.cpp/releases/tag/v0.8.0" rel="noopener noreferrer"&gt;llama.cpp v0.8.0 release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ggml-org/llama.cpp/pull/31269" rel="noopener noreferrer"&gt;llama.cpp PR #31269: realtime conversation on /v1/realtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.liquid.ai/lfm-license" rel="noopener noreferrer"&gt;LFM Open License&lt;/a&gt; and &lt;a href="https://docs.liquid.ai/lfm/help/model-license" rel="noopener noreferrer"&gt;Liquid docs on the license&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>llm</category>
      <category>machinelearning</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>GitHub Actions Down Again? How to Mirror Your Repos to Codeberg Without Actions</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Sat, 31 Oct 2026 19:00:00 +0000</pubDate>
      <link>https://dev.to/alanwest/github-actions-down-again-how-to-mirror-your-repos-to-codeberg-without-actions-4h33</link>
      <guid>https://dev.to/alanwest/github-actions-down-again-how-to-mirror-your-repos-to-codeberg-without-actions-4h33</guid>
      <description>&lt;p&gt;On October 30 at 17:50 UTC, GitHub started &lt;a href="https://www.githubstatus.com/incidents/pwxsjgnvrk6b" rel="noopener noreferrer"&gt;investigating degraded performance for Actions and Webhooks&lt;/a&gt;. Ten minutes later Pages was on the list too. By 18:06 they were reporting delayed workflows, delayed Pages deployments, delayed webhook events, and errors in code search and live updates. The incident was marked resolved at 19:23.&lt;/p&gt;

&lt;p&gt;That's about 90 minutes on the status page. In the &lt;a href="https://news.ycombinator.com/item?id=50307723" rel="noopener noreferrer"&gt;Hacker News thread&lt;/a&gt;, one commenter pointed out that the same incident happened 11 days earlier, and another counted "several Actions outages in the past two weeks."&lt;/p&gt;

&lt;p&gt;The same day, Tangled published &lt;a href="https://tangled.org/blog/forge/" rel="noopener noreferrer"&gt;The federated code forge&lt;/a&gt;, arguing that relying on someone else for your uptime "hasn't played out well." I don't think the timing was planned. It still works as an ad.&lt;/p&gt;

&lt;p&gt;My take: don't move everything off GitHub because of one bad Friday afternoon. Spend an hour this week mirroring your repos to Codeberg, a self-hosted Forgejo or Tangled, so the next outage costs you 10 minutes instead of a lost evening. Below: a status check you can alias, four ways to mirror, the popular setup that fails during an outage, and a CI fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: check if GitHub is down before you debug your own pipeline
&lt;/h2&gt;

&lt;p&gt;I've seen people (fine, I've been one of them) rerun a stuck workflow four times, roll back a commit and blame a Dependabot bump before checking whether GitHub itself is broken. GitHub's status page has a public JSON API, so make the check a shell alias:&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;alias &lt;/span&gt;&lt;span class="nv"&gt;ghdown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'curl -s https://www.githubstatus.com/api/v2/components.json \
  | jq -r ".components[] | select(.status != \"operational\") | \"\(.name): \(.status)\""'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that prints &lt;code&gt;Actions: degraded_performance&lt;/code&gt;, close the laptop. To list active incidents, use &lt;code&gt;https://www.githubstatus.com/api/v2/incidents/unresolved.json&lt;/code&gt;. The &lt;a href="https://www.githubstatus.com/api" rel="noopener noreferrer"&gt;full endpoint list&lt;/a&gt; also covers summary, scheduled maintenance and incident history.&lt;/p&gt;

&lt;p&gt;One caveat from the HN thread: people noticed the 30-day uptime bar staying green during acknowledged incidents, because partial degradation isn't counted as downtime. One commenter mentioned that a third-party status page had to be built to track Actions accurately. So a green bar on the status page tells you very little.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: mirroring GitHub with a GitHub Action
&lt;/h2&gt;

&lt;p&gt;The most common mirror setup I see is a workflow that runs &lt;code&gt;git push --mirror&lt;/code&gt; to Codeberg on every push. It works fine until Actions goes down, and then the mirror stops updating at exactly the moment you need it.&lt;/p&gt;

&lt;p&gt;Your mirror has to be updated by something that doesn't depend on GitHub's job queue. That leaves two options: your own machine, or a forge that pushes or pulls on its own schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1: one &lt;code&gt;git push&lt;/code&gt;, two forges
&lt;/h2&gt;

&lt;p&gt;This is the cheapest setup and needs no infrastructure. Git lets one remote have several push URLs:&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="c"&gt;# keep fetching from GitHub, but push everywhere&lt;/span&gt;
git remote set-url &lt;span class="nt"&gt;--add&lt;/span&gt; &lt;span class="nt"&gt;--push&lt;/span&gt; origin git@github.com:you/project.git
git remote set-url &lt;span class="nt"&gt;--add&lt;/span&gt; &lt;span class="nt"&gt;--push&lt;/span&gt; origin git@codeberg.org:you/project.git
git remote set-url &lt;span class="nt"&gt;--add&lt;/span&gt; &lt;span class="nt"&gt;--push&lt;/span&gt; origin git@tangled.org:you.tngl.sh/project

git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;span class="c"&gt;# origin  git@github.com:you/project.git (fetch)&lt;/span&gt;
&lt;span class="c"&gt;# origin  git@github.com:you/project.git (push)&lt;/span&gt;
&lt;span class="c"&gt;# origin  git@codeberg.org:you/project.git (push)&lt;/span&gt;
&lt;span class="c"&gt;# origin  git@tangled.org:you.tngl.sh/project (push)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first &lt;code&gt;--add --push&lt;/code&gt; replaces the implicit push URL, which is why GitHub has to be listed explicitly. From then on, every &lt;code&gt;git push&lt;/code&gt; goes to all three. You need to create the empty repos on Codeberg and Tangled first.&lt;/p&gt;

&lt;p&gt;The weakness is that it only mirrors what you push from that clone. Merges done through the GitHub UI won't show up until someone pulls and pushes again. For a solo project that's fine. For a team, use option 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2: Codeberg, which only takes pushed mirrors
&lt;/h2&gt;

&lt;p&gt;Codeberg runs Forgejo, and Forgejo supports pull mirrors. Codeberg.org doesn't allow them, though. Their FAQ says that "mirrors that pull content from other code hosting services were problematic for Codeberg" and suggests manual mirrors with multiple remotes and &lt;code&gt;git push --mirror&lt;/code&gt; instead (&lt;a href="https://docs.codeberg.org/getting-started/faq/" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt;). That's option 1 again, and I think it's a reasonable rule for a nonprofit that pays for its own disks.&lt;/p&gt;

&lt;p&gt;If the Codeberg copy is a backup and nothing more, turn off issues and PRs in the repo settings so nobody files bugs in the wrong place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 3: self-hosted Forgejo pull mirror, then fan out
&lt;/h2&gt;

&lt;p&gt;If you have a $5 VPS or a homelab box, this is the setup I'd pick, because it's the only one here that catches merges done in the GitHub UI. On your own Forgejo instance, create the repo with &lt;strong&gt;New Migration&lt;/strong&gt; and check &lt;strong&gt;This repository will be a mirror&lt;/strong&gt;. Forgejo then pulls from GitHub on a schedule, including changes made through the GitHub web UI.&lt;/p&gt;

&lt;p&gt;You can then fan out from there: &lt;strong&gt;Settings &amp;gt; Repository &amp;gt; Mirror Settings &amp;gt; Add Push Mirror&lt;/strong&gt; pushes to Codeberg, Tangled or GitLab. For GitLab, the &lt;a href="https://forgejo.org/docs/latest/user/repo-mirror/" rel="noopener noreferrer"&gt;Forgejo docs&lt;/a&gt; say to use &lt;code&gt;oauth2&lt;/code&gt; as the username and a token with the &lt;code&gt;write_repository&lt;/code&gt; scope. SSH push mirrors generate an Ed25519 key that you add as a deploy key on the target.&lt;/p&gt;

&lt;p&gt;Two warnings from those docs: push mirrors are forced and overwrite the remote, and LFS over SSH isn't implemented, so an SSH push mirror won't carry your LFS objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 4: Tangled, the federated forge on ATProto
&lt;/h2&gt;

&lt;p&gt;Tangled is built on the AT Protocol, the same protocol Bluesky runs on. Repos live on "knots," which you can host yourself or leave on tangled.org. CI runs on "spindles." The October 30 release added knot2, a Rust rewrite of the knot server, and moved issues, PRs, comments, reactions and labels onto the knot as collaborative objects, each one "just a chain of Git objects in the repo itself." That matters for mirroring: if your knot holds the issues too, your backup carries the issue and PR discussion along with the commits. The blog's pitch is "Whatever you choose, you can still talk to everyone else."&lt;/p&gt;

&lt;p&gt;Pushing to it is plain SSH. Add your key under Settings &amp;gt; Keys, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;Host&lt;/span&gt; tangled.org
  &lt;span class="k"&gt;Hostname&lt;/span&gt; tangled.org
  &lt;span class="k"&gt;User&lt;/span&gt; git
  &lt;span class="k"&gt;IdentityFile&lt;/span&gt; ~/.ssh/id_ed25519
  &lt;span class="k"&gt;AddressFamily&lt;/span&gt; inet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a backup, the gaps count for more than the features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private repos aren't available yet. A co-founder said on HN they're rolling out "in the following couple weeks," and another team member said they have a working demo. Until they ship, Tangled only works for public code.&lt;/li&gt;
&lt;li&gt;HTTPS push and clone came up because people want knots behind Cloudflare. A team member replied that HTTPS push already works but isn't documented yet, so expect to figure it out yourself.&lt;/li&gt;
&lt;li&gt;On Windows, one commenter couldn't clone a repo with a colon in a filename. That's a Windows limit, not a Tangled bug, but it'll bite you the same way.&lt;/li&gt;
&lt;li&gt;Self-hosted knot operators have to upgrade to v1.20.0 for the new release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of &lt;a href="https://news.ycombinator.com/item?id=50305573" rel="noopener noreferrer"&gt;that thread&lt;/a&gt; is an argument about the protocol. One camp says ATProto "heavily lends itself to centralization." The other camp says relays are cheap and that ForgeFed, the ActivityPub approach Forgejo was working on, has been "in limbo forever." I lean toward Tangled here, but for a reason other than the protocol. A federated forge that ships stacked PRs today is more useful than a theoretically better protocol that hasn't shipped. Still, I wouldn't make a forge without private repos my only backup.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CI fallback: Forgejo Actions, Woodpecker or Tangled spindles
&lt;/h2&gt;

&lt;p&gt;A mirror with no CI is a read-only archive. You don't need to port your whole pipeline, just enough to run tests and cut a release by hand.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Where it runs&lt;/th&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Forgejo Actions&lt;/td&gt;
&lt;td&gt;Your runner, or Codeberg's &lt;a href="https://docs.codeberg.org/ci/actions/" rel="noopener noreferrer"&gt;limited hosted Actions&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.forgejo/workflows/*.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Designed to feel familiar to GitHub Actions users, though not compatible; disabled by default per repo on Codeberg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Woodpecker CI&lt;/td&gt;
&lt;td&gt;Codeberg's hosted instance (request access) or self-hosted&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.woodpecker.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What Codeberg's docs recommend for hosted CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tangled spindles&lt;/td&gt;
&lt;td&gt;Self-hosted runner, or third-party CI via &lt;a href="https://tangled.org/mitchellh.com/tack" rel="noopener noreferrer"&gt;tack&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.tangled/workflows/*.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nixery engine, deps from Nixpkgs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A minimal spindle workflow looks like this. The &lt;a href="https://tangled.org/j3s.sh/core/blob/ci/docs/spindle/pipeline.md" rel="noopener noreferrer"&gt;pipeline docs&lt;/a&gt; list &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull_request&lt;/code&gt; and &lt;code&gt;manual&lt;/code&gt; as events, and &lt;code&gt;nixery&lt;/code&gt; as the only engine for now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;push"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pull_request"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nixery"&lt;/span&gt;

&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nixpkgs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;go&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;go&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;./..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useful part of the Forgejo runner is that it connects outbound to the forge, so a box behind NAT works. Codeberg's docs say it "does not need a public IP address." An old laptop in a closet is enough to unblock a hotfix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-hour checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;ghdown&lt;/code&gt; alias, or a bookmark to &lt;code&gt;https://www.githubstatus.com/api/v2/summary.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create empty repos on Codeberg and/or Tangled.&lt;/li&gt;
&lt;li&gt;Add them as extra push URLs on &lt;code&gt;origin&lt;/code&gt;, or set up a pull mirror on your own Forgejo.&lt;/li&gt;
&lt;li&gt;Make sure the mirror doesn't depend on GitHub Actions.&lt;/li&gt;
&lt;li&gt;Copy your test job to one fallback CI and run it once, so you know it works before you need it.&lt;/li&gt;
&lt;li&gt;Write down which secrets the release job needs and where they'd live on the backup forge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm not leaving GitHub. It's still where people find your project, and it will probably stay that way. I just want "GitHub is down" to mean I push somewhere else for 90 minutes and keep working.&lt;/p&gt;

&lt;p&gt;So: do you keep a mirror of your repos anywhere besides GitHub, or are you all in? And if you've tried Tangled's ATProto setup, is it federation or a nicer-looking single point of failure?&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.githubstatus.com/incidents/pwxsjgnvrk6b" rel="noopener noreferrer"&gt;GitHub Status: Incident with Actions, Pages, and Webhooks&lt;/a&gt; and &lt;a href="https://news.ycombinator.com/item?id=50307723" rel="noopener noreferrer"&gt;HN discussion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.githubstatus.com/api" rel="noopener noreferrer"&gt;GitHub Status API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tangled.org/blog/forge/" rel="noopener noreferrer"&gt;Tangled: The federated code forge&lt;/a&gt; and &lt;a href="https://news.ycombinator.com/item?id=50305573" rel="noopener noreferrer"&gt;HN discussion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tangled.org/j3s.sh/core/blob/ci/docs/spindle/pipeline.md" rel="noopener noreferrer"&gt;Tangled spindle pipeline docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://forgejo.org/docs/latest/user/repo-mirror/" rel="noopener noreferrer"&gt;Forgejo: Repository mirrors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.codeberg.org/getting-started/faq/" rel="noopener noreferrer"&gt;Codeberg FAQ&lt;/a&gt; and &lt;a href="https://docs.codeberg.org/ci/actions/" rel="noopener noreferrer"&gt;Codeberg: Forgejo Actions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Is AI Making You a Worse Developer? Anthropic's Data Says Yes. Here's the Fix</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Sat, 31 Oct 2026 17:00:02 +0000</pubDate>
      <link>https://dev.to/alanwest/is-ai-making-you-a-worse-developer-anthropics-data-says-yes-heres-the-fix-1jj7</link>
      <guid>https://dev.to/alanwest/is-ai-making-you-a-worse-developer-anthropics-data-says-yes-heres-the-fix-1jj7</guid>
      <description>&lt;p&gt;Is AI making developers worse? In the best controlled study I've found, yes. Anthropic had 52 mostly junior engineers learn Trio, a Python async library. The ones who used an AI assistant scored 17 points lower on the follow-up quiz than the ones who wrote the code by hand, and the gap was widest on debugging questions, which is the part of the job you get paged for at 3 a.m.&lt;/p&gt;

&lt;p&gt;This week Hacker News had three threads on this going at once: SREs losing incident skills, Cisco handing a 27-year-old unlimited tokens to rewrite legacy code, and a lot of developers admitting they're just tired. Read next to the study, they're the same problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  SigNoz on SREs losing incident skills
&lt;/h2&gt;

&lt;p&gt;SigNoz's newsletter ran a piece called &lt;a href="https://newsletter.signoz.io/p/ai-isnt-replacing-sres-its-deskilling" rel="noopener noreferrer"&gt;"AI isn't replacing SREs, it's deskilling them"&lt;/a&gt;. According to the piece, AI now handles alert grouping, runbook execution, log pattern detection and auto-remediation for the easy failures, like restarting a crashed pod. Humans keep the leftovers: the novel, cascading, nobody-has-seen-this-before outages.&lt;/p&gt;

&lt;p&gt;The author asks: "When AI handles 95% of your incident response, do you get worse at handling the 5% that actually matters?"&lt;/p&gt;

&lt;p&gt;None of this is new. Lisanne Bainbridge described it in 1983 in &lt;a href="https://www.semanticscholar.org/paper/Ironies-of-automation-Bainbridge/0713bb9d9b138e4e0a15406006de9b0cddf68e28" rel="noopener noreferrer"&gt;"Ironies of Automation"&lt;/a&gt;: the more you automate, the more the human matters during the rare failure, and the less practice that human has had. The article lists what this looks like on an on-call rotation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You stop reading raw logs because the AI summarizes them.&lt;/li&gt;
&lt;li&gt;You stop forming hypotheses because the AI suggests a root cause.&lt;/li&gt;
&lt;li&gt;You stop building a mental model of the architecture because the AI maps dependencies for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of those is a productivity win on its own. Stack them up and you get an engineer who can't function when the summary is wrong.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://news.ycombinator.com/item?id=50305693" rel="noopener noreferrer"&gt;HN thread&lt;/a&gt; (601 points, 452 comments) mostly agreed, then argued about whether anyone will pay to fix it. digitallogic: "In the moment, getting the broken thing back up and running is seen as far more important than the learning opportunity." sshine got the whole article down to one line: "Atrophy happens when you trade understanding for productivity."&lt;/p&gt;

&lt;h2&gt;
  
  
  Cisco gives one engineer unlimited AI tokens to rewrite legacy code
&lt;/h2&gt;

&lt;p&gt;The same week, &lt;a href="https://fortune.com/2026/10/30/cisco-president-jeetu-patel-gen-z-27-year-old-unlimited-ai-tokens-rewrite-legacy-code-entry-level-jobs/" rel="noopener noreferrer"&gt;Fortune reported&lt;/a&gt; that Cisco president Jeetu Patel handed Padmanabhan "Paddy" Krishnamurthy, 27, unlimited AI tokens to refactor Cisco's legacy code. Krishnamurthy pitched it as a job for a two-person team and has four weeks to prove the idea. The end goal is 98% of Cisco's legacy code refactored within 24 months.&lt;/p&gt;

&lt;p&gt;"I've given him unlimited tokens because he's going to refactor code," Patel said. "So I'm like, you can go, you can go nuts."&lt;/p&gt;

&lt;p&gt;I have nothing against the guy. He co-founded a startup Cisco acquired, so he has shipped real things. My problem is the framing. Executives now treat tokens as the scarce resource, and on a rewrite like this they aren't. The scarce resource is people who understand what the old code actually does, including the bugs customers depend on without knowing it.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://news.ycombinator.com/item?id=50304122" rel="noopener noreferrer"&gt;HN thread on that one&lt;/a&gt; went straight there. cromka: "some of the bugs have become features without users even knowing it." raizer88 had the punchline: "Followup question: did anyone read the automated test suite? Silence. The software rewrite is shelved."&lt;/p&gt;

&lt;p&gt;So in one week we got engineers losing the ability to debug their systems, and a company betting it can rewrite its legacy code faster than anyone can read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the research says about AI deskilling
&lt;/h2&gt;

&lt;p&gt;Software isn't the only field with data on this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Study&lt;/th&gt;
&lt;th&gt;What happened&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Software&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills" rel="noopener noreferrer"&gt;Anthropic RCT&lt;/a&gt;, Jan 2026, 52 mostly junior engineers learning Trio&lt;/td&gt;
&lt;td&gt;AI group ~50% on the quiz vs ~67% hand-coding. Biggest gap on debugging. Time saved: ~2 min, not statistically significant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medicine&lt;/td&gt;
&lt;td&gt;Budzyń et al., &lt;a href="https://www.thelancet.com/journals/langas/article/PIIS2468-1253(25)00133-5/abstract" rel="noopener noreferrer"&gt;Lancet Gastroenterology &amp;amp; Hepatology&lt;/a&gt;, 4 Polish centres&lt;/td&gt;
&lt;td&gt;Adenoma detection in non-AI colonoscopies fell from 28.4% to 22.4% after doctors got used to AI assistance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aviation&lt;/td&gt;
&lt;td&gt;&lt;a href="https://flightsafety.org/wp-content/uploads/2019/12/IASS_2019_Behrend_Lafargue.pdf" rel="noopener noreferrer"&gt;Behrend &amp;amp; Lafargue, IASS 2019&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Air France eye-tracking study: hand-flying with the flight director on doesn't build the basic skills that flying with it off does, and long-haul pilots are most exposed to skill erosion. The SigNoz piece makes the same comparison with the FAA and manual flying time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Anthropic one is worth reading in full. The authors are open about its limits (small sample, quiz taken right after a 35-minute coding task), and they say agentic tools like Claude Code could hit skill development &lt;em&gt;harder&lt;/em&gt; than the sidebar chat assistant they tested.&lt;/p&gt;

&lt;p&gt;The most useful part is the breakdown by how people used the AI. The groups are tiny (two to seven people each), so treat this as a hint. Participants who delegated everything scored around 39%. The "iterative AI debugging" group, the ones who kept pasting errors back in until something worked, scored about 24% and were also the slowest at roughly 31 minutes. The two people who generated code and then asked follow-up questions to understand it scored about 86%.&lt;/p&gt;

&lt;p&gt;The way you use the assistant seems to matter more than whether you use one. The worst pattern in that study, on both speed and learning, was "paste the stack trace, apply the patch, repeat".&lt;/p&gt;

&lt;h2&gt;
  
  
  Developers are also exhausted
&lt;/h2&gt;

&lt;p&gt;The third thread, &lt;a href="https://news.ycombinator.com/item?id=50301479" rel="noopener noreferrer"&gt;"Ask HN: Are you tired too in this AI era?"&lt;/a&gt; (144 points, 139 comments), started with the poster describing having to "read enormous amounts of generated text." thunfischtoast: "I feel my brain atrophying. I forget how to do things." Gigachad, on PRs nobody understood: "I just don't have time to review 4000 lines of code."&lt;/p&gt;

&lt;p&gt;This worries me more than the study. Tired engineers rubber-stamp, and rubber-stamping builds no mental model. The 3 a.m. outage then lands on someone who has approved a lot of diffs and understood very few of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 ways to keep AI from deskilling you
&lt;/h2&gt;

&lt;p&gt;I'm not giving up the tools. They're too good at the boring 80%. But I've started following a few rules, and they cost almost nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Debug by hand for a few hours a week
&lt;/h3&gt;

&lt;p&gt;Pick a block each week (I use Friday afternoons) where any bug you touch gets debugged with no assistant: logs, &lt;code&gt;git bisect&lt;/code&gt;, a debugger, &lt;code&gt;strace&lt;/code&gt; if it comes to that. On-call teams can copy the SigNoz suggestion of "deliberate inefficiency": send some incidents the AI &lt;em&gt;could&lt;/em&gt; resolve to a human as practice. Airlines push pilots to hand-fly for the same reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write your hypothesis before you paste the alert
&lt;/h3&gt;

&lt;p&gt;Two lines in the incident channel: what you think broke, and what would prove you wrong. Then ask the model. If it agrees, your model of the system holds up. If it disagrees, you get to find out which of you is wrong, and that's the part where you learn something.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Make the agent explain before it fixes
&lt;/h3&gt;

&lt;p&gt;Claude Code has a built-in setting for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/output-style learning
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learning mode adds &lt;code&gt;Insight&lt;/code&gt; blocks explaining its choices and leaves &lt;code&gt;TODO(human)&lt;/code&gt; markers for the parts with real design decisions. &lt;code&gt;/output-style explanatory&lt;/code&gt; gives you the explanations without the homework. (The Anthropic study authors point to these same two modes.) To make it the default across projects, set it in &lt;code&gt;~/.claude/settings.json&lt;/code&gt;:&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;"outputStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Explanatory"&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 value is case-sensitive, per the &lt;a href="https://code.claude.com/docs/en/output-styles" rel="noopener noreferrer"&gt;docs&lt;/a&gt;. &lt;code&gt;"explanatory"&lt;/code&gt; silently falls back to Default. Whatever tool you use, put a rule like this in your project instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Before proposing any fix for a bug or incident:
&lt;span class="p"&gt;1.&lt;/span&gt; State the root cause in one paragraph.
&lt;span class="p"&gt;2.&lt;/span&gt; Name the evidence (log line, metric, trace) that supports it.
&lt;span class="p"&gt;3.&lt;/span&gt; Say what would make this diagnosis wrong.
Do not edit files until I reply "go".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Write the postmortem yourself
&lt;/h3&gt;

&lt;p&gt;No AI drafts. Rebuilding the timeline by hand forces you to understand why the system failed, and that's how the mental model gets built. Use the AI afterwards to check you didn't miss anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Read the tests on any AI rewrite
&lt;/h3&gt;

&lt;p&gt;If you're on a Cisco-style refactor, that raizer88 comment is your checklist. If nobody has read the test suite, nobody knows what "done" means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rusty seniors, juniors who never learn
&lt;/h2&gt;

&lt;p&gt;I don't think AI is coming for most developer jobs this year. What I see happening is slower than that and harder to spot. Juniors are losing the hands-on incidents where people used to build intuition, which the SigNoz piece calls "never-skilling." The seniors are getting rusty at the one part of the job the AI still can't do, which is noticing when the AI's answer is confidently wrong.&lt;/p&gt;

&lt;p&gt;So be honest: could you still debug a production outage today without an AI assistant? When did you last try?&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://newsletter.signoz.io/p/ai-isnt-replacing-sres-its-deskilling" rel="noopener noreferrer"&gt;AI isn't replacing SREs, it's deskilling them (SigNoz)&lt;/a&gt; · &lt;a href="https://news.ycombinator.com/item?id=50305693" rel="noopener noreferrer"&gt;HN discussion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fortune.com/2026/10/30/cisco-president-jeetu-patel-gen-z-27-year-old-unlimited-ai-tokens-rewrite-legacy-code-entry-level-jobs/" rel="noopener noreferrer"&gt;Cisco gives engineer unlimited AI tokens to rewrite legacy code (Fortune)&lt;/a&gt; · &lt;a href="https://news.ycombinator.com/item?id=50304122" rel="noopener noreferrer"&gt;HN discussion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=50301479" rel="noopener noreferrer"&gt;Ask HN: Are you tired too in this AI era?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills" rel="noopener noreferrer"&gt;How AI assistance impacts the formation of coding skills (Anthropic)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.thelancet.com/journals/langas/article/PIIS2468-1253(25)00133-5/abstract" rel="noopener noreferrer"&gt;Endoscopist deskilling after exposure to AI in colonoscopy (Lancet Gastroenterology &amp;amp; Hepatology)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.semanticscholar.org/paper/Ironies-of-automation-Bainbridge/0713bb9d9b138e4e0a15406006de9b0cddf68e28" rel="noopener noreferrer"&gt;Bainbridge, Ironies of Automation (1983)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/output-styles" rel="noopener noreferrer"&gt;Claude Code output styles docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>discuss</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Stop Claude Code From Reading Your .env File (Deny Rules Aren't Enough)</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Sat, 31 Oct 2026 15:10:00 +0000</pubDate>
      <link>https://dev.to/alanwest/how-to-stop-claude-code-from-reading-your-env-file-deny-rules-arent-enough-3a9c</link>
      <guid>https://dev.to/alanwest/how-to-stop-claude-code-from-reading-your-env-file-deny-rules-arent-enough-3a9c</guid>
      <description>&lt;p&gt;Claude Code doesn't ask before reading files in your project. Anthropic's own &lt;a href="https://code.claude.com/docs/en/permissions" rel="noopener noreferrer"&gt;permissions table&lt;/a&gt; says it: read-only tools like file reads and Grep need "No" approval within the working directory. Your &lt;code&gt;.env&lt;/code&gt; sits in the working directory. So unless you've changed something, the agent can open it, put your Stripe key into its context, and quote it back in a debug log without ever asking.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt; does nothing here. It only keeps the file out of commits. The agent reads straight from disk.&lt;/p&gt;

&lt;p&gt;There's a fresh reason to care. On October 30, Phorion &lt;a href="https://phorion.io/blog/offical-claude-code-vsx-compromise/" rel="noopener noreferrer"&gt;published an advisory&lt;/a&gt; about a backdoored "Claude Code for VS Code" build on the Cursor Marketplace, versions 2.1.312 and 2.1.313. It added an attacker's SSH key to &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;, opened a reverse tunnel, and beaconed home with up to 40 environment variable &lt;em&gt;names&lt;/em&gt; matching &lt;code&gt;KEY|TOKEN|SECRET|PASS|AWS|GCP&lt;/code&gt;. On &lt;a href="https://news.ycombinator.com/item?id=50300683" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt;, Anthropic's Felix Rieseberg said "it wasn't a compromise of Anthropic's systems or employee laptops." I don't much care whose fault it was. Every file your tooling can read is one bad update away from leaving your machine.&lt;/p&gt;

&lt;p&gt;Below is my setup. The deny rule most guides stop at is only the first step, because Bash can still read the file around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block Claude Code from reading .env with permissions.deny
&lt;/h2&gt;

&lt;p&gt;Put this in &lt;code&gt;~/.claude/settings.json&lt;/code&gt; so it applies to every project:&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;"permissions"&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;"deny"&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="s2"&gt;"Read(.env)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(.env.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(**/secrets/**)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(~/.ssh/**)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Read(~/.aws/**)"&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 first two rules handle &lt;code&gt;.env&lt;/code&gt;. The other three are cheap to add while you're in there.&lt;/p&gt;

&lt;p&gt;The path syntax trips people up. The docs' own example uses &lt;code&gt;Read(./.env)&lt;/code&gt;, which &lt;a href="https://code.claude.com/docs/en/permissions#read-and-edit" rel="noopener noreferrer"&gt;matches&lt;/a&gt; "the &lt;code&gt;.env&lt;/code&gt; file in the current directory". A bare &lt;code&gt;Read(.env)&lt;/code&gt; follows gitignore semantics and matches any &lt;code&gt;.env&lt;/code&gt; at or under the current directory, so &lt;code&gt;apps/api/.env&lt;/code&gt; in your monorepo is covered too. Also, don't put &lt;code&gt;Read(/secrets/**)&lt;/code&gt; in user settings. There, a leading &lt;code&gt;/&lt;/code&gt; anchors to &lt;code&gt;~/.claude&lt;/code&gt;, so it would block &lt;code&gt;~/.claude/secrets/**&lt;/code&gt; and leave your project alone.&lt;/p&gt;

&lt;p&gt;What these rules cover, per the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Read tool, plus a best-effort pass over Grep, Glob, &lt;code&gt;@file&lt;/code&gt; mentions and the open-file context the IDE extension shares&lt;/li&gt;
&lt;li&gt;Edit and Write on the same path (Write needs v2.1.228+)&lt;/li&gt;
&lt;li&gt;Bash commands Claude Code recognizes as file commands: &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;tee&lt;/code&gt;, and redirections like &lt;code&gt;&amp;lt; .env&lt;/code&gt; (input redirects are checked from v2.1.257, &lt;code&gt;tee&lt;/code&gt; targets from v2.1.269)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you still have a &lt;code&gt;.claudeignore&lt;/code&gt; file lying around, the docs say flatly that "it has no effect". Move its entries into deny rules.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;/status&lt;/code&gt; afterwards and check that &lt;code&gt;User settings&lt;/code&gt; shows up under &lt;code&gt;Setting sources&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What deny rules don't cover: Bash can still read your secrets
&lt;/h2&gt;

&lt;p&gt;Most "just add a deny rule" posts skip this part. According to the &lt;a href="https://code.claude.com/docs/en/permissions#read-and-edit" rel="noopener noreferrer"&gt;permissions warning box&lt;/a&gt;, deny rules don't apply to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a command that reads files without naming them, such as &lt;code&gt;grep -r pattern .&lt;/code&gt; run from the directory that holds the file, or to arbitrary subprocesses that read or write files indirectly, like a Python or Node script that opens files itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So &lt;code&gt;cat .env&lt;/code&gt; gets blocked, but &lt;code&gt;grep -r DATABASE_URL .&lt;/code&gt; or &lt;code&gt;node -e "require('dotenv').config(); console.log(process.env)"&lt;/code&gt; doesn't. Nobody has to be malicious for this to happen. An agent debugging a connection error will try exactly those commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Close the Bash hole with the sandbox
&lt;/h2&gt;

&lt;p&gt;This has to be enforced by the OS. Claude Code's &lt;a href="https://code.claude.com/docs/en/sandboxing" rel="noopener noreferrer"&gt;sandbox&lt;/a&gt; uses Seatbelt on macOS and bubblewrap on Linux and WSL2, and the docs say Read and Edit deny rules get "merged into the final sandbox configuration". With it on, the kernel stops &lt;code&gt;grep -r&lt;/code&gt; and that Node one-liner, where before they slipped past a string matcher.&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;"sandbox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"failIfUnavailable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowUnsandboxedCommands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&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;"denyRead"&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="s2"&gt;"~/.ssh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.aws"&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;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;Why the two less obvious keys are in there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, if the sandbox can't start, Claude Code "runs commands without sandboxing". That fails open. &lt;code&gt;failIfUnavailable: true&lt;/code&gt; makes it exit instead.&lt;/li&gt;
&lt;li&gt;When a sandboxed command fails, Claude may retry it with &lt;code&gt;dangerouslyDisableSandbox&lt;/code&gt;, and in &lt;code&gt;bypassPermissions&lt;/code&gt; mode that retry runs without a prompt. &lt;code&gt;allowUnsandboxedCommands: false&lt;/code&gt; turns the retry off.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The sandbox has two limits. Its default read scope is "most of the machine, including credential files such as &lt;code&gt;~/.ssh&lt;/code&gt; and &lt;code&gt;~/.aws/credentials&lt;/code&gt;", so you have to list what you want hidden. And on native Windows, commands run unsandboxed, full stop. Use WSL2.&lt;/p&gt;

&lt;p&gt;If you're on v2.1.257 or later, also set &lt;code&gt;"blockReadsOutsideWorkingDirectories": true&lt;/code&gt; under &lt;code&gt;permissions&lt;/code&gt;. It makes Read, Grep, Glob and LSP refuse paths outside your project in every mode, including &lt;code&gt;bypassPermissions&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A PreToolUse hook as a tripwire
&lt;/h2&gt;

&lt;p&gt;I still run a hook with the sandbox on. You get a clear message in the transcript, and it works on machines where you can't sandbox. Save this as &lt;code&gt;.claude/hooks/block-secrets.sh&lt;/code&gt; and &lt;code&gt;chmod +x&lt;/code&gt; it:&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_input.command // empty'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Eq&lt;/span&gt; &lt;span class="s1"&gt;'\.env([^A-Za-z]|$)|secrets/|\.ssh/|id_(rsa|ed25519)|\.aws/credentials'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Blocked: this command touches a secrets file. Ask the user for the value instead."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wire it up in &lt;code&gt;.claude/settings.json&lt;/code&gt;:&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;"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;"PreToolUse"&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;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&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;"${CLAUDE_PROJECT_DIR}/.claude/hooks/block-secrets.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;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;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;Exit code 2 blocks the call and sends stderr back to Claude as the reason, per the &lt;a href="https://code.claude.com/docs/en/hooks" rel="noopener noreferrer"&gt;hooks docs&lt;/a&gt;. The regex is deliberately greedy: it also catches &lt;code&gt;process.env.FOO&lt;/code&gt; and &lt;code&gt;.env.example&lt;/code&gt;. I'd rather get a false positive than explain a rotated key to my team. It doesn't match &lt;code&gt;.envrc&lt;/code&gt;, so add that if you use direnv.&lt;/p&gt;

&lt;p&gt;It's only a string match on the command text, though, so &lt;code&gt;grep -r pattern .&lt;/code&gt; sails right through it. Anthropic says the same about its own &lt;code&gt;if&lt;/code&gt; filters: use the permission system, "rather than a hook to enforce a hard allow or deny". I treat the hook as a readable error message and leave the blocking to the sandbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same fix in Cursor and Codex
&lt;/h2&gt;

&lt;p&gt;Cursor gives you a better default. Its &lt;a href="https://cursor.com/docs/context/ignore-files" rel="noopener noreferrer"&gt;ignore docs&lt;/a&gt; say it respects &lt;code&gt;.gitignore&lt;/code&gt; plus a built-in list that includes &lt;code&gt;.env*&lt;/code&gt;, and you can add paths with &lt;code&gt;.cursorignore&lt;/code&gt;. The same page also says: "The terminal and MCP server tools used by Agent cannot block access to code governed by &lt;code&gt;.cursorignore&lt;/code&gt;." So you're back to the same Bash hole, without a sandbox config to close it.&lt;/p&gt;

&lt;p&gt;Codex handles it as a filesystem permission profile, enforced on sandboxed commands. From the &lt;a href="https://learn.chatgpt.com/docs/permissions.md" rel="noopener noreferrer"&gt;permissions docs&lt;/a&gt;, in &lt;code&gt;~/.codex/config.toml&lt;/code&gt;:&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="n"&gt;default_permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"project-edit"&lt;/span&gt;

&lt;span class="k"&gt;[&lt;/span&gt;&lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project-edit&lt;/span&gt;&lt;span class="k"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;":workspace"&lt;/span&gt;

&lt;span class="k"&gt;[&lt;/span&gt;&lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project-edit&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filesystem&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="s"&gt;":workspace_roots"&lt;/span&gt;&lt;span class="k"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;"**/*.env"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"deny"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch for two things. If &lt;code&gt;sandbox_mode&lt;/code&gt; shows up in any active config layer, or you pass &lt;code&gt;--sandbox&lt;/code&gt;, Codex falls back to the legacy sandbox settings and your profile doesn't apply. And on Linux, WSL and some Windows modes, glob matches are captured "when each sandboxed process starts", so a long-running dev server won't see a &lt;code&gt;.env&lt;/code&gt; you create later as denied. For env vars, set &lt;code&gt;shell_environment_policy.ignore_default_excludes = false&lt;/code&gt; so Codex strips variables containing &lt;code&gt;KEY&lt;/code&gt;, &lt;code&gt;SECRET&lt;/code&gt; or &lt;code&gt;TOKEN&lt;/code&gt; from subprocesses.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Default on &lt;code&gt;.env&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Built-in file tools&lt;/th&gt;
&lt;th&gt;Shell commands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;Readable, no prompt&lt;/td&gt;
&lt;td&gt;&lt;code&gt;permissions.deny&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only with &lt;code&gt;sandbox.enabled&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;Ignored (&lt;code&gt;.env*&lt;/code&gt; on default list)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.cursorignore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not blocked, per docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;Readable under &lt;code&gt;:workspace&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Permission profile &lt;code&gt;deny&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Enforced in sandbox, glob snapshot caveat&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What none of this fixes
&lt;/h2&gt;

&lt;p&gt;The backdoored extension never went through Claude Code's permission system. It ran inside the editor with your user's full access. No deny rule stops that. What helps is a separate user account or container for agent work (a couple of HN commenters suggest exactly this), and not keeping production secrets in plaintext files at all. Inject them at runtime from a vault or &lt;code&gt;op run&lt;/code&gt;, and keep &lt;code&gt;.env&lt;/code&gt; for local throwaway values.&lt;/p&gt;

&lt;p&gt;If you installed 2.1.312 or 2.1.313 in Cursor, run &lt;code&gt;grep -n svc-telemetry ~/.ssh/authorized_keys&lt;/code&gt; and check &lt;code&gt;~/Library/LaunchAgents/com.apple.sysmond.plist&lt;/code&gt; on macOS. The label is just a comment and trivial to change, so Phorion also says to check the fingerprint: run &lt;code&gt;ssh-keygen -lf ~/.ssh/authorized_keys&lt;/code&gt; and look for &lt;code&gt;SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My minimum setup: the deny block, the sandbox with &lt;code&gt;failIfUnavailable&lt;/code&gt;, and the hook as a tripwire. It takes ten minutes.&lt;/p&gt;

&lt;p&gt;So where do your secrets actually live while you code with an agent: &lt;code&gt;.env&lt;/code&gt;, a vault, or "I'd rather not say"? And if you think the sandbox is overkill for local dev, tell me why in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://phorion.io/blog/offical-claude-code-vsx-compromise/" rel="noopener noreferrer"&gt;Phorion: backdoor in Claude Code for VS Code on the Cursor Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=50300683" rel="noopener noreferrer"&gt;Hacker News discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/permissions" rel="noopener noreferrer"&gt;Claude Code: Configure permissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/settings" rel="noopener noreferrer"&gt;Claude Code: Settings files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/settings-reference" rel="noopener noreferrer"&gt;Claude Code: Settings reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/sandboxing" rel="noopener noreferrer"&gt;Claude Code: Sandboxing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/hooks" rel="noopener noreferrer"&gt;Claude Code: Hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cursor.com/docs/context/ignore-files" rel="noopener noreferrer"&gt;Cursor: Ignore files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/permissions.md" rel="noopener noreferrer"&gt;Codex: Permissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/config-file/config-reference" rel="noopener noreferrer"&gt;Codex: Config reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>claude</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Claude Code Extension Backdoor in Cursor: Uninstalling Won't Remove the SSH Key</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Sat, 31 Oct 2026 13:20:01 +0000</pubDate>
      <link>https://dev.to/alanwest/claude-code-extension-backdoor-in-cursor-uninstalling-wont-remove-the-ssh-key-4o2k</link>
      <guid>https://dev.to/alanwest/claude-code-extension-backdoor-in-cursor-uninstalling-wont-remove-the-ssh-key-4o2k</guid>
      <description>&lt;p&gt;If you run Cursor on macOS or Windows and it pulled the Claude Code extension (&lt;code&gt;anthropic.claude-code&lt;/code&gt;) 2.1.312 or 2.1.313 on October 29, your machine may now have a stranger's SSH key in &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; and a reverse SSH tunnel that restarts at login. Uninstalling the Claude Code extension doesn't remove it. Updating to 2.1.314 doesn't remove it either.&lt;/p&gt;

&lt;p&gt;The check takes about 5 minutes and uses the indicators Cursor, Phorion and Microsoft published. After that I cover what to rotate and how to stop your editor from installing whatever turns up in a marketplace overnight.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened with the Claude Code extension backdoor in Cursor
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://cursor.com/blog/claude-code-extension-security-notice" rel="noopener noreferrer"&gt;Cursor's security notice&lt;/a&gt;, tampered builds of &lt;code&gt;Anthropic.claude-code&lt;/code&gt; versions 2.1.312 and 2.1.313 for Windows and macOS were served from the Cursor Extension Marketplace between about 2:27am and 1:35pm PT on October 29, 2026. Cursor says those builds "were not developed by Anthropic". &lt;a href="https://www.stepsecurity.io/blog/claude-code-extension-trojanized" rel="noopener noreferrer"&gt;StepSecurity&lt;/a&gt; reports that, by Cursor's count, "at most 5,000" of its users received the trojanized build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phorion.io/blog/offical-claude-code-vsx-compromise/" rel="noopener noreferrer"&gt;Phorion&lt;/a&gt; published a teardown. Someone had prepended code to the minified &lt;code&gt;extension.js&lt;/code&gt;, and it runs as soon as Node loads the file, before &lt;code&gt;activate&lt;/code&gt; is even called. You didn't have to click anything or open a Claude panel; loading the extension was enough.&lt;/p&gt;

&lt;p&gt;The part that bothers me most is the listing itself. It used the real extension ID, the one you'd tell a junior dev is safe to trust. Most of us have learned to look out for typosquats like &lt;code&gt;anthropic-official-claude&lt;/code&gt;, and that habit was no help here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is affected (and who isn't)
&lt;/h2&gt;

&lt;p&gt;The early headlines went too far. DoublePulsar ran "Anthropic hacked to deliver remote access trojan", but Anthropic engineers said on &lt;a href="https://news.ycombinator.com/item?id=50300683" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt; that their systems and laptops weren't compromised. They also made sure their next real update was 2.1.314, "in order to disambiguate" it from the tampered builds. Per &lt;a href="https://www.stepsecurity.io/blog/claude-code-extension-trojanized" rel="noopener noreferrer"&gt;StepSecurity&lt;/a&gt; and &lt;a href="https://www.microsoft.com/en-us/security/blog/2026/10/30/inside-malicious-claude-code-branded-cursor-extension-persistent-ssh-backdoor/" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where you got the extension&lt;/th&gt;
&lt;th&gt;2.1.312&lt;/th&gt;
&lt;th&gt;2.1.313&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cursor Marketplace (Win/macOS)&lt;/td&gt;
&lt;td&gt;malicious build served Oct 29&lt;/td&gt;
&lt;td&gt;malicious&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open VSX (VSCodium, Windsurf, etc.)&lt;/td&gt;
&lt;td&gt;clean&lt;/td&gt;
&lt;td&gt;not found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft VS Code Marketplace&lt;/td&gt;
&lt;td&gt;not affected&lt;/td&gt;
&lt;td&gt;never published&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So plain VS Code and VSCodium users can relax, mostly. Cursor users on macOS or Windows who had the editor running that day should check. The implant also contains Linux persistence logic, so Linux Cursor users should run the checks too. They take about a minute.&lt;/p&gt;

&lt;p&gt;I don't fully buy Anthropic's "not our systems" line as the end of the story, though. The extension said "Anthropic" on it. As one HN commenter put it, "the malware has their branding and their name on it." Cursor's own docs say extension searches and downloads go through its proxy at &lt;code&gt;marketplace.cursorapi.com&lt;/code&gt;, and Anthropic's Felix Rieseberg wrote on HN that a malicious actor "used access to Cursor's marketplace" to ship the build under the real ID. Cursor's notice says it audited access and rotated keys, but not how the attacker got in. Until someone explains that, I think both companies own part of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: list your extensions and versions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cursor &lt;span class="nt"&gt;--list-extensions&lt;/span&gt; &lt;span class="nt"&gt;--show-versions&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; claude
code   &lt;span class="nt"&gt;--list-extensions&lt;/span&gt; &lt;span class="nt"&gt;--show-versions&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; claude
codium &lt;span class="nt"&gt;--list-extensions&lt;/span&gt; &lt;span class="nt"&gt;--show-versions&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A clean result here doesn't settle anything. If Cursor has already updated you to 2.1.314, the 2.1.313 folder is probably gone, but the persistence it dropped outside the extension folder is still there. Look on disk too:&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; ~/.cursor/extensions/anthropic.claude-code-&lt;span class="k"&gt;*&lt;/span&gt; 2&amp;gt;/dev/null
find ~/.cursor/extensions &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s1"&gt;'*claude-code*'&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; extension.js &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-exec&lt;/span&gt; shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backdoored &lt;code&gt;extension.js&lt;/code&gt; hashes to &lt;code&gt;ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15&lt;/code&gt;. Cursor's notice also lists VSIX hashes for each version and platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: check for the SSH key and persistence (macOS / Linux)
&lt;/h2&gt;

&lt;p&gt;If you only run one set of checks, run these:&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="c"&gt;# 1. The planted login key&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'svc-telemetry'&lt;/span&gt; ~/.ssh/authorized_keys
ssh-keygen &lt;span class="nt"&gt;-lf&lt;/span&gt; ~/.ssh/authorized_keys | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk'&lt;/span&gt;

&lt;span class="c"&gt;# 2. Dropped scripts and keys&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; ~/.config/.smt ~/.config/.smtk 2&amp;gt;/dev/null
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /tmp/.stk_&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TMPDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/.stk_&lt;span class="k"&gt;*&lt;/span&gt; 2&amp;gt;/dev/null

&lt;span class="c"&gt;# 3. macOS LaunchAgent pretending to be Apple&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; ~/Library/LaunchAgents/com.apple.sysmond.plist 2&amp;gt;/dev/null
launchctl list | &lt;span class="nb"&gt;grep &lt;/span&gt;sysmond

&lt;span class="c"&gt;# 4. Linux cron entry&lt;/span&gt;
crontab &lt;span class="nt"&gt;-l&lt;/span&gt; 2&amp;gt;/dev/null | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'\.smt'&lt;/span&gt;

&lt;span class="c"&gt;# 5. Live tunnel&lt;/span&gt;
ps &lt;span class="nt"&gt;-eo&lt;/span&gt; pid,args | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'134\.209\.82\.225|:0:localhost:22'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the fingerprint check even if the grep finds nothing. Phorion points out that the malware looks for the string &lt;code&gt;svc-telemetry&lt;/code&gt; and not the key itself, so a key with an edited comment would slip past a plain grep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 (Windows)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Select-String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\.ssh\authorized_keys"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"C:\ProgramData\ssh\administrators_authorized_keys"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'svc-telemetry'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-ScheduledTask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TaskName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SysMon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Microsoft\Windows\Start Menu\Programs\Startup\sysmon.cmd"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\.config\smt.cmd"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;TEMP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.stk_*'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Network indicators
&lt;/h2&gt;

&lt;p&gt;If you have firewall, DNS or EDR logs, search them for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;134.209.82.225&lt;/code&gt; on TCP 22 (reverse SSH as user &lt;code&gt;tunnel&lt;/code&gt;, with &lt;code&gt;-R *:0:localhost:22&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;http://134.209.82.225:8099/beacon&lt;/code&gt; (HTTP POST)&lt;/li&gt;
&lt;li&gt;SSH logins from &lt;code&gt;127.0.0.1&lt;/code&gt; or &lt;code&gt;::1&lt;/code&gt; using the &lt;code&gt;svc-telemetry&lt;/code&gt; key. The operator comes back in through the tunnel, so the login looks local.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Microsoft's post includes Defender XDR hunting queries if your company runs that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How bad is it if you find something?
&lt;/h2&gt;

&lt;p&gt;The payload isn't very good, which is lucky. Phorion found that on macOS it runs &lt;code&gt;systemsetup -getremotelogin&lt;/code&gt; without admin rights, gets an error, and so never turns Remote Login on. On Windows the OpenSSH install goes through a helper hardcoded to &lt;code&gt;/bin/sh&lt;/code&gt;, which probably fails. Cursor says the attacker's server is now offline.&lt;/p&gt;

&lt;p&gt;That said, if Remote Login was &lt;em&gt;already&lt;/em&gt; enabled on your Mac, or sshd was already running on your Linux box, the tunnel pointed straight at it and the attacker had a working SSH path into your account for as long as it stayed up.&lt;/p&gt;

&lt;p&gt;The beacon also sent your hostname, username, git email, public IP, and up to 40 environment variable names matching &lt;code&gt;KEY|TOKEN|SECRET|PASS|AWS|GCP&lt;/code&gt;. Only the names went out, not the values, but that still gives the attacker a list of which machines hold AWS keys and which ones are worth logging into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean up, then rotate
&lt;/h2&gt;

&lt;p&gt;Cursor provides &lt;code&gt;remediate-macos.sh&lt;/code&gt; (run as your user, not root) and &lt;code&gt;remediate-windows.ps1&lt;/code&gt; (run as Administrator) on the &lt;a href="https://cursor.com/blog/claude-code-extension-security-notice" rel="noopener noreferrer"&gt;notice page&lt;/a&gt;. If you'd rather do it by hand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Kill the &lt;code&gt;ssh&lt;/code&gt;/&lt;code&gt;autossh&lt;/code&gt; processes and their retry loop.&lt;/li&gt;
&lt;li&gt;Unload and delete &lt;code&gt;com.apple.sysmond.plist&lt;/code&gt;, remove the &lt;code&gt;@reboot&lt;/code&gt; cron line, or delete the &lt;code&gt;SysMon&lt;/code&gt; task and &lt;code&gt;sysmon.cmd&lt;/code&gt;. Then delete &lt;code&gt;~/.config/.smt&lt;/code&gt; and &lt;code&gt;.smtk&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Remove only the &lt;code&gt;svc-telemetry&lt;/code&gt; line from &lt;code&gt;authorized_keys&lt;/code&gt;, and delete the &lt;code&gt;.stk_*&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;Check that Remote Login / sshd is in the state you expect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Phorion warns that a bug in the malware's cron check can wipe your existing user cron jobs on repeat runs, so compare &lt;code&gt;crontab -l&lt;/code&gt; against what you remember having.&lt;/p&gt;

&lt;p&gt;If you found any artifact, rotate everything that user account could reach. Start with anything an env var name like &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; or &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; pointed to, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your SSH keys (generate new ones and remove the old public keys from GitHub, GitLab and your servers)&lt;/li&gt;
&lt;li&gt;git tokens, &lt;code&gt;gh auth&lt;/code&gt; sessions, and npm/PyPI publish tokens&lt;/li&gt;
&lt;li&gt;cloud credentials in &lt;code&gt;~/.aws&lt;/code&gt;, &lt;code&gt;~/.config/gcloud&lt;/code&gt; and &lt;code&gt;~/.azure&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Anthropic, OpenAI and other API keys sitting in &lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do the rotation from a different machine. If you're a company with EDR, Microsoft and Cursor both suggest isolating the host and considering a rebuild. I'd rebuild any machine where you can't rule out an inbound login.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin extensions and stop auto-updating them
&lt;/h2&gt;

&lt;p&gt;Auto-update is how a build like this reaches thousands of laptops without anyone clicking anything, and it's easy to switch off.&lt;/p&gt;

&lt;p&gt;In VS Code, VSCodium or Cursor &lt;code&gt;settings.json&lt;/code&gt;:&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;"extensions.autoUpdate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions.autoCheckUpdates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cursor also has an install cooldown. Per &lt;a href="https://cursor.com/help/customization/extensions" rel="noopener noreferrer"&gt;Cursor's extensions docs&lt;/a&gt;, the per-user setting is &lt;code&gt;extensions.installCooldownHours&lt;/code&gt;, and team admins can enforce "Marketplace Install Cooldown (hours)" fleet-wide under Team settings → Security &amp;amp; automation. The same page has an "Allowed extensions" list and "Require Extension Signature Verification". The team default is 0, meaning off. I'd set it to 72. An 11-hour exposure window means even a one-day delay would have skipped this entirely.&lt;/p&gt;

&lt;p&gt;To pin a known-good version explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cursor &lt;span class="nt"&gt;--install-extension&lt;/span&gt; anthropic.claude-code@2.1.314
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, you'll lag a few days behind on features, and that's fine with me.&lt;/p&gt;

&lt;p&gt;So, do you let your editor auto-update extensions, or did this just change your mind? And who do you think owns this one, Cursor for running the marketplace or Anthropic for the name on the box? Tell me in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://phorion.io/blog/offical-claude-code-vsx-compromise/" rel="noopener noreferrer"&gt;Phorion: Backdoor in Claude Code for VS Code on the Cursor Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cursor.com/blog/claude-code-extension-security-notice" rel="noopener noreferrer"&gt;Cursor security notice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.microsoft.com/en-us/security/blog/2026/10/30/inside-malicious-claude-code-branded-cursor-extension-persistent-ssh-backdoor/" rel="noopener noreferrer"&gt;Microsoft Security: Inside a malicious Claude Code-branded extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.stepsecurity.io/blog/claude-code-extension-trojanized" rel="noopener noreferrer"&gt;StepSecurity: Trojanized Claude Code extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cursor.com/help/customization/extensions" rel="noopener noreferrer"&gt;Cursor docs: Extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=50300683" rel="noopener noreferrer"&gt;Hacker News discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cyberplace.social/@GossiTheDog/117528831681803563" rel="noopener noreferrer"&gt;Kevin Beaumont on Mastodon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>vscode</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Gemini 4 Carbon vs Claude Opus 5.5: #1 Overall, but Opus Still Wins at Coding</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Fri, 30 Oct 2026 21:24:18 +0000</pubDate>
      <link>https://dev.to/alanwest/gemini-4-carbon-vs-claude-opus-55-1-overall-but-opus-still-wins-at-coding-3o2i</link>
      <guid>https://dev.to/alanwest/gemini-4-carbon-vs-claude-opus-55-1-overall-but-opus-still-wins-at-coding-3o2i</guid>
      <description>&lt;p&gt;Gemini 4 Carbon is the new #1 on the Artificial Analysis Intelligence Index v5 with 59 points. Claude Opus 5.5 has 58. On coding, which is what most of us actually pay these models for, Opus still wins: 62 to 59 on the Coding Agent Index and 56% to 51% on FrontierCode. And you can't call Carbon on the public API yet.&lt;/p&gt;

&lt;p&gt;The headline is true. It also tells you almost nothing if you're picking a model for your editor or your agent loop. I went through the published numbers for Gemini 4 Carbon vs Claude Opus 5.5 vs GPT-6.1 (per-benchmark scores, price per million tokens, cost per task, speed, context window) to see where each one wins. I didn't run anything myself. Every number below comes from &lt;a href="https://artificialanalysis.ai/articles/gemini-4-carbon-new-number-1" rel="noopener noreferrer"&gt;Artificial Analysis&lt;/a&gt; or the vendors' pricing pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gemini 4 Carbon vs Opus 5.5 vs GPT-6.1 Sol: the full scoreboard
&lt;/h2&gt;

&lt;p&gt;First, "GPT-6.1" isn't one model. OpenAI has GPT-6.1 Sol (released September 29) and the cheaper GPT-6.1 Terra. Sol scores higher on the Index (55), so that's what I'm comparing. OpenAI's highest scorer is still the older GPT-6 Astra at 57.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Gemini 4 Carbon (high)&lt;/th&gt;
&lt;th&gt;Claude Opus 5.5 (max)&lt;/th&gt;
&lt;th&gt;GPT-6.1 Sol (max)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Intelligence Index v5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;59&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coding Agent Index&lt;/td&gt;
&lt;td&gt;59 (Antigravity CLI)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;62&lt;/strong&gt; (Claude Code)&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FrontierCode v1.1&lt;/td&gt;
&lt;td&gt;51%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;56%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-Omniscience v1.1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;54&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hallucination rate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price in/out per 1M tokens&lt;/td&gt;
&lt;td&gt;$4 / $20&lt;/td&gt;
&lt;td&gt;$4 / $20&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$2 / $10&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per Index task&lt;/td&gt;
&lt;td&gt;$7.76&lt;/td&gt;
&lt;td&gt;$10.04&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$1.27&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output speed&lt;/td&gt;
&lt;td&gt;82.5 t/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96.6 t/s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;81.1 t/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;td&gt;1M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can you use it today?&lt;/td&gt;
&lt;td&gt;selected users only&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sources: the &lt;a href="https://artificialanalysis.ai/articles/gemini-4-carbon-new-number-1" rel="noopener noreferrer"&gt;Carbon launch write-up&lt;/a&gt;, the &lt;a href="https://artificialanalysis.ai/articles/artificial-analysis-intelligence-index-v5" rel="noopener noreferrer"&gt;Index v5 announcement&lt;/a&gt;, and the AA model pages for &lt;a href="https://artificialanalysis.ai/models/gemini-4-carbon" rel="noopener noreferrer"&gt;Carbon&lt;/a&gt;, &lt;a href="https://artificialanalysis.ai/models/claude-opus-5-5" rel="noopener noreferrer"&gt;Opus 5.5&lt;/a&gt; and &lt;a href="https://artificialanalysis.ai/models/gpt-6-1-sol" rel="noopener noreferrer"&gt;GPT-6.1 Sol&lt;/a&gt;. The n/a cells are Sol numbers I couldn't find in any of them.&lt;/p&gt;

&lt;p&gt;Look at the list prices first. Carbon and Opus 5.5 are both $4 input and $20 output per million tokens, and both get a 95% cache discount down to $0.20. Calling Carbon "cheaper" only works for two reasons. One is a 50% launch discount that Google hasn't put an end date on. The other is token count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Gemini 4 Carbon wins: fewer hallucinations
&lt;/h2&gt;

&lt;p&gt;On AA-Omniscience v1.1 Carbon scores 54 to Opus 5.5's 48. Its hallucination rate is 11%. Opus 5.5 (max) and GPT-6 Astra (max) both sit at 50%. If you're building something that answers questions from its own knowledge (support bots, research assistants, anything where a confident wrong answer costs you), that gap is far bigger than the one-point gap on the Index.&lt;/p&gt;

&lt;p&gt;One caveat: that 11% is &lt;em&gt;up&lt;/em&gt; from 4% on Gemini 4 Argon. Google traded some caution for accuracy. And the &lt;a href="https://news.ycombinator.com/item?id=50288019" rel="noopener noreferrer"&gt;Hacker News thread&lt;/a&gt; has people saying Argon made things up anyway: invented paragraphs in project summaries, a fake espresso machine. A benchmark hallucination rate and your production hallucination rate aren't the same number.&lt;/p&gt;

&lt;p&gt;Carbon also uses fewer tokens. AA measured 123k output tokens per Index task, against 173k for Opus 5.5 at max effort, which is 29% fewer. That's where the ~23% cost-per-task advantage ($7.76 vs $10.04) comes from. The per-token price is identical, so the saving is all in how much each model writes.&lt;/p&gt;

&lt;p&gt;It's #1 on 4 of the 9 Index evaluations: HLE-Diamond, Terminal-Bench-Science, AA-Omniscience and AutomationBench-AA. Three of those sit in the Science and General categories; AutomationBench-AA is the only Knowledge Work one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding: Opus 5.5 is still ahead
&lt;/h2&gt;

&lt;p&gt;One of the key results in AA's own write-up is literally titled "Behind only Claude Opus 5.5 on coding agents." The details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding Agent Index: Carbon in Antigravity CLI scores 59. Claude Code with Opus 5.5 (max) scores 62.&lt;/li&gt;
&lt;li&gt;FrontierCode v1.1: Carbon 51%, Opus 5.5 56%.&lt;/li&gt;
&lt;li&gt;Terminal-Bench 4.0: Carbon 64%, which AA says is second place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three points on a composite isn't a blowout. But the Coding Agent Index scores the model inside its agent harness, which is closer to how you'll actually use it, and Opus is ahead there. One HN commenter put it bluntly: "Carbon scoring below Opus 5.5 on coding highlights how magnificent Opus 5.5 is as a coding agent."&lt;/p&gt;

&lt;p&gt;So Carbon took the overall #1 by winning science and knowledge, while Opus is ahead on the Coding Agent Index and FrontierCode. In Index v5 the categories are weighted equally: Knowledge Work 25%, Coding 25%, Science 25%, General 25%. Terminal-Bench-Science alone is 15% of the total. If you never ask a model to do lab-style science in a terminal, 15% of that "59" isn't measuring anything you'll use.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPT-6.1 Sol is the one that should worry Google
&lt;/h2&gt;

&lt;p&gt;Everyone's arguing about first and second place, and meanwhile GPT-6.1 Sol scores 55 for $1.27 per Index task. That's about 6x cheaper than Carbon and about 8x cheaper than Opus 5.5 at max effort, for a model 3-4 points behind.&lt;/p&gt;

&lt;p&gt;On CritPt v2 (hard subset), Sol scores 69%. Opus 5.5 scores 61%. On Terminal-Bench-Science, Sol gets 58% and Opus gets 59%, which is close to a tie.&lt;/p&gt;

&lt;p&gt;There's a catch if you work with big contexts. &lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI's pricing page&lt;/a&gt; charges more above 272K input tokens. Sol goes from $2/$10 to $4/$15, and Terra goes from $1/$5 to $2/$7.50. &lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic bills Opus 5.5 at standard rates for the whole 1M window&lt;/a&gt;. A 900k-token request costs the same per token as a 9k one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Long context: the Index stopped measuring it
&lt;/h2&gt;

&lt;p&gt;All three advertise roughly 1M tokens. What bothers me is that Index v5 removed AA-LCR, the long-context reasoning benchmark, along with GDPval-AA and SciCode. So the #1 ranking contains zero direct evidence about how any of these models reasons over 500k tokens of your codebase.&lt;/p&gt;

&lt;p&gt;What you can compare is cost. Opus 5.5 has flat pricing across the full window. Sol charges double for input above 272K. For Carbon, AA lists only the $4/$20 headline, the cache discount and the launch discount, and you can't call it publicly yet anyway.&lt;/p&gt;

&lt;p&gt;Speed matters for long-context work too. AA lists Opus 5.5 at 96.6 tokens/s, Carbon at 82.5 and Sol at 81.1. Time to first token is ugly across the board at these reasoning settings: 103.54s for Carbon, 277.18s for Sol, and 644.22s for Opus 5.5 at max. Nobody is running max effort interactively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which model I'd pick for coding, pipelines and Q&amp;amp;A
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Coding agents, refactors, repo-wide changes: Claude Opus 5.5 in Claude Code. It leads the Coding Agent Index (62 vs 59) and FrontierCode, and you can use it today.&lt;/li&gt;
&lt;li&gt;High-volume pipelines, CI bots, eval loops: GPT-6.1 Sol. 55 points for $1.27 a task. Keep prompts under 272K or the price jumps.&lt;/li&gt;
&lt;li&gt;Factual Q&amp;amp;A, research, anything where hallucinations hurt: Gemini 4 Carbon, once you can actually get access. An 11% vs 50% hallucination rate is the biggest real gap in this whole comparison.&lt;/li&gt;
&lt;li&gt;Long context on a budget: Opus 5.5 for predictable billing up to 1M, but test it on your own data, because the index no longer measures this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before you switch anything, check two settings.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Effort. Opus 5.5 scores 35 at low effort and 58 at max. At low effort it costs $0.98 per task. GPT-6.1 Sol's low-to-max spread is 20 points. The "same model" can be a different product depending on one parameter, so compare at the effort level you actually run.&lt;/li&gt;
&lt;li&gt;Whether you're caching. Opus 5.5 and Carbon both discount cached input by 95%, down to $0.20 per 1M tokens. If your agent re-sends the same repo context every turn and you aren't caching, you're paying for it again on every turn.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  About that #1
&lt;/h2&gt;

&lt;p&gt;The thread's other big argument is about trust. AA now says 60% of the Index comes from private test sets or held-out answers. One camp calls that unverifiable. The other says it's the only defense against benchmaxxing. I'm in the second camp, but private tests also mean you can't check how much the weighting decides the ranking. A one-point lead under a reweighting that happened in the same week as the launch deserves some skepticism.&lt;/p&gt;

&lt;p&gt;My take: Carbon earned the headline by being the most careful model on knowledge questions. It hasn't earned your coding workflow, and you can't even buy it on the API yet.&lt;/p&gt;

&lt;p&gt;Would a #1 ranking get you to switch away from your current model, or does your coding workflow keep you where you are? If you've had early Carbon access, tell me whether that 11% hallucination number matches what you're seeing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/articles/gemini-4-carbon-new-number-1" rel="noopener noreferrer"&gt;Gemini 4 Carbon is the new #1 on the Artificial Analysis Intelligence Index v5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/articles/artificial-analysis-intelligence-index-v5" rel="noopener noreferrer"&gt;Announcing Artificial Analysis Intelligence Index v5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/models/gemini-4-carbon" rel="noopener noreferrer"&gt;AA model page: Gemini 4 Carbon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/models/claude-opus-5-5" rel="noopener noreferrer"&gt;AA model page: Claude Opus 5.5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artificialanalysis.ai/models/gpt-6-1-sol" rel="noopener noreferrer"&gt;AA model page: GPT-6.1 Sol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI API pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=50288019" rel="noopener noreferrer"&gt;Hacker News discussion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
      <category>developertools</category>
    </item>
    <item>
      <title>How to Run LiquidAI d1-Omni-2B Locally (It Hears Audio but Can't Talk Back)</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Fri, 30 Oct 2026 16:40:01 +0000</pubDate>
      <link>https://dev.to/alanwest/how-to-run-liquidai-d1-omni-2b-locally-it-hears-audio-but-cant-talk-back-520h</link>
      <guid>https://dev.to/alanwest/how-to-run-liquidai-d1-omni-2b-locally-it-hears-audio-but-cant-talk-back-520h</guid>
      <description>&lt;p&gt;If you came here hoping to run LiquidAI d1-Omni-2B locally as a small voice assistant, I'll save you the download first: it can't talk back, and it can't write back either. It listens to audio and returns typed answers with probabilities attached, and that's all you get out of it.&lt;/p&gt;

&lt;p&gt;Hugging Face files &lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B" rel="noopener noreferrer"&gt;d1-Omni-2B&lt;/a&gt; under audio-text-to-text, and that label sets the wrong expectations. Liquid calls it a "decision model". You give it a state (text, JSON, an image, a video, or an audio clip) and a set of named questions, and it answers all of them in one forward pass with zero generated tokens. The card says plainly that it "writes no transcript or speech", and the &lt;a href="https://docs.liquid.ai/lfm/models/d1-omni-2b" rel="noopener noreferrer"&gt;docs&lt;/a&gt; say it is not a chat model.&lt;/p&gt;

&lt;p&gt;I think that's a good design, for reasons I'll get to below. But it changes what "running it locally" means, so here's what the 2B adds over the 600M, how much RAM it needs, and what works today in transformers, llama.cpp, Ollama, MLX and ONNX (as of late October 2026). All benchmark and speed numbers below are Liquid's own. I haven't run it myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What d1-Omni-2B actually does
&lt;/h2&gt;

&lt;p&gt;You ask typed questions and get typed answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;noul&lt;/code&gt;: yes/no, returns P(yes)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;choice&lt;/code&gt;: one of several named options, with probabilities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;score&lt;/code&gt;: an ordinal scale of 2 to 10 levels ("Agitated", "Neutral", "Calm")&lt;/li&gt;
&lt;li&gt;in transformers, not yet in llama.cpp: multiple choice, extraction of text/number/date spans, number estimates with intervals, and bounding boxes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That fits call routing ("billing, technical or fraud?"), voicemail triage, sound event detection, or a cheap check at the front of a pipeline before a bigger model gets involved. Questions can even be spoken: the &lt;code&gt;instructions&lt;/code&gt; field takes an audio clip. For text- or image-only work, Liquid's card itself tells you to use &lt;a href="https://huggingface.co/LiquidAI/d1-2B" rel="noopener noreferrer"&gt;d1-2B&lt;/a&gt; instead, which beats the Omni on most rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  d1-Omni-2B vs d1-omni-600M: what 3x the parameters buys you
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://huggingface.co/LiquidAI/d1-omni-600M" rel="noopener noreferrer"&gt;600M&lt;/a&gt; came out with the &lt;a href="https://www.liquid.ai/blog/open-d1" rel="noopener noreferrer"&gt;Open d1 release&lt;/a&gt; on October 7, 2026, billed as Liquid's "first experimental checkpoint". According to &lt;a href="https://www.orcarouter.ai/blog/d1-omni-2b-what-the-repo-shows" rel="noopener noreferrer"&gt;OrcaRouter's repo write-up&lt;/a&gt;, the 2B repo was created on October 24. The 2B sits on a different base model, so treat it as a separate model rather than a bigger 600M:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;d1-omni-600M&lt;/th&gt;
&lt;th&gt;d1-Omni-2B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parameters&lt;/td&gt;
&lt;td&gt;587M&lt;/td&gt;
&lt;td&gt;2.17B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;LFM2.5-Encoder-350M&lt;/td&gt;
&lt;td&gt;LFM3-Omni-2B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;16,384 tokens&lt;/td&gt;
&lt;td&gt;128K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audio input&lt;/td&gt;
&lt;td&gt;one 16 kHz mono clip, up to 30 s&lt;/td&gt;
&lt;td&gt;clips + spoken questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Images + audio in one request&lt;/td&gt;
&lt;td&gt;no (&lt;code&gt;ValueError&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speech languages&lt;/td&gt;
&lt;td&gt;trained on English requests&lt;/td&gt;
&lt;td&gt;12 (the 16 text languages minus Hindi, Thai, Vietnamese, Indonesian)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision Index v0.3&lt;/td&gt;
&lt;td&gt;18.3&lt;/td&gt;
&lt;td&gt;49.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average (public decision + image benchmarks)&lt;/td&gt;
&lt;td&gt;42.8&lt;/td&gt;
&lt;td&gt;67.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Min transformers&lt;/td&gt;
&lt;td&gt;5.15&lt;/td&gt;
&lt;td&gt;5.19&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The jump is large. Liquid says the 2B beats the 600M on every benchmark it reports, and beats d1-3B on the decision board and on 16 of 18 image benchmarks with about 70% of the parameters. VisualWebBench goes from 14.9 to 88.6. The 600M card reports no audio benchmarks at all, so there's no audio comparison to make between the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio scores: written vs. spoken input
&lt;/h2&gt;

&lt;p&gt;The 2B card does publish audio scores, and they're worth a careful look. Each task is scored twice, once with the input written as text and once with the same input read aloud. The gap between the two columns is what the speech path costs you:&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;Written&lt;/th&gt;
&lt;th&gt;Heard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SLURP (assistant commands, real speakers)&lt;/td&gt;
&lt;td&gt;87.4&lt;/td&gt;
&lt;td&gt;81.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speech-MASSIVE (12 languages)&lt;/td&gt;
&lt;td&gt;85.2&lt;/td&gt;
&lt;td&gt;63.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FLEURS (spoken language ID, 43 languages)&lt;/td&gt;
&lt;td&gt;92.4&lt;/td&gt;
&lt;td&gt;92.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC-50 (sound events)&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;84.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spoken short states&lt;/td&gt;
&lt;td&gt;42.0&lt;/td&gt;
&lt;td&gt;22.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Belebele (passages, 8 languages)&lt;/td&gt;
&lt;td&gt;83.6&lt;/td&gt;
&lt;td&gt;41.8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Short English commands and sound classification hold up. Long passages and non-English speech fall apart: Belebele loses half its score once you speak it. The card admits that "long spoken passages lose much of their accuracy, most of all outside Latin-script languages." If you're building multilingual voicemail triage, run your own eval before you trust it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much RAM and VRAM d1-Omni-2B needs
&lt;/h2&gt;

&lt;p&gt;Liquid publishes no memory requirements, so here's the arithmetic plus the file sizes they do publish. At 2 bytes per parameter, 2.17B is about 4.3 GB of weights, which matches the single 4.33 GB BF16 safetensors file. Being a hybrid (13 short-convolution layers, 5 sliding-window, only 6 global attention), it should keep a smaller KV cache than a pure transformer at long context. And since it never decodes, you only pay for the prefill.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Build&lt;/th&gt;
&lt;th&gt;Size on disk&lt;/th&gt;
&lt;th&gt;Where it runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Safetensors BF16&lt;/td&gt;
&lt;td&gt;4.33 GB&lt;/td&gt;
&lt;td&gt;transformers (CUDA, MPS, CPU in fp32)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GGUF BF16 / F16&lt;/td&gt;
&lt;td&gt;3.47 GB&lt;/td&gt;
&lt;td&gt;llama.cpp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GGUF Q8_0&lt;/td&gt;
&lt;td&gt;1.85 GB&lt;/td&gt;
&lt;td&gt;llama.cpp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MLX 8-bit&lt;/td&gt;
&lt;td&gt;2.71 GB&lt;/td&gt;
&lt;td&gt;Apple Silicon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONNX q4&lt;/td&gt;
&lt;td&gt;2.45 GB&lt;/td&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONNX q4f16&lt;/td&gt;
&lt;td&gt;2.20 GB&lt;/td&gt;
&lt;td&gt;GPU / WebGPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONNX fp32&lt;/td&gt;
&lt;td&gt;8.32 GB&lt;/td&gt;
&lt;td&gt;reference&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Watch the CPU path in transformers: the sample code loads in float32 on CPU, so budget for roughly double the BF16 footprint, around 8.7 GB by my math. The GGUF sizes are the language model only; llama.cpp also pulls an mmproj file for audio and images (0.33 GB at Q8_0, 0.61 GB at BF16). On an 8 GB laptop, use the Q8_0 GGUF or ONNX q4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime status: transformers, llama.cpp, Ollama, MLX
&lt;/h2&gt;

&lt;h3&gt;
  
  
  transformers
&lt;/h3&gt;

&lt;p&gt;Full support, including every question type. It needs remote code:&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; &lt;span class="s2"&gt;"transformers&amp;gt;=5.19"&lt;/span&gt; torch torchvision pillow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;torch&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModel&lt;/span&gt;

&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;dtype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bfloat16&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LiquidAI/d1-Omni-2B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call &lt;code&gt;model.system_one(state, questions, media=...)&lt;/code&gt;. WAV files need to be 16-bit PCM and get resampled to 16 kHz.&lt;/p&gt;

&lt;h3&gt;
  
  
  llama.cpp
&lt;/h3&gt;

&lt;p&gt;It works from build b11960 (v0.8.0) using the &lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-GGUF" rel="noopener noreferrer"&gt;official GGUF&lt;/a&gt;, but only for &lt;code&gt;noul&lt;/code&gt;, &lt;code&gt;choice&lt;/code&gt; and &lt;code&gt;score&lt;/code&gt;. Extraction, estimates, boxes and multi-select aren't supported there yet. On a laptop, this is what I'd run:&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;-hf&lt;/span&gt; LiquidAI/d1-Omni-2B-GGUF:Q8_0 &lt;span class="nt"&gt;-b&lt;/span&gt; 8192 &lt;span class="nt"&gt;-ub&lt;/span&gt; 8192
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't drop the batch flags. Each question's full state and media has to fit in a single batch. An image can use at most half of &lt;code&gt;-ub&lt;/code&gt;, so 8192 gives it the full 4096-token budget. Then POST audio to the custom endpoint (this is the card's audio example):&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;-sL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; jfk.wav https://github.com/ggml-org/whisper.cpp/raw/master/samples/jfk.wav

curl http://127.0.0.1:8080/v1/systemone &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; @- &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="sh"&gt;
{
  "state": "Recording from a public event.",
  "files": ["data:audio/wav;base64,&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;base64&lt;/span&gt; &amp;lt; jfk.wav | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"],
  "questions": {
    "kind": {"type": "choice", "instructions": "What kind of utterance is this?",
             "criteria": {"request": "A request to do something",
                          "question": "A question asking for information",
                          "speech": "A speech to an audience"}},
    "calm": {"type": "score", "instructions": "How calm is the speaker?",
             "criteria": ["Agitated", "Neutral", "Calm"]}
  }
}
&lt;/span&gt;&lt;span class="no"&gt;JSON
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spoken questions work here too: put an &lt;code&gt;input_audio&lt;/code&gt; part in a question's &lt;code&gt;instructions&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ollama
&lt;/h3&gt;

&lt;p&gt;There's an official &lt;a href="https://ollama.com/library/d1-omni" rel="noopener noreferrer"&gt;&lt;code&gt;d1-omni&lt;/code&gt; library entry&lt;/a&gt; with a &lt;code&gt;2b&lt;/code&gt; tag at 4.4 GB. That's roughly the BF16 checkpoint, so don't expect a small quant. It serves the same &lt;code&gt;/v1/systemone&lt;/code&gt; endpoint on port 11434, and the CLI gets an &lt;code&gt;--ask&lt;/code&gt; flag. The page's own example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:11434/v1/systemone &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&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;'{
    "model": "d1-omni:2b",
    "state": "Hello World",
    "questions": {
      "says_hello": {
        "type": "noul",
        "instructions": "Does the state text contain a greeting?",
        "criteria": {
          "true": "The state text contains a greeting.",
          "false": "The state text does not contain a greeting."
        }
      }
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a catch. When I checked, the readme on that page still described the 600M (587M parameters, English speech only, 30-second clips, no audio and images together), and Liquid's d1-Omni-2B docs page only covers transformers and llama.cpp. Compare the 2B tag against transformers on a few of your own clips before you rely on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  MLX
&lt;/h3&gt;

&lt;p&gt;Official builds exist (&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-MLX-fp16" rel="noopener noreferrer"&gt;fp16&lt;/a&gt;, &lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-MLX-8bit" rel="noopener noreferrer"&gt;8-bit&lt;/a&gt;) and run through &lt;code&gt;mlx_vlm&lt;/code&gt;, but the card itself says "Support for d1 in MLX-VLM is in progress". The examples may need an mlx-vlm release that doesn't exist yet. On a Mac I'd stick with transformers on MPS for now.&lt;/p&gt;

&lt;h3&gt;
  
  
  ONNX
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-ONNX" rel="noopener noreferrer"&gt;ONNX repo&lt;/a&gt; is the one I'd keep an eye on. It has CPU q4/q8 bundles and a WebGPU path via &lt;code&gt;onnxruntime-web/webgpu&lt;/code&gt;, so routing audio in the browser looks doable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed: fast on GPUs, and no CPU numbers yet
&lt;/h2&gt;

&lt;p&gt;Liquid's bf16 numbers after &lt;code&gt;model.compile()&lt;/code&gt;, for a 10-second audio clip: 12.4 ms on an H100 PCIe, 8.2 ms on an MI325X, 33.3 ms on an Apple M5 Pro. A single question on the M5 Pro takes 21.1 ms. Nothing gets decoded, which is why the numbers are that low.&lt;/p&gt;

&lt;p&gt;Liquid doesn't publish any CPU or Raspberry Pi number for this model. I'd ignore any headline that says it "runs on CPU" until someone posts timings. It will run, since the ONNX CPU builds exist, but nobody has said how fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  License: free until you hit $10M revenue
&lt;/h2&gt;

&lt;p&gt;The weights ship under the &lt;a href="https://docs.liquid.ai/lfm/help/model-license.md" rel="noopener noreferrer"&gt;LFM Open License v1.0&lt;/a&gt;. Commercial use is free under $10 million USD annual revenue, counted across your whole corporate group. Above that, you need a separate license. The threshold also applies to your downstream customers, and violating any term terminates the license immediately. That's fine for hobby projects and startups. If you ship it in an enterprise product, talk to a lawyer before it goes out. The Open d1 blog's "without restrictions" line is more generous than the actual license text.&lt;/p&gt;

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

&lt;p&gt;Skipping generation is the right call for this job. When I'm routing a call I want &lt;code&gt;{"team": "billing", "confidence": 0.94}&lt;/code&gt; back in 20 ms, with a probability I can put a threshold on; a 300-token explanation is just latency. The 600M was a research preview. The 2B is the first d1-Omni I'd consider putting in a real pipeline, as long as the audio is short, mostly English, and you've calibrated thresholds on your own recordings, which the card also tells you to do.&lt;/p&gt;

&lt;p&gt;Is 2B the sweet spot for an on-device voice model, or would you rather run the 600M on a Pi and accept the accuracy hit? And if you've run &lt;code&gt;d1-omni:2b&lt;/code&gt; in Ollama, do its probabilities match what transformers gives you for the same clip? Tell me in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B" rel="noopener noreferrer"&gt;LiquidAI/d1-Omni-2B model card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-GGUF" rel="noopener noreferrer"&gt;LiquidAI/d1-Omni-2B-GGUF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-MLX-8bit" rel="noopener noreferrer"&gt;LiquidAI/d1-Omni-2B-MLX-8bit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-Omni-2B-ONNX" rel="noopener noreferrer"&gt;LiquidAI/d1-Omni-2B-ONNX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/LiquidAI/d1-omni-600M" rel="noopener noreferrer"&gt;LiquidAI/d1-omni-600M model card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.liquid.ai/lfm/models/d1-omni-2b" rel="noopener noreferrer"&gt;Liquid docs: d1-omni-2B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.liquid.ai/blog/open-d1" rel="noopener noreferrer"&gt;Liquid AI blog: Open d1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ollama.com/library/d1-omni" rel="noopener noreferrer"&gt;Ollama library: d1-omni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.liquid.ai/lfm/help/model-license.md" rel="noopener noreferrer"&gt;LFM Open License v1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.orcarouter.ai/blog/d1-omni-2b-what-the-repo-shows" rel="noopener noreferrer"&gt;OrcaRouter: d1-Omni-2B, what the repo shows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>opensource</category>
      <category>llm</category>
    </item>
    <item>
      <title>Cursor Agent SDK vs Claude Agent SDK: Every Model Is Billed Through Cursor</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Fri, 30 Oct 2026 15:10:02 +0000</pubDate>
      <link>https://dev.to/alanwest/cursor-agent-sdk-vs-claude-agent-sdk-every-model-is-billed-through-cursor-gal</link>
      <guid>https://dev.to/alanwest/cursor-agent-sdk-vs-claude-agent-sdk-every-model-is-billed-through-cursor-gal</guid>
      <description>&lt;p&gt;The npm package for Cursor's new Agent SDK isn't &lt;code&gt;@cursor/anything&lt;/code&gt;. According to &lt;a href="https://cursor.com/docs/agent-sdk" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;, you install it with:&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; &lt;span class="nt"&gt;--global&lt;/span&gt; @grok/agent-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That package name breaks the usual framing of the Cursor Agent SDK vs Claude Agent SDK question, which goes "editor company with a model-agnostic harness vs model company pushing its own model." SpaceX closed its &lt;a href="https://ca.finance.yahoo.com/news/spacexs-60-billion-acquisition-cursor-142939211.html" rel="noopener noreferrer"&gt;$60B acquisition of Cursor&lt;/a&gt; on August 14 and folded it into SpaceXAI, and Cursor's own &lt;a href="https://cursor.com/docs/models-and-pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; now lists Grok 4.x as a "Cursor model". So both of these SDKs come from a company that trains models. And whichever model you pick in Cursor's SDK, Claude and GPT included, the inference runs through Cursor and so does the bill.&lt;/p&gt;

&lt;p&gt;I went through the docs, changelogs and the &lt;a href="https://news.ycombinator.com/item?id=50273731" rel="noopener noreferrer"&gt;HN thread&lt;/a&gt; (141 points, 132 comments) for Cursor's Agent SDK, Anthropic's Claude Agent SDK and OpenAI's Agents SDK. I haven't run any of them, so everything below is what the vendors published, with links.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Cursor actually shipped
&lt;/h2&gt;

&lt;p&gt;Cursor &lt;a href="https://cursor.com/blog/agent-sdk" rel="noopener noreferrer"&gt;announced the Agent SDK&lt;/a&gt; on October 20. The &lt;a href="https://cursor.com/docs/agent-sdk/changelog" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; marks 0.3.0 (2026-10-23) as the GA release. It's the framework Cursor uses internally for Bugbot, Security Reviewer and Rollouts.&lt;/p&gt;

&lt;p&gt;An agent is a folder of Markdown and TypeScript. Prompts live in &lt;code&gt;.md&lt;/code&gt; (or &lt;code&gt;.ts&lt;/code&gt;) files, you write the tools, and Cursor's harness runs the model loop. The CLI needs Node 22.13 or newer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agent-sdk login
agent-sdk init ./my-bot
agent-sdk dev        &lt;span class="c"&gt;# local playground&lt;/span&gt;
agent-sdk validate &lt;span class="nt"&gt;--dir&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
agent-sdk deploy     &lt;span class="c"&gt;# Cursor-managed hosting&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI also covers evals, logs, deployment secrets, Slack setup and webhook replay for GitHub, GitLab, Bitbucket and PagerDuty. Subagents are defined in the project itself. If you don't want Cursor hosting it, the docs say you can run it on your own infrastructure. One team at Cursor built its internal &lt;code&gt;kb-reviewer&lt;/code&gt; PR bot "in about a day."&lt;/p&gt;

&lt;p&gt;There's some naming mess. The announcement's code sample imports &lt;code&gt;defineAgent&lt;/code&gt; from &lt;code&gt;@cursor/agent-sdk&lt;/code&gt;. The docs install &lt;code&gt;@grok/agent-sdk&lt;/code&gt; and note it used to be &lt;code&gt;@cursor/bdk&lt;/code&gt;. On top of that there's a separate, older &lt;code&gt;@cursor/sdk&lt;/code&gt; (&lt;a href="https://cursor.com/blog/typescript-sdk" rel="noopener noreferrer"&gt;April 2026&lt;/a&gt;) for calling Cursor's agent from your own code, and the Agent SDK docs say it runs on that same Cursor SDK harness. Pin your versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor Agent SDK vs Claude Agent SDK vs OpenAI Agents SDK: the table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Cursor Agent SDK&lt;/th&gt;
&lt;th&gt;Claude Agent SDK&lt;/th&gt;
&lt;th&gt;OpenAI Agents SDK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm i -g @grok/agent-sdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm install @anthropic-ai/claude-agent-sdk&lt;/code&gt; / &lt;code&gt;pip install claude-agent-sdk&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pip install openai-agents&lt;/code&gt; / &lt;code&gt;npm install @openai/agents zod&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Languages&lt;/td&gt;
&lt;td&gt;TypeScript (+ Markdown prompts)&lt;/td&gt;
&lt;td&gt;TypeScript, Python&lt;/td&gt;
&lt;td&gt;Python, TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime minimum&lt;/td&gt;
&lt;td&gt;Node 22.13&lt;/td&gt;
&lt;td&gt;Node 18.14 / Python 3.10&lt;/td&gt;
&lt;td&gt;Python 3.10 / Node 22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Models&lt;/td&gt;
&lt;td&gt;Cursor's catalog: Composer 2.5, Grok 4.x, Claude, GPT, Gemini, DeepSeek, GLM, Kimi&lt;/td&gt;
&lt;td&gt;Claude only&lt;/td&gt;
&lt;td&gt;OpenAI by default; others via Chat Completions, LiteLLM (beta), Any-LLM (beta)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where inference goes&lt;/td&gt;
&lt;td&gt;Through Cursor&lt;/td&gt;
&lt;td&gt;Anthropic API, Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, Claude Platform on AWS&lt;/td&gt;
&lt;td&gt;Wherever you point it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in coding tools&lt;/td&gt;
&lt;td&gt;Cursor's harness&lt;/td&gt;
&lt;td&gt;Read/Edit/Bash/Glob/Grep/WebSearch etc.&lt;/td&gt;
&lt;td&gt;You bring them (plus sandbox agents)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Cursor-managed or self-hosted&lt;/td&gt;
&lt;td&gt;Self-host; Managed Agents if you want Anthropic to run it&lt;/td&gt;
&lt;td&gt;Self-host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandboxing&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;local.sandbox&lt;/code&gt;, off by default&lt;/td&gt;
&lt;td&gt;Permissions + hooks; container isolation is on you&lt;/td&gt;
&lt;td&gt;Sandbox agents: Unix-local, Docker, hosted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pricing&lt;/td&gt;
&lt;td&gt;Token-based, same pools as the IDE&lt;/td&gt;
&lt;td&gt;API token pricing&lt;/td&gt;
&lt;td&gt;Whatever your model provider charges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Proprietary (Cursor Terms of Service)&lt;/td&gt;
&lt;td&gt;Anthropic Commercial Terms; bundles the closed Claude Code binary&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every row is sourced in the list at the end. A few of them need more room than a table cell.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Model-agnostic" here means agnostic within Cursor
&lt;/h2&gt;

&lt;p&gt;Model choice is Cursor's main selling point. On the &lt;a href="https://cursor.com/docs/api/sdk/typescript" rel="noopener noreferrer"&gt;Cursor TypeScript SDK&lt;/a&gt; the docs say it plainly: "All inference goes through Cursor's hosted models in both modes." You can switch from &lt;code&gt;composer-2.5&lt;/code&gt; to a Claude or GPT model by changing one field, but the bill always comes from Cursor.&lt;/p&gt;

&lt;p&gt;Under the &lt;a href="https://cursor.com/docs/models-and-pricing" rel="noopener noreferrer"&gt;current plans&lt;/a&gt;, third-party models are billed at API list price on Premium ($30/mo) and up. On Teams and Enterprise there's also a Cursor Token Rate of $0.25 per million tokens on eligible third-party models. SDK runs "follow the same pricing, request pools, and Privacy Mode rules as runs from the IDE." The Agent SDK docs don't list a separate price for hosted deployments, so you can't budget hosted agents from the docs alone yet.&lt;/p&gt;

&lt;p&gt;So you can swap models all day, but leaving Cursor means a rewrite. The lock-in is the Cursor account, and picking a different model in the config does nothing about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Agent SDK: one model family, five ways to pay
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://code.claude.com/docs/en/agent-sdk/overview" rel="noopener noreferrer"&gt;Claude Agent SDK&lt;/a&gt; gives you "the same tools, agent loop, and context management that power Claude Code" in Python and TypeScript. Under the hood it &lt;a href="https://code.claude.com/docs/en/agent-sdk/hosting" rel="noopener noreferrer"&gt;spawns a &lt;code&gt;claude&lt;/code&gt; CLI subprocess&lt;/a&gt; per session. It runs Claude models only, but you can pay for them through Anthropic's API, Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform or Microsoft Foundry:&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;CLAUDE_CODE_USE_BEDROCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1   &lt;span class="c"&gt;# or CLAUDE_CODE_USE_VERTEX=1, CLAUDE_CODE_USE_FOUNDRY=1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you depend on one model family but not on one vendor account. For a company that already has an AWS or Azure commit, that's a lot easier to get through procurement than another SaaS bill.&lt;/p&gt;

&lt;p&gt;The hosting docs are refreshingly concrete. Start at 1 GiB RAM, 5 GiB disk and 1 CPU per agent. A minimal container costs "roughly $0.05 per hour," and token cost "typically dominates container infrastructure cost by an order of magnitude or more."&lt;/p&gt;

&lt;p&gt;The part people argue about is subscriptions. The docs say: "Unless previously approved, Anthropic does not allow third party developers to offer claude.ai login or rate limits for their products." Plan on API billing. A long stretch of the HN thread was people disagreeing about whether &lt;code&gt;claude -p&lt;/code&gt; and the SDK draw from Max limits, which tells you how unclear that line is in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does Claude work better in Claude's own harness?
&lt;/h2&gt;

&lt;p&gt;This was the best exchange on HN. One commenter argued "there's reason to believe that Claude itself works better with Claude Code than with other harnesses," and another replied that labs generally tune models alongside a specific harness. If that's true, a model-agnostic harness is always running someone else's model a bit off-tune.&lt;/p&gt;

&lt;p&gt;I think it's true in part. Cursor's argument works the same way, just for Composer and Grok: those are the models its harness is tuned for. With Claude in Cursor's harness, you get Cursor's tool definitions and prompts, not Anthropic's. Neither vendor publishes a cross-harness benchmark, so take any "better" claim as marketing until one shows up.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI's SDK is the only one with nothing closed underneath
&lt;/h2&gt;

&lt;p&gt;The OpenAI Agents SDK is &lt;a href="https://github.com/openai/openai-agents-js" rel="noopener noreferrer"&gt;MIT-licensed&lt;/a&gt; and the most provider-agnostic of the three. The caveats are in &lt;a href="https://openai.github.io/openai-agents-python/models/" rel="noopener noreferrer"&gt;its own docs&lt;/a&gt;. LiteLLM support is "best-effort, beta." Some providers "don't have support for structured outputs." Tracing uploads fail with a 401 if you don't have an OpenAI key. It also ships a much thinner coding harness. You get &lt;a href="https://openai.github.io/openai-agents-python/sandbox_agents/" rel="noopener noreferrer"&gt;sandbox agents&lt;/a&gt; with Unix-local and Docker clients, but not a ready-made Claude Code or Cursor agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd pick
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For a PR bot or code reviewer you want shipped this week, I'd pick the Cursor Agent SDK. &lt;code&gt;agent-sdk deploy&lt;/code&gt;, PR triggers and evals out of the box beat wiring all that up yourself. Accept that you're a Cursor customer for as long as it runs.&lt;/li&gt;
&lt;li&gt;For an agent inside your own product, especially a multi-tenant one, I'd pick the Claude Agent SDK. It has the best-documented production story of the three, and your inference bill can sit with your cloud provider.&lt;/li&gt;
&lt;li&gt;If exit cost is what you care about most, go with the OpenAI Agents SDK and write the coding tools yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A checklist for whichever you pick
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Put your tools behind MCP servers. All three SDKs speak MCP, so your tools are the part you can move to another SDK. Prompts in Markdown move easily too. Harness-specific hooks don't.&lt;/li&gt;
&lt;li&gt;Running Cursor agents locally? Set &lt;code&gt;local.sandbox&lt;/code&gt; in &lt;code&gt;defineAgent&lt;/code&gt;. It's off by default, which means shell commands auto-approve and inherit the host's credentials. With it on, shell commands run without network access and writes outside the session workspace are refused.&lt;/li&gt;
&lt;li&gt;Running the Claude SDK for multiple tenants? Pass &lt;code&gt;settingSources: []&lt;/code&gt;, set &lt;code&gt;CLAUDE_CODE_DISABLE_AUTO_MEMORY=1&lt;/code&gt;, and give each tenant its own &lt;code&gt;cwd&lt;/code&gt; and &lt;code&gt;CLAUDE_CONFIG_DIR&lt;/code&gt;. Otherwise one tenant's &lt;code&gt;CLAUDE.md&lt;/code&gt; can leak into another's session.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;maxTurns&lt;/code&gt;. Claude's docs say outright that there's no top-level session timeout.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So: would you build your agent on an editor company's SDK or a model company's, now that Cursor is technically both? I think the harness matters less than whose invoice it's on, and I'd like to hear from anyone who has shipped on one of these and disagrees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cursor: &lt;a href="https://cursor.com/blog/agent-sdk" rel="noopener noreferrer"&gt;Agent SDK announcement&lt;/a&gt;, &lt;a href="https://cursor.com/docs/agent-sdk" rel="noopener noreferrer"&gt;Agent SDK docs&lt;/a&gt;, &lt;a href="https://cursor.com/docs/agent-sdk/reference/cli" rel="noopener noreferrer"&gt;CLI reference&lt;/a&gt;, &lt;a href="https://cursor.com/docs/agent-sdk/changelog" rel="noopener noreferrer"&gt;changelog&lt;/a&gt;, &lt;a href="https://cursor.com/docs/api/sdk/typescript" rel="noopener noreferrer"&gt;TypeScript SDK docs&lt;/a&gt;, &lt;a href="https://cursor.com/blog/typescript-sdk" rel="noopener noreferrer"&gt;Cursor SDK post&lt;/a&gt;, &lt;a href="https://cursor.com/docs/models-and-pricing" rel="noopener noreferrer"&gt;models and pricing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Anthropic: &lt;a href="https://code.claude.com/docs/en/agent-sdk/overview" rel="noopener noreferrer"&gt;Agent SDK overview&lt;/a&gt;, &lt;a href="https://code.claude.com/docs/en/agent-sdk/quickstart" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt;, &lt;a href="https://code.claude.com/docs/en/agent-sdk/hosting" rel="noopener noreferrer"&gt;hosting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenAI: &lt;a href="https://openai.github.io/openai-agents-python/" rel="noopener noreferrer"&gt;Agents SDK (Python)&lt;/a&gt;, &lt;a href="https://openai.github.io/openai-agents-python/models/" rel="noopener noreferrer"&gt;models&lt;/a&gt;, &lt;a href="https://openai.github.io/openai-agents-python/sandbox_agents/" rel="noopener noreferrer"&gt;sandbox agents&lt;/a&gt;, &lt;a href="https://github.com/openai/openai-agents-js" rel="noopener noreferrer"&gt;openai-agents-js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Discussion: &lt;a href="https://news.ycombinator.com/item?id=50273731" rel="noopener noreferrer"&gt;Hacker News thread&lt;/a&gt;; acquisition: &lt;a href="https://thenextweb.com/news/spacex-cursor-acquisition-official-60-billion" rel="noopener noreferrer"&gt;The Next Web (deal terms)&lt;/a&gt;, &lt;a href="https://ca.finance.yahoo.com/news/spacexs-60-billion-acquisition-cursor-142939211.html" rel="noopener noreferrer"&gt;Yahoo Finance (close)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>aiagents</category>
      <category>typescript</category>
      <category>developertools</category>
    </item>
    <item>
      <title>How to Run Tencent WeVisOne-VL-4B Locally on 8 GB VRAM (Ollama Drops the Masks)</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Thu, 29 Oct 2026 19:00:03 +0000</pubDate>
      <link>https://dev.to/alanwest/how-to-run-tencent-wevisone-vl-4b-locally-on-8-gb-vram-ollama-drops-the-masks-1eik</link>
      <guid>https://dev.to/alanwest/how-to-run-tencent-wevisone-vl-4b-locally-on-8-gb-vram-ollama-drops-the-masks-1eik</guid>
      <description>&lt;p&gt;Tencent's WeVisOne-VL-4B picked up 5,986 Hugging Face downloads last month, and I suspect a lot of those people expected another small chat-about-your-image model. It's a perception model instead: boxes, points, counts, text locations, segmentation masks and alpha mattes, all from one 4B checkpoint built on Qwen3-VL. You can run WeVisOne-VL-4B locally on an 8 GB GPU with a Q4_K_M GGUF in llama.cpp, and the Hub offers a one-line Ollama pull too. You just lose the masks when you do.&lt;/p&gt;

&lt;p&gt;I went through the model card, the GitHub README, the config and the GGUF repos. This post covers what the model is, Tencent's numbers against Qwen3-VL-8B (and the baseline they left out), VRAM per format, and the two ways to run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What WeVisOne-VL-4B actually is
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://huggingface.co/tencent/WeVisOne-VL-4B" rel="noopener noreferrer"&gt;model card&lt;/a&gt; says it comes from WeChat Vision at Tencent and is built on Qwen3-VL. The &lt;a href="https://huggingface.co/tencent/WeVisOne-VL-4B/blob/main/config.json" rel="noopener noreferrer"&gt;config.json&lt;/a&gt; confirms it: &lt;code&gt;Qwen3VLForConditionalGeneration&lt;/code&gt;, 36 text layers, hidden size 2560, a 24-layer ViT with patch size 16. That's the Qwen3-VL-4B layout with a 152,680-token vocabulary.&lt;/p&gt;

&lt;p&gt;The extra tokens are the trick. Coordinates are emitted as &lt;code&gt;&amp;lt;0&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;1000&amp;gt;&lt;/code&gt; (normalized boxes and points), and every predicted box in dense tasks is followed by an &lt;code&gt;&amp;lt;OBJ&amp;gt;&lt;/code&gt; token (ID 152678). A separate 9.6M-parameter pixel decoder, shipped as &lt;code&gt;mask_decoder.pt&lt;/code&gt;, reads those &lt;code&gt;&amp;lt;OBJ&amp;gt;&lt;/code&gt; positions plus multi-level ViT features and produces masks and stride-1 alpha mattes, so there's no SAM in the loop.&lt;/p&gt;

&lt;p&gt;The task list from the &lt;a href="https://github.com/Tencent/WeVisOne-VL" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;: &lt;code&gt;detection&lt;/code&gt;, &lt;code&gt;referring&lt;/code&gt;, &lt;code&gt;point&lt;/code&gt;, &lt;code&gt;count_box&lt;/code&gt; / &lt;code&gt;count_point&lt;/code&gt;, &lt;code&gt;ocr&lt;/code&gt; / &lt;code&gt;ocr_grounding&lt;/code&gt;, &lt;code&gt;segmentation&lt;/code&gt;, &lt;code&gt;matting&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Other facts worth knowing before you download:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;License: Apache-2.0 for Tencent-authored code; third-party components keep their own licenses.&lt;/li&gt;
&lt;li&gt;Context: &lt;code&gt;max_position_embeddings&lt;/code&gt; is 262144, same as the Qwen3-VL base. Tencent's evals cap images at 1,960 visual tokens, so context isn't the constraint here.&lt;/li&gt;
&lt;li&gt;Single-turn, single image. The pixel decoder rejects video grids, and the model returns structured output without chain-of-thought.&lt;/li&gt;
&lt;li&gt;It answers &lt;code&gt;None&lt;/code&gt; when the thing you asked for isn't in the image, which matters more than it sounds (see the benchmarks).&lt;/li&gt;
&lt;li&gt;There's also a 2B sibling. Paper is &lt;a href="https://arxiv.org/abs/2610.31329" rel="noopener noreferrer"&gt;arXiv:2610.31329&lt;/a&gt;, submitted 22 Oct 2026.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WeVisOne-VL-4B vs Qwen3-VL benchmarks, and who's missing
&lt;/h2&gt;

&lt;p&gt;All numbers below are from the GitHub README. Tencent compares against Qwen3-VL-8B, Qwen3.5-9B, Rex-Omni-3B, LocateAnything-3B and a few specialists.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task (metric)&lt;/th&gt;
&lt;th&gt;Qwen3-VL-8B&lt;/th&gt;
&lt;th&gt;Qwen3.5-9B&lt;/th&gt;
&lt;th&gt;Rex-Omni-3B&lt;/th&gt;
&lt;th&gt;LocateAnything-3B&lt;/th&gt;
&lt;th&gt;WeVisOne-VL-4B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LVIS detection (F1)&lt;/td&gt;
&lt;td&gt;42.9&lt;/td&gt;
&lt;td&gt;43.7&lt;/td&gt;
&lt;td&gt;46.9&lt;/td&gt;
&lt;td&gt;50.7&lt;/td&gt;
&lt;td&gt;55.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dense200 detection (F1)&lt;/td&gt;
&lt;td&gt;13.8&lt;/td&gt;
&lt;td&gt;18.0&lt;/td&gt;
&lt;td&gt;58.3&lt;/td&gt;
&lt;td&gt;58.7&lt;/td&gt;
&lt;td&gt;71.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RefCOCOg test (F1)&lt;/td&gt;
&lt;td&gt;74.9&lt;/td&gt;
&lt;td&gt;74.6&lt;/td&gt;
&lt;td&gt;74.3&lt;/td&gt;
&lt;td&gt;77.6&lt;/td&gt;
&lt;td&gt;81.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WeRef rejection rate&lt;/td&gt;
&lt;td&gt;18.3&lt;/td&gt;
&lt;td&gt;70.7&lt;/td&gt;
&lt;td&gt;43.3&lt;/td&gt;
&lt;td&gt;73.0&lt;/td&gt;
&lt;td&gt;96.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PixMo-Count acc&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;80.4&lt;/td&gt;
&lt;td&gt;71.9&lt;/td&gt;
&lt;td&gt;82.8&lt;/td&gt;
&lt;td&gt;89.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TotalText OCR (F1)&lt;/td&gt;
&lt;td&gt;35.4&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;40.6&lt;/td&gt;
&lt;td&gt;43.3&lt;/td&gt;
&lt;td&gt;52.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SROIE OCR (F1)&lt;/td&gt;
&lt;td&gt;43.3&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;44.8&lt;/td&gt;
&lt;td&gt;40.3&lt;/td&gt;
&lt;td&gt;68.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On matting (MAD ×10³, lower is better), WeVisOne-VL-4B scores 9.8 on Tencent's WeRefMat referring benchmark against 22.4 for a Qwen3.5-9B + SAM2-Matting pipeline. On ReasonSeg val it gets 71.2 gIoU vs 65.0 for a fine-tuned LISA-13B.&lt;/p&gt;

&lt;p&gt;The rejection numbers are the ones I care about. Qwen3-VL-8B on the WeRef set rejects absent targets 18.3% of the time, which means it draws a box around something that isn't there most of the time. At 96.4% you can put the detector in a pipeline; at 18.3% you end up babysitting it. One caveat: WeRef-Bench and WeRefMat are Tencent's own benchmarks.&lt;/p&gt;

&lt;p&gt;The 2B sibling is closer than you'd expect: 53.3 on LVIS, 92.9% WeRef rejection, 88.1 on PixMo-Count. If the 4B doesn't fit your card at bf16, the 2B through the official package is the one to try before you give up on masks.&lt;/p&gt;

&lt;p&gt;I do have complaints about the comparison. Qwen3-VL-4B isn't in the tables. This model is a 4B built on Qwen3-VL, and Tencent compares it with the 8B. I'd like to know how much of the gain comes from the fine-tuning and how much from the base, and the one baseline that would tell us is missing.&lt;/p&gt;

&lt;p&gt;There's no Gemma and no general VLM benchmark either: no DocVQA, no OCRBench, no MMMU, no chart QA. That fits what the model is for, but it leaves the "vs Qwen VL and Gemma" question unanswered for general image chat, and nobody has published those numbers yet.&lt;/p&gt;

&lt;p&gt;People are already questioning the baseline selection. &lt;a href="https://huggingface.co/tencent/WeVisOne-VL-4B/discussions/3" rel="noopener noreferrer"&gt;Discussion #3&lt;/a&gt; on the model page asks how the baselines were selected, pointing out that the GroundingPI paper reports additional baselines and higher scores on some overlapping benchmarks, and how the model compares with frontier proprietary models. No reply at the time of writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much VRAM it needs: bf16 vs Q8_0 vs Q4_K_M
&lt;/h2&gt;

&lt;p&gt;Tencent publishes no VRAM figures. The table below is estimated from file sizes. These are weight sizes only; activations and KV cache come on top.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Weights&lt;/th&gt;
&lt;th&gt;Vision projector&lt;/th&gt;
&lt;th&gt;Total on disk&lt;/th&gt;
&lt;th&gt;8 GB card?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;f16 GGUF&lt;/td&gt;
&lt;td&gt;8.84 GB&lt;/td&gt;
&lt;td&gt;0.84 GB (f16 mmproj)&lt;/td&gt;
&lt;td&gt;~9.7 GB&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q8_0 GGUF&lt;/td&gt;
&lt;td&gt;4.70 GB&lt;/td&gt;
&lt;td&gt;0.45 GB (Q8_0 mmproj)&lt;/td&gt;
&lt;td&gt;~5.2 GB&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q4_K_M GGUF&lt;/td&gt;
&lt;td&gt;2.72 GB&lt;/td&gt;
&lt;td&gt;0.45 GB&lt;/td&gt;
&lt;td&gt;~3.2 GB&lt;/td&gt;
&lt;td&gt;Easily&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sizes are the actual file sizes in &lt;a href="https://huggingface.co/mradermacher/WeVisOne-VL-4B-GGUF" rel="noopener noreferrer"&gt;mradermacher/WeVisOne-VL-4B-GGUF&lt;/a&gt;; the repo's README table rounds them up (2.8 GB for Q4_K_M, 0.6 GB for the Q8_0 mmproj). The Hub lists the original checkpoint at 5B params in BF16, so the official bf16 path is roughly 10 GB of weights. That doesn't fit on an 8 GB card without offloading.&lt;/p&gt;

&lt;p&gt;There is one measured data point, from the &lt;a href="https://huggingface.co/PALLER-NOVUS/WeVisOne-VL-GGUF" rel="noopener noreferrer"&gt;PALLER-NOVUS GGUF repo&lt;/a&gt;: in a 20-query pilot on an RTX 2060 6 GB (context 4096, 1,024 to 1,960 image tokens), 4B Q4_K_M peaked at 4.38 GiB of whole-device VRAM at 4.17 s per request. The 4B F16 GGUF had to spill onto the CPU on that card and took about 60 s per query. My guess is that 12 GB is the realistic floor for the Tencent package at bf16, but nobody has published a measured number yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it with the official package (the only way to get masks)
&lt;/h2&gt;

&lt;p&gt;The Tencent package is what loads &lt;code&gt;mask_decoder.pt&lt;/code&gt;. Install it from the repo:&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/Tencent/WeVisOne-VL.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;WeVisOne-VL
conda create &lt;span class="nt"&gt;-n&lt;/span&gt; wevisone-vl &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.10 &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; conda activate wevisone-vl
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &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 python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;PIL&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;wevisone_vl&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WeVisOneVL&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;wevisone_vl.visualization&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;save_result&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WeVisOneVL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tencent/WeVisOne-VL-4B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transformers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# or backend="vllm"
&lt;/span&gt;
&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;demo/examples/images/seabreeze.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RGB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;person&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;save_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outputs/matting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the README example. Swap &lt;code&gt;task&lt;/code&gt; for &lt;code&gt;detection&lt;/code&gt; (with a list of categories as &lt;code&gt;query&lt;/code&gt;), &lt;code&gt;ocr&lt;/code&gt;, &lt;code&gt;count_box&lt;/code&gt; and so on. The README also lists options for &lt;code&gt;device&lt;/code&gt; (&lt;code&gt;"auto"&lt;/code&gt;, &lt;code&gt;"cuda:0"&lt;/code&gt;, &lt;code&gt;"npu:0"&lt;/code&gt;, &lt;code&gt;"cpu"&lt;/code&gt;), &lt;code&gt;dtype&lt;/code&gt;, &lt;code&gt;min_pixels&lt;/code&gt; / &lt;code&gt;max_pixels&lt;/code&gt; and the usual decoding arguments like &lt;code&gt;max_new_tokens&lt;/code&gt; and &lt;code&gt;temperature&lt;/code&gt;. If you're short on memory, lower &lt;code&gt;max_pixels&lt;/code&gt; before anything else; fewer visual tokens means less activation memory. There's a Gradio demo too:&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;CUDA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 python demo/app.py &lt;span class="nt"&gt;--model&lt;/span&gt; tencent/WeVisOne-VL-4B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;--backend vllm&lt;/code&gt; to run it on vLLM instead of transformers.&lt;/p&gt;

&lt;p&gt;The Hub's "Use this model" menu also offers a plain &lt;code&gt;vllm serve "tencent/WeVisOne-VL-4B"&lt;/code&gt; and an SGLang launch command. Since the architecture is stock &lt;code&gt;qwen3_vl&lt;/code&gt;, those serve the language model only: you get coordinate tokens back, parse them yourself, and never see a mask.&lt;/p&gt;

&lt;p&gt;The Hub's transformers snippet for the model asks "What animal is on the candy?" That's the generic image-text-to-text example, so don't judge the model by free-form chat; it was trained for structured outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  GGUF in Ollama and llama.cpp: boxes yes, masks no
&lt;/h2&gt;

&lt;p&gt;There are three community GGUF repos for the 4B so far: &lt;a href="https://huggingface.co/mradermacher/WeVisOne-VL-4B-GGUF" rel="noopener noreferrer"&gt;mradermacher&lt;/a&gt;, &lt;a href="https://huggingface.co/prithivMLmods/tencent-WeVisOne-VL-4B-GGUF" rel="noopener noreferrer"&gt;prithivMLmods&lt;/a&gt; and &lt;a href="https://huggingface.co/PALLER-NOVUS/WeVisOne-VL-GGUF" rel="noopener noreferrer"&gt;PALLER-NOVUS&lt;/a&gt;, which ships 2B and 4B in one repo. The Hub's "Use this model" menu on the mradermacher repo gives:&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;-hf&lt;/span&gt; mradermacher/WeVisOne-VL-4B-GGUF:Q4_K_M
ollama run hf.co/mradermacher/WeVisOne-VL-4B-GGUF:Q4_K_M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that a GGUF is the language model plus an mmproj vision projector. The pixel decoder is a separate PyTorch file, and neither llama.cpp nor Ollama knows what to do with an &lt;code&gt;&amp;lt;OBJ&amp;gt;&lt;/code&gt; token. So on an 8 GB card you should get detection, referring boxes, pointing, counting and OCR grounding as coordinate text, but not segmentation or matting. PALLER-NOVUS says the same: putting &lt;code&gt;mask_decoder.pt&lt;/code&gt; next to a GGUF doesn't give you pixel output. Their Q4_K_M runs did return structured boxes on a pinned, patched llama.cpp build (they say the patch carries changes for another model and adds no WeVisOne capabilities, but stock upstream is untested), launched with &lt;code&gt;--special&lt;/code&gt; so the coordinate tokens survive decoding. I haven't seen anyone confirm that Ollama's &lt;code&gt;hf.co&lt;/code&gt; pull picks up the separate mmproj for this architecture, so test image input there before you build on it. There are no imatrix quants yet either; mradermacher only has static ones so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it the vision model to run on an 8 GB card?
&lt;/h2&gt;

&lt;p&gt;For grounding work, I think yes. If your local pipeline is GroundingDINO for boxes plus SAM for masks, or a general VLM you keep asking for coordinates, this is the first small model I'd test as a replacement, mostly because of the rejection rate. Q4_K_M plus its projector at ~3.2 GB leaves plenty of room.&lt;/p&gt;

&lt;p&gt;For "read this screenshot and tell me what the error says", I wouldn't switch. The OCR benchmarks here measure finding and transcribing text regions with boxes, not answering questions about a document. Stay on whatever general Qwen3-VL build you already use until someone posts DocVQA or OCRBench numbers for this one.&lt;/p&gt;

&lt;p&gt;And if you want masks on 8 GB, you're waiting on a quantized path for the official package, or on someone wiring the pixel decoder into llama.cpp.&lt;/p&gt;

&lt;p&gt;Which small vision model do you actually use for OCR or screenshots locally right now, and would you trust a 4B model's boxes without a human checking them?&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/tencent/WeVisOne-VL-4B" rel="noopener noreferrer"&gt;tencent/WeVisOne-VL-4B model card&lt;/a&gt; and &lt;a href="https://huggingface.co/tencent/WeVisOne-VL-4B/blob/main/config.json" rel="noopener noreferrer"&gt;config.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Tencent/WeVisOne-VL" rel="noopener noreferrer"&gt;Tencent/WeVisOne-VL on GitHub&lt;/a&gt; (benchmark tables, install, tasks)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2610.31329" rel="noopener noreferrer"&gt;WeVisOne-VL paper, arXiv:2610.31329&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/mradermacher/WeVisOne-VL-4B-GGUF" rel="noopener noreferrer"&gt;mradermacher/WeVisOne-VL-4B-GGUF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/prithivMLmods/tencent-WeVisOne-VL-4B-GGUF" rel="noopener noreferrer"&gt;prithivMLmods/tencent-WeVisOne-VL-4B-GGUF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/PALLER-NOVUS/WeVisOne-VL-GGUF" rel="noopener noreferrer"&gt;PALLER-NOVUS/WeVisOne-VL-GGUF&lt;/a&gt; (RTX 2060 pilot in BENCHMARKS.md)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/tencent/WeVisOne-VL-4B/discussions/3" rel="noopener noreferrer"&gt;Discussion #3: Questions on Baseline Selection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>computervision</category>
      <category>llm</category>
    </item>
    <item>
      <title>Raspberry Pi Zero 3W Specs Leak: Pi 4 Chip, Release Date and Why It Won't Be $15</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Thu, 29 Oct 2026 17:40:03 +0000</pubDate>
      <link>https://dev.to/alanwest/raspberry-pi-zero-3w-specs-leak-pi-4-chip-release-date-and-why-it-wont-be-15-3lmc</link>
      <guid>https://dev.to/alanwest/raspberry-pi-zero-3w-specs-leak-pi-4-chip-release-date-and-why-it-wont-be-15-3lmc</guid>
      <description>&lt;p&gt;The Raspberry Pi Zero 3W now has a device tree, and it says the board runs on the BCM2711, the same quad Cortex-A72 chip as the Pi 4. I don't see a way it costs $15 like the Zero 2W, and the reason is the LPDDR4 that chip needs, which Raspberry Pi says has gone up sevenfold in a year.&lt;/p&gt;

&lt;p&gt;I went through the new &lt;code&gt;.dts&lt;/code&gt; files to see what they actually confirm about Zero 3W specs and what's still guesswork (clock, RAM, price, release date). I also pulled published Pi 4 benchmarks to get a rough idea of how fast it could run a small LLM, and whether you should just buy a Zero 2W now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Raspberry Pi Zero 3W leak came from
&lt;/h2&gt;

&lt;p&gt;Phoronix covered it too, but &lt;a href="https://bret.dk/raspberry-pi-zero-3-w-pi-4-model-a/" rel="noopener noreferrer"&gt;bret.dk wrote the detailed breakdown&lt;/a&gt; on 27 October 2026. Two device tree source files written by Marta Momotko were merged into Raspberry Pi's own kernel tree, the &lt;code&gt;rpi-6.18.y&lt;/code&gt; branch of &lt;code&gt;raspberrypi/linux&lt;/code&gt;, through &lt;a href="https://github.com/raspberrypi/linux/pull/7711" rel="noopener noreferrer"&gt;PR #7711&lt;/a&gt; on 25 October 2026. They aren't in mainline Linux, and Raspberry Pi hasn't announced either board. The links below point at the original commits on the &lt;code&gt;martamomotko/linux&lt;/code&gt; fork.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero 3W: &lt;a href="https://raw.githubusercontent.com/martamomotko/linux/1afad193173c7e17fd1d4e802e5e2d7c8ee3fc09/arch/arm/boot/dts/broadcom/bcm2711-rpi-zero-3-w.dts" rel="noopener noreferrer"&gt;&lt;code&gt;bcm2711-rpi-zero-3-w.dts&lt;/code&gt;&lt;/a&gt;, commit &lt;code&gt;1afad193&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pi 4 Model A: &lt;a href="https://raw.githubusercontent.com/martamomotko/linux/c17dd5f6e7accd9b62a7f272c6e69e40efb7563c/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-a.dts" rel="noopener noreferrer"&gt;&lt;code&gt;bcm2711-rpi-4-a.dts&lt;/code&gt;&lt;/a&gt;, commit &lt;code&gt;c17dd5f6&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Zero 3W file is very direct about what it describes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compatible = "raspberrypi,model-zero-3-w", "brcm,bcm2711";
model = "Raspberry Pi Zero 3 W";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Zero 3W specs: confirmed vs. guesswork
&lt;/h2&gt;

&lt;p&gt;A device tree describes how the board is wired. It doesn't cover clocks, RAM or price, so I've split what's in the file from what isn't.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Zero 2W (shipping)&lt;/th&gt;
&lt;th&gt;Zero 3W (device tree)&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SoC&lt;/td&gt;
&lt;td&gt;RP3A0, 4x Cortex-A53 @ 1GHz&lt;/td&gt;
&lt;td&gt;BCM2711, 4x Cortex-A72&lt;/td&gt;
&lt;td&gt;In the DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clock speed&lt;/td&gt;
&lt;td&gt;1GHz&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;Not in DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;512MB LPDDR2&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;Device trees don't describe RAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wi-Fi/BT&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes, includes &lt;code&gt;bcm283x-rpi-wifi-bt.dtsi&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;In the DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;microSD&lt;/td&gt;
&lt;td&gt;EMMC2 with &lt;code&gt;bus-width = &amp;lt;8&amp;gt;&lt;/code&gt;, comment says "eMMC/SD card"&lt;/td&gt;
&lt;td&gt;In the DTS, final form unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bootloader&lt;/td&gt;
&lt;td&gt;On SD&lt;/td&gt;
&lt;td&gt;SPI flash lines, so an EEPROM bootloader like the Pi 4&lt;/td&gt;
&lt;td&gt;In the DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDMI&lt;/td&gt;
&lt;td&gt;1x mini&lt;/td&gt;
&lt;td&gt;1x (second controller disabled)&lt;/td&gt;
&lt;td&gt;In the DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCIe&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;amp;pcie0&lt;/code&gt; enabled&lt;/td&gt;
&lt;td&gt;In the DTS; whether it's exposed is unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Camera&lt;/td&gt;
&lt;td&gt;2-lane CSI&lt;/td&gt;
&lt;td&gt;4-lane CSI config&lt;/td&gt;
&lt;td&gt;In the DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power button&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gpio-keys&lt;/code&gt; on GPIO 46 → &lt;code&gt;KEY_POWER&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;In the DTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price&lt;/td&gt;
&lt;td&gt;$15&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;Pure speculation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 8-bit bus width caught my eye. microSD only uses 4 data lines, so an 8-bit bus points to eMMC. Bret thinks it's a leftover and expects microSD on the final board. That could be right, but I'd keep an eye out for an eMMC SKU, because a Zero with soldered storage would make sense for industrial buyers.&lt;/p&gt;

&lt;p&gt;The Pi 4 Model A file is the boring sibling. It has a disabled Ethernet controller, one HDMI, no analogue audio or composite, microSD only, and antenna-switching lines (&lt;code&gt;ANT_CTRL1&lt;/code&gt;/&lt;code&gt;ANT_CTRL2&lt;/code&gt;, overlay params &lt;code&gt;ant1&lt;/code&gt;, &lt;code&gt;ant2&lt;/code&gt;, &lt;code&gt;noant&lt;/code&gt;) that look a lot like the CM4's internal/external antenna option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raspberry Pi Zero 3W release date
&lt;/h2&gt;

&lt;p&gt;No date has been announced. A device tree merged into Raspberry Pi's kernel means bring-up work is happening, but that doesn't tell you when boards will ship. Anyone quoting a month is guessing. The Zero 2W launched about five years ago and the last Model A was the 3A+ in 2018, so a refresh is overdue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The $15 Zero 3W problem: LPDDR4 prices
&lt;/h2&gt;

&lt;p&gt;The Zero 2W still costs $15 and hasn't gone up during the RAM crunch. Raspberry Pi's own &lt;a href="https://www.raspberrypi.com/news/a-new-3gb-raspberry-pi-4-for-83-75-and-more-memory-driven-price-increases/" rel="noopener noreferrer"&gt;April 2026 pricing post&lt;/a&gt; explains why. The LPDDR2 used in the Zero, Zero 2W and Pi 3 comes from stock the company already holds. The LPDDR4 used in the Pi 4 and Pi 5 has seen "a seven-fold increase over the last year".&lt;/p&gt;

&lt;p&gt;That same post put another $25 on the Pi 4 4GB, $50 on the 8GB, and launched a 3GB Pi 4 at $83.75.&lt;/p&gt;

&lt;p&gt;The BCM2711 uses LPDDR4, so the Zero 3W lands on the memory whose price went up sevenfold instead of the LPDDR2 Raspberry Pi already has in a warehouse. I'd bet on a 512MB or 1GB base model at a price that makes people angry in the comments. On the &lt;a href="https://news.ycombinator.com/item?id=50265594" rel="noopener noreferrer"&gt;HN thread&lt;/a&gt;, one commenter points out that an Orange Pi Zero used to cost less than $10 and now sells for a tad over $30.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can the Zero 3W run an LLM? Pi 4 numbers are the ceiling
&lt;/h2&gt;

&lt;p&gt;There are no Zero 3W benchmarks because there's no Zero 3W yet. But it uses the same SoC as the Pi 4, and a small, passively cooled board almost certainly won't beat a Pi 4. So published Pi 4 numbers are a reasonable upper bound.&lt;/p&gt;

&lt;p&gt;The most useful dataset I found is &lt;a href="https://simeononsecurity.com/articles/ai-models-raspberry-pi-4-5/" rel="noopener noreferrer"&gt;SimeonOnSecurity's Ollama runs on a 2GB Pi 4B&lt;/a&gt;. The runs used five prompts, a 140-token output cap, and cold loads:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model (Pi 4, 2GB)&lt;/th&gt;
&lt;th&gt;Generation tok/s&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LFM2.5-230M&lt;/td&gt;
&lt;td&gt;12.8&lt;/td&gt;
&lt;td&gt;383MB peak RSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LFM2.5-350M&lt;/td&gt;
&lt;td&gt;8.6&lt;/td&gt;
&lt;td&gt;516MB peak RSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen2.5:0.5b&lt;/td&gt;
&lt;td&gt;8.0&lt;/td&gt;
&lt;td&gt;5/5 prompts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MiniCPM5-1B (no reasoning)&lt;/td&gt;
&lt;td&gt;5.9&lt;/td&gt;
&lt;td&gt;883MB peak RSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;granite4:350m&lt;/td&gt;
&lt;td&gt;4.6&lt;/td&gt;
&lt;td&gt;stable, no swap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gemma3:1b&lt;/td&gt;
&lt;td&gt;4.0&lt;/td&gt;
&lt;td&gt;heavy swapping, board rebooted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen3.5:0.8b&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;didn't finish, board rebooted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For comparison, the &lt;a href="https://learn.adafruit.com/local-llms-on-raspberry-pi.md?view=all" rel="noopener noreferrer"&gt;Adafruit guide&lt;/a&gt; measured &lt;code&gt;gemma3:1b&lt;/code&gt; at 9.99 tok/s on an 8GB Pi 5, and SimeonOnSecurity got 11.2 tok/s on its 8GB Pi 5. That's the same model that swapped a 2GB Pi 4 into a reboot at 4.0 tok/s.&lt;/p&gt;

&lt;p&gt;On the Zero 2W, the &lt;a href="https://github.com/ravijo/pi-llm" rel="noopener noreferrer"&gt;pi-llm project&lt;/a&gt; got llama.cpp working with SmolLM2-135M at Q4_K_M. It managed 9.5 to 10.9 tok/s generation, needed a mandatory 2GB swapfile, and took about 24 hours to compile on the board. The README warns that larger models may not run at all.&lt;/p&gt;

&lt;p&gt;What I take from those numbers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;RAM matters more than the A72 cores. Gemma 3 1B was already swapping and rebooting a 2GB Pi 4. If the Zero 3W ships with 512MB or 1GB, 1B-class models will be painful or won't load.&lt;/li&gt;
&lt;li&gt;Models from 230M to 500M are where it'll work. LFM2.5-230M at 12.8 tok/s, or LFM2.5-350M and Qwen2.5-0.5B at around 8 tok/s, on Pi 4 silicon is fine for intent parsing, short summaries or a voice-assistant command layer. I wouldn't chat with it.&lt;/li&gt;
&lt;li&gt;Over the Zero 2W, you mostly gain model size. The Zero 2W gets about 10 tok/s from a 135M model; Pi 4 silicon with enough RAM should get similar speed from a model about 3x bigger. That's worth having, since the pi-llm README admits its 135M model's responses "can be repetitive or incoherent".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want a 1B model on a Pi today, buy a Pi 5. Boring answer, but that's what the numbers say.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buy a Zero 2W now or wait for the Zero 3W?
&lt;/h2&gt;

&lt;p&gt;My take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buy the Zero 2W now if your project is GPIO, sensors, a Pi-hole, a USB gadget, or anything that already runs fine on it. It costs $15, it's in stock, and the price is protected by LPDDR2 stock. A Zero 3W probably won't help a temperature logger.&lt;/li&gt;
&lt;li&gt;Wait if you're hitting the 512MB wall, need PCIe or 4-lane CSI, or want a small on-device model. Expect to pay more.&lt;/li&gt;
&lt;li&gt;Skip both if you want local LLMs. Get a Pi 5 with at least 4GB. HN commenters also bring up Rockchip boards like the Radxa Zero 3W, though one owner there says its Cortex-A55 cores are only slightly better than the Zero 2W's A53s.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you already have a Zero 2W and want to try a tiny model, don't compile on the board. Build on a faster ARM64 machine or cross-compile, copy the binary over, and add swap first. On a Bookworm-based Raspberry Pi OS image that still uses &lt;code&gt;dphys-swapfile&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;&lt;span class="nb"&gt;sudo &lt;/span&gt;dphys-swapfile swapoff
&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/^CONF_SWAPSIZE=.*/CONF_SWAPSIZE=2048/'&lt;/span&gt; /etc/dphys-swapfile
&lt;span class="nb"&gt;sudo &lt;/span&gt;dphys-swapfile setup &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;dphys-swapfile swapon
free &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run a model in the SmolLM2-135M class with &lt;code&gt;-t 4&lt;/code&gt;, and watch &lt;code&gt;vcgencmd get_throttled&lt;/code&gt; while it generates. On a Zero, thermals will start to matter before model quality does.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what's it for?
&lt;/h2&gt;

&lt;p&gt;I like the idea of a Pi 4 chip in a Zero footprint, and it's overdue. With LPDDR4 at current prices, though, I doubt it'll be the cheap hacking board people on HN want. My guess is a small, pricier board for camera rigs, PCIe experiments and edge projects that have outgrown 512MB.&lt;/p&gt;

&lt;p&gt;What would you build with a Zero 3W that the Zero 2W was too slow for? And at what price do you skip it for a Pi 5 or an ESP32? Tell me in the comments. I especially want to hear from people running models on a Zero 2W today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bret.dk/raspberry-pi-zero-3-w-pi-4-model-a/" rel="noopener noreferrer"&gt;bret.dk: Raspberry Pi Zero 3 W and Pi 4 Model A on the way?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/martamomotko/linux/1afad193173c7e17fd1d4e802e5e2d7c8ee3fc09/arch/arm/boot/dts/broadcom/bcm2711-rpi-zero-3-w.dts" rel="noopener noreferrer"&gt;Zero 3W device tree, commit 1afad193&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/martamomotko/linux/c17dd5f6e7accd9b62a7f272c6e69e40efb7563c/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-a.dts" rel="noopener noreferrer"&gt;Pi 4 Model A device tree, commit c17dd5f6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/raspberrypi/linux/pull/7711" rel="noopener noreferrer"&gt;raspberrypi/linux PR #7711&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=50265594" rel="noopener noreferrer"&gt;Hacker News discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.raspberrypi.com/news/a-new-3gb-raspberry-pi-4-for-83-75-and-more-memory-driven-price-increases/" rel="noopener noreferrer"&gt;Raspberry Pi: a new 3GB Raspberry Pi 4 for $83.75, and more memory-driven price increases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simeononsecurity.com/articles/ai-models-raspberry-pi-4-5/" rel="noopener noreferrer"&gt;SimeonOnSecurity: AI models on Raspberry Pi 4 and 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.adafruit.com/local-llms-on-raspberry-pi.md?view=all" rel="noopener noreferrer"&gt;Adafruit: Local LLMs on Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ravijo/pi-llm" rel="noopener noreferrer"&gt;ravijo/pi-llm: llama.cpp on Pi Zero 2W&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>raspberrypi</category>
      <category>linux</category>
      <category>hardware</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to Run an Offline AI Assistant With No Internet (Even on a Raspberry Pi)</title>
      <dc:creator>Alan West</dc:creator>
      <pubDate>Thu, 29 Oct 2026 16:30:03 +0000</pubDate>
      <link>https://dev.to/alanwest/how-to-run-an-offline-ai-assistant-with-no-internet-even-on-a-raspberry-pi-4lf3</link>
      <guid>https://dev.to/alanwest/how-to-run-an-offline-ai-assistant-with-no-internet-even-on-a-raspberry-pi-4lf3</guid>
      <description>&lt;p&gt;&lt;a href="https://www.brangus.io/survival-llm" rel="noopener noreferrer"&gt;Survival LLM&lt;/a&gt;, the offline AI assistant Hacker News spent this week arguing about, got 14 of 22 blackout and first-aid questions right on a 16 GB machine. The other eight missed the main point of the official guidance, and these were emergency questions.&lt;/p&gt;

&lt;p&gt;It's free, MIT-licensed, and bundles a local model with an offline emergency library so you can ask questions with no internet. I like the idea. I also think the library is the half that matters and the model is mostly a search box on top of it. Below I go through what Survival LLM ships and what hardware it wants, then how to build the same kind of offline kit on Linux with Ollama or llama.cpp plus Kiwix, including on a Raspberry Pi, which Survival LLM doesn't support.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Survival LLM actually ships
&lt;/h2&gt;

&lt;p&gt;The app is small (212 MB on Mac, 25 MB on Windows). On first run it checks how much memory you have, picks a model and downloads it. These are the published tiers from &lt;a href="https://www.brangus.io/survival-llm" rel="noopener noreferrer"&gt;the project page&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your machine&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Emergency test score&lt;/th&gt;
&lt;th&gt;Model download&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mac, 128 GB+&lt;/td&gt;
&lt;td&gt;NVIDIA Nemotron 3.5 Super&lt;/td&gt;
&lt;td&gt;21 / 22&lt;/td&gt;
&lt;td&gt;80 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mac, 32–96 GB&lt;/td&gt;
&lt;td&gt;Qwen3.8 27B&lt;/td&gt;
&lt;td&gt;21 / 22&lt;/td&gt;
&lt;td&gt;18 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows PC, 32 GB+&lt;/td&gt;
&lt;td&gt;NVIDIA Nemotron 3.5 Lightning&lt;/td&gt;
&lt;td&gt;19 / 22&lt;/td&gt;
&lt;td&gt;25 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mac or PC, 16–31 GB&lt;/td&gt;
&lt;td&gt;IBM Granite 4.2 8B&lt;/td&gt;
&lt;td&gt;14 / 22&lt;/td&gt;
&lt;td&gt;6 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The score counts answers that got the main point of official guidance right on 22 blind-graded questions. The page notes the tests ran against an earlier build of the library.&lt;/p&gt;

&lt;p&gt;The library is the interesting part. The full version is a 9 GB download (19 GB installed) of plain-text, searchable copies of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;about 930,000 of Wikipedia's most-read articles&lt;/li&gt;
&lt;li&gt;WikiMed, MedlinePlus, UK Medicines A to Z and WikEM (emergency medicine)&lt;/li&gt;
&lt;li&gt;Ready.gov (FEMA) guides, CDC travelers' health, and U.S. military medicine and survival manuals&lt;/li&gt;
&lt;li&gt;wikiHow, iFixit, Appropedia&lt;/li&gt;
&lt;li&gt;Stack Exchange Q&amp;amp;A on home repair, cooking, gardening, outdoors and ham radio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also a 1.3 GB "smaller library" (3 GB installed) that drops Wikipedia and iFixit. For disk space, plan on the model size plus 5 GB, and about 27 GB of temporary space while the full library installs. You can add your own PDFs, ebooks and notes, and each answer shows its sources. Version 0.3.4 (Oct 27, 2026) added a reasoning budget setting: Off, 1,000, 4,000, 16,000 tokens, or no limit.&lt;/p&gt;

&lt;p&gt;Platform support is Apple Silicon on macOS 14+ or 64-bit Windows 10/11. There's no Linux build, which got the expected grumbling &lt;a href="https://news.ycombinator.com/item?id=50264853" rel="noopener noreferrer"&gt;in the HN thread&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Power: about 100 W per answer, 100 to 300 answers per charge
&lt;/h2&gt;

&lt;p&gt;The project publishes this, which I appreciate. On a MacBook Pro it draws about 100 W while answering, for 5 to 40 seconds per question, which works out to roughly 100 to 300 answers on a full battery.&lt;/p&gt;

&lt;p&gt;At 20 questions a day that's 5 to 15 days per charge, and recharging is the hard part when the grid is down. One HN commenter asked whether you'd really run your generator for a local model. Plain Kiwix, by comparison, is a web server reading compressed files, and it sips power next to a GPU doing inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the LLM shouldn't be the only thing on the drive
&lt;/h2&gt;

&lt;p&gt;The HN thread splits in two. One side treats the LLM as search: it finds the article when you don't know the keyword. The other asks what it adds over a plain index, which is smaller and faster and can't invent anything. I think both sides have a point. One commenter asked how to build a bow drill and got an answer that was partly wrong about how the bow works. Another, running Qwen 27B on a 32 GB M1 (about 19 to 23 GB used), noticed that answers the model pulled from its own memory came with no sources, and that it ran a real search once told to "look that up".&lt;/p&gt;

&lt;p&gt;So my rule is to use the model to find the page, then read the page. The library has to be something you can browse without the model running. Kiwix gives you that, and it's what I'd build around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build your own offline AI kit on Linux: Ollama plus Kiwix
&lt;/h2&gt;

&lt;p&gt;You need two pieces. For the model runtime, &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; is the easy path, and &lt;a href="https://github.com/ggml-org/llama.cpp" rel="noopener noreferrer"&gt;llama.cpp&lt;/a&gt; is there if you want fewer layers between you and the GGUF file. For the library, use &lt;a href="https://github.com/kiwix/kiwix-tools" rel="noopener noreferrer"&gt;Kiwix&lt;/a&gt; ZIM files served by &lt;code&gt;kiwix-serve&lt;/code&gt;. Most of what Survival LLM bundles (Wikipedia, WikiMed, iFixit, Appropedia) is available as ZIM files: compressed, searchable archives, with or without images.&lt;/p&gt;

&lt;p&gt;Sizes from the &lt;a href="https://download.kiwix.org/zim/" rel="noopener noreferrer"&gt;Kiwix mirror&lt;/a&gt; as of this month:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ZIM file&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;
&lt;code&gt;wikipedia_en_all_maxi_2026-08.zim&lt;/code&gt; (full, with images)&lt;/td&gt;
&lt;td&gt;119 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;wikipedia_en_all_nopic_2026-06.zim&lt;/code&gt; (full, no images)&lt;/td&gt;
&lt;td&gt;49 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;wikipedia_en_all_mini_2026-09.zim&lt;/code&gt; (intros only)&lt;/td&gt;
&lt;td&gt;13 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;wikipedia_en_top_maxi_2026-09.zim&lt;/code&gt; (top articles)&lt;/td&gt;
&lt;td&gt;6.5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wikipedia_en_medicine_maxi_2026-10.zim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.7 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;mdwiki_en_all_maxi_2025-11.zim&lt;/code&gt; (WikiMed)&lt;/td&gt;
&lt;td&gt;2.1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ifixit_en_all_2025-12.zim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3.3 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zimgit-post-disaster_en_2024-05.zim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;615 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;appropedia_en_all_maxi_2026-02.zim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;555 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zimgit-water_en_2024-08.zim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;20 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Disk and RAM by tier, from Raspberry Pi 5 to a 32 GB laptop
&lt;/h2&gt;

&lt;p&gt;Model sizes are from the Ollama library pages for &lt;a href="https://ollama.com/library/granite4.2" rel="noopener noreferrer"&gt;Granite 4.2&lt;/a&gt; and &lt;a href="https://ollama.com/library/gemma4" rel="noopener noreferrer"&gt;Gemma 4&lt;/a&gt;. Gemma 4 12B was the model HN commenters suggested for modest hardware.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Model (Ollama tag, size)&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Total disk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi 5, 16 GB&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;granite4.2:3b&lt;/code&gt;, 2.2 GB&lt;/td&gt;
&lt;td&gt;top_maxi + WikiMed + iFixit + post-disaster + Appropedia&lt;/td&gt;
&lt;td&gt;~15 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Old laptop, 16 GB&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;granite4.2:8b&lt;/code&gt;, 5.3 GB&lt;/td&gt;
&lt;td&gt;full nopic Wikipedia + same extras&lt;/td&gt;
&lt;td&gt;~61 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mini PC or laptop, 32 GB&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gemma4:26b&lt;/code&gt;, 16–19 GB&lt;/td&gt;
&lt;td&gt;full maxi Wikipedia + same extras&lt;/td&gt;
&lt;td&gt;~145 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 16 GB row uses the same Granite 8B that Survival LLM picks for that tier, so expect roughly the same 14/22 accuracy. That's another reason to keep the articles one click away.&lt;/p&gt;

&lt;p&gt;On the Pi, be realistic. One &lt;a href="https://stratospherelinuxips.readthedocs.io/en/develop/immune/research_rpi_llm_performance.html" rel="noopener noreferrer"&gt;Pi 5 benchmark under Ollama&lt;/a&gt; measured &lt;code&gt;qwen2.5:3b&lt;/code&gt; at 5.2 tokens/s and &lt;code&gt;llama3.2:3b&lt;/code&gt; at 4.69 tokens/s, both Q4_K_M. Those same authors set &lt;code&gt;OLLAMA_LOAD_TIMEOUT=60m0s&lt;/code&gt; because some models load that slowly. &lt;a href="https://localaimaster.com/blog/llm-raspberry-pi-5" rel="noopener noreferrer"&gt;Another write-up&lt;/a&gt; works out a theoretical ceiling of about 8.6 tokens/s for Llama 3.2 3B at Q4_K_M from the Pi 5's 17.1 GB/s memory bandwidth. It also notes that inference pins all four cores at 100%, so get the active cooler. Either way, on a Pi the model is the slow extra and Kiwix is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup commands (do all of this while you still have internet)
&lt;/h2&gt;

&lt;p&gt;Install Ollama and pull a model:&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;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
ollama pull granite4.2:8b
ollama run granite4.2:8b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with llama.cpp, using the commands from its current README:&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;-LsSf&lt;/span&gt; https://llama.app/install.sh | sh
llama serve &lt;span class="nt"&gt;-hf&lt;/span&gt; ggml-org/Qwen3.5-0.8B-GGUF   &lt;span class="c"&gt;# swap in the GGUF repo you want&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;llama serve&lt;/code&gt; gives you an OpenAI-compatible API and a built-in web UI. Run it once while you're online so the weights are already on disk.&lt;/p&gt;

&lt;p&gt;Then the library. Install &lt;code&gt;kiwix-tools&lt;/code&gt; from your distro (Debian and Ubuntu package it), download your ZIMs, and serve them:&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;kiwix-tools
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/zim &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ~/zim
wget https://download.kiwix.org/zim/wikipedia/wikipedia_en_all_nopic_2026-06.zim
wget https://download.kiwix.org/zim/ifixit/ifixit_en_all_2025-12.zim
kiwix-serve &lt;span class="nt"&gt;-p&lt;/span&gt; 8080 ~/zim/&lt;span class="k"&gt;*&lt;/span&gt;.zim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:8080&lt;/code&gt; and you have searchable offline Wikipedia and iFixit. Any phone on the same Wi-Fi can reach it too, which is the main thing a Pi tier gets you.&lt;/p&gt;

&lt;p&gt;If you'd rather not wire it up yourself, &lt;a href="https://www.projectnomad.us/" rel="noopener noreferrer"&gt;Project NOMAD&lt;/a&gt; (Apache 2.0) bundles Kiwix, Ollama, OpenStreetMap offline maps and Kolibri in a Docker install on Ubuntu or Debian. It recommends 32 GB RAM and a 1 TB SSD, though, so it's not the "old laptop" route.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pre-outage checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Pull the model and run it once with the network cable unplugged. If it tries to fetch something, find out now.&lt;/li&gt;
&lt;li&gt;Check the ZIM files open in &lt;code&gt;kiwix-serve&lt;/code&gt; before you go offline.&lt;/li&gt;
&lt;li&gt;Put the whole thing on a second drive, and keep a cheap USB stick with just the Kiwix files.&lt;/li&gt;
&lt;li&gt;Print the few pages you'd need in the first hour: CPR, water purification, your own medications. Several HN commenters made this point, and they're right: paper doesn't need a charger.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'd install Survival LLM on a Mac without thinking twice. Just remember the 14/22 at the 16 GB tier, and treat the library as the source of truth.&lt;/p&gt;

&lt;p&gt;If the internet went down for a month, what would you want on your offline drive besides a model and Wikipedia? One HN commenter said the default library feels "more like a tool for city dwellers" because it skips hunting and field dressing. What's missing from yours?&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.brangus.io/survival-llm" rel="noopener noreferrer"&gt;Survival LLM project page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=50264853" rel="noopener noreferrer"&gt;Hacker News discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://download.kiwix.org/zim/" rel="noopener noreferrer"&gt;Kiwix ZIM downloads&lt;/a&gt; and &lt;a href="https://github.com/kiwix/kiwix-tools" rel="noopener noreferrer"&gt;kiwix-tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://manpages.debian.org/testing/kiwix-tools/kiwix-serve.1.en.html" rel="noopener noreferrer"&gt;kiwix-serve man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ollama.com/library/granite4.2" rel="noopener noreferrer"&gt;Ollama: Granite 4.2&lt;/a&gt;, &lt;a href="https://ollama.com/library/gemma4" rel="noopener noreferrer"&gt;Gemma 4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ggml-org/llama.cpp" rel="noopener noreferrer"&gt;llama.cpp README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.projectnomad.us/" rel="noopener noreferrer"&gt;Project NOMAD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Raspberry Pi 5 LLM numbers: &lt;a href="https://stratospherelinuxips.readthedocs.io/en/develop/immune/research_rpi_llm_performance.html" rel="noopener noreferrer"&gt;Stratosphere research notes&lt;/a&gt;, &lt;a href="https://localaimaster.com/blog/llm-raspberry-pi-5" rel="noopener noreferrer"&gt;localaimaster.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>selfhosted</category>
      <category>linux</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
