<?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: Valentyn Ivanov</title>
    <description>The latest articles on DEV Community by Valentyn Ivanov (@valentinivanov).</description>
    <link>https://dev.to/valentinivanov</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%2F4076022%2F90ca3b7c-8bb4-4614-9fcb-618522bd9ada.jpg</url>
      <title>DEV Community: Valentyn Ivanov</title>
      <link>https://dev.to/valentinivanov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/valentinivanov"/>
    <language>en</language>
    <item>
      <title>The power of mental models for developers</title>
      <dc:creator>Valentyn Ivanov</dc:creator>
      <pubDate>Tue, 08 Sep 2026 13:34:30 +0000</pubDate>
      <link>https://dev.to/valentinivanov/the-power-of-mental-models-for-developers-2nc9</link>
      <guid>https://dev.to/valentinivanov/the-power-of-mental-models-for-developers-2nc9</guid>
      <description>&lt;h2&gt;
  
  
  Down the memory lane
&lt;/h2&gt;

&lt;p&gt;Some developers don’t understand memory.&lt;br&gt;
They understand new, delete, or garbage collection. And again — that’s just the surface.&lt;/p&gt;

&lt;p&gt;Memory is not a flat, uniform space.&lt;br&gt;
It’s a hierarchy:&lt;br&gt;
• registers&lt;br&gt;
• multiple levels of cache&lt;br&gt;
• RAM&lt;br&gt;
• virtual memory managed by the OS&lt;br&gt;
Each layer has different latency and behavior.&lt;/p&gt;

&lt;p&gt;But we usually learn memory management like this:&lt;br&gt;
“allocate object → use it → free it”&lt;br&gt;
So we assume: as long as memory is “managed”, everything is fine.&lt;br&gt;
It’s not.&lt;/p&gt;

&lt;p&gt;Performance is often dominated by:&lt;br&gt;
• cache locality&lt;br&gt;
• allocation patterns&lt;br&gt;
• fragmentation&lt;br&gt;
• allocator contention&lt;/p&gt;

&lt;p&gt;That’s why two identical algorithms can have wildly different performance&lt;br&gt;
depending on how data is laid out in memory.&lt;/p&gt;

&lt;p&gt;Using smart pointers doesn’t mean you understand memory. It means you’ve delegated part of the problem. Which is fine — until it isn’t.&lt;/p&gt;

&lt;p&gt;If you care about performance, you need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how data moves,&lt;/li&gt;
&lt;li&gt;how it’s cached,
and how it’s allocated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because in the end:&lt;br&gt;
It’s not about what your code does.&lt;br&gt;
It’s about how it lives in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building blocks
&lt;/h2&gt;

&lt;p&gt;Data types are one of the most misunderstood fundamentals.&lt;br&gt;
Because we don’t really learn what they are.&lt;/p&gt;

&lt;p&gt;We learn their names: int, float, bool - feel like simple building blocks.&lt;br&gt;
But underneath, they are:&lt;br&gt;
• bit patterns&lt;br&gt;
• rules of interpretation&lt;br&gt;
• operations defined over those bits&lt;br&gt;
Without that model, decisions become guesswork.&lt;/p&gt;

&lt;p&gt;Like using signed integers for sizes.&lt;br&gt;
A size is a count. It cannot be negative.&lt;/p&gt;

&lt;p&gt;But if your type allows negative values, you’ve already introduced invalid states into your system.&lt;br&gt;
This leads to subtle bugs:&lt;br&gt;
• overflow issues&lt;br&gt;
• signed/unsigned comparison traps&lt;br&gt;
• edge cases that “should never happen” — but do&lt;/p&gt;

&lt;p&gt;The deeper issue is this:&lt;br&gt;
A type is not a label. It’s a constraint on reality.&lt;/p&gt;

&lt;p&gt;If you don’t understand:&lt;br&gt;
• binary representation&lt;br&gt;
• overflow behavior&lt;br&gt;
• how arithmetic actually works at the hardware level&lt;br&gt;
then you’re not choosing types. You’re guessing.&lt;/p&gt;

&lt;p&gt;And sometimes guessing is enough.&lt;br&gt;
Until it isn’t.&lt;/p&gt;

&lt;p&gt;We teach developers what to write.&lt;br&gt;
We rarely teach them what it means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrency
&lt;/h2&gt;

&lt;p&gt;Some developers don’t learn concurrency. They learn async/await or whatever concurrency utilities their favorite language or framework provides. And those are not the same thing.&lt;/p&gt;

&lt;p&gt;Threads are not a language feature. They exist at the OS level, run on physical CPU cores, and compete for shared memory and cache.&lt;/p&gt;

&lt;p&gt;But many of us first encounter concurrency through: Python, C++, Java, or some framework API.&lt;br&gt;
So our mental model becomes: “this is how concurrency works.”&lt;br&gt;
It’s not.&lt;br&gt;
It’s just how one runtime exposes it.&lt;/p&gt;

&lt;p&gt;That’s why things feel unpredictable:&lt;br&gt;
• “Why do I still get race conditions?”&lt;br&gt;
• “Why is my async code slower than sync?”&lt;br&gt;
• “Why doesn’t this scale across cores?”&lt;br&gt;
Because underneath:&lt;br&gt;
• the OS scheduler decides who runs&lt;br&gt;
• context switching is not free&lt;br&gt;
• cores share memory with non-uniform latency&lt;br&gt;
• caches can invalidate each other&lt;/p&gt;

&lt;p&gt;If you don’t understand that layer, you’re not really reasoning about concurrency.&lt;br&gt;
You’re just using it.&lt;/p&gt;

&lt;p&gt;To be clear — that’s fine at the beginning.&lt;br&gt;
But the moment you care about performance or correctness under load,&lt;br&gt;
you have to go down the stack.&lt;/p&gt;

&lt;p&gt;Hardware → OS → runtime → language.&lt;br&gt;
Not the other way around.&lt;/p&gt;

&lt;p&gt;Otherwise you’re not solving concurrency problems.&lt;br&gt;
You’re operating an API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstractions are just tools
&lt;/h2&gt;

&lt;p&gt;In previous chapters I talked about:&lt;br&gt;
• concurrency&lt;br&gt;
• memory&lt;br&gt;
• data types&lt;/p&gt;

&lt;p&gt;At first glance, these look like different topics.&lt;br&gt;
They’re not.&lt;/p&gt;

&lt;p&gt;They all share the same root problem:&lt;br&gt;
We learn abstractions… without understanding what they abstract.&lt;/p&gt;

&lt;p&gt;We learn:&lt;br&gt;
• async/await instead of how threads are scheduled&lt;br&gt;
• new/delete instead of how memory behaves&lt;br&gt;
• int/float instead of how data is represented&lt;/p&gt;

&lt;p&gt;So our mental model becomes: “this is how the system works”&lt;br&gt;
When in reality: “this is how one layer exposes it”&lt;/p&gt;

&lt;p&gt;And most of the time, that’s enough.&lt;br&gt;
Until it isn’t.&lt;/p&gt;

&lt;p&gt;The cracks appear when:&lt;br&gt;
• performance matters&lt;br&gt;
• systems scale&lt;br&gt;
• bugs become non-deterministic&lt;br&gt;
• behavior stops matching intuition&lt;/p&gt;

&lt;p&gt;That’s when abstraction stops helping and starts hiding the problem.&lt;/p&gt;

&lt;p&gt;This doesn’t mean everyone must become a hardware engineer.&lt;br&gt;
But it does mean: &lt;br&gt;
If you want to reason about systems, you need to understand the layers below them.&lt;/p&gt;

&lt;p&gt;A simple rule that helped me:&lt;br&gt;
When something feels “weird” or unpredictable — you’re probably missing a layer in your mental model.&lt;/p&gt;

&lt;p&gt;Go one level deeper:&lt;br&gt;
hardware → OS → runtime → language.&lt;br&gt;
That’s usually where the answer is.&lt;/p&gt;

&lt;p&gt;Abstractions are tools.&lt;br&gt;
But understanding is leverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mental model
&lt;/h2&gt;

&lt;p&gt;A fair question may come up:&lt;br&gt;
“How do I actually learn all these lower layers without going down a 5-year rabbit hole?”&lt;/p&gt;

&lt;p&gt;Short answer:&lt;br&gt;
You don’t need to learn everything. You need to learn just enough to build a mental model.&lt;/p&gt;

&lt;p&gt;Here’s what actually works.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Learn one layer below your current work&lt;br&gt;
If you’re writing application code → learn runtime behavior&lt;br&gt;
If you’re using runtime features → learn OS basics&lt;br&gt;
If you’re already there → peek into hardware&lt;br&gt;
Don’t jump straight into CPU manuals. Go one step down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learn through problems, not theory&lt;br&gt;
Don’t start with textbooks.&lt;br&gt;
Start with questions like:&lt;br&gt;
• “Why is this slower than expected?”&lt;br&gt;
• “Why does this break under load?”&lt;br&gt;
• “Why does this behave differently on another machine?”&lt;br&gt;
Then dig until you hit the real cause. That’s where learning sticks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build small, focused experiments&lt;br&gt;
You don’t need big projects.&lt;br&gt;
Try things like:&lt;br&gt;
• write a tiny thread pool&lt;br&gt;
• measure cache effects with different data layouts&lt;br&gt;
• intentionally create a race condition and observe it&lt;br&gt;
• compare contiguous vs scattered allocations&lt;br&gt;
You’ll learn more from one experiment than from hours of passive reading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use tools that show reality&lt;br&gt;
Start simple:&lt;br&gt;
• profilers (CPU, memory)&lt;br&gt;
• timing measurements&lt;br&gt;
• system monitors&lt;br&gt;
Look at what the system is actually doing — not what you think it’s doing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accept partial understanding&lt;br&gt;
You don’t need to master everything.&lt;br&gt;
If you walk away knowing:&lt;br&gt;
• caches exist and affect performance&lt;br&gt;
• threads are scheduled, not “run” by your code&lt;br&gt;
• memory is not uniform&lt;br&gt;
you’re already ahead of most developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go deeper only when it pays off&lt;br&gt;
Not every problem needs low-level knowledge.&lt;br&gt;
But when something feels:&lt;br&gt;
• slow&lt;br&gt;
• unpredictable&lt;br&gt;
• “magical”&lt;br&gt;
that’s your signal to go down a layer.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don’t need to become a systems expert.&lt;br&gt;
But you do need to know when the abstraction stops being enough.&lt;br&gt;
That’s the real skill.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Embedding a web UI into a native desktop application comes with a price</title>
      <dc:creator>Valentyn Ivanov</dc:creator>
      <pubDate>Mon, 07 Sep 2026 12:45:20 +0000</pubDate>
      <link>https://dev.to/valentinivanov/embedding-a-web-ui-into-a-native-desktop-application-comes-with-a-price-2f26</link>
      <guid>https://dev.to/valentinivanov/embedding-a-web-ui-into-a-native-desktop-application-comes-with-a-price-2f26</guid>
      <description>&lt;p&gt;I thought embedding a web UI into a native desktop application would be the easy part.&lt;br&gt;
After all... macOS has WebKit. Linux has GTK WebKit. Windows has WebView2.&lt;/p&gt;

&lt;p&gt;One API per platform, smaller installers, native look &amp;amp; feel. Sounds perfect.&lt;br&gt;
Then reality arrived.&lt;/p&gt;

&lt;h2&gt;
  
  
  macOS 🍎
&lt;/h2&gt;

&lt;p&gt;Honestly, this was the easiest platform.&lt;br&gt;
System WebKit is there.&lt;br&gt;
It behaves consistently.&lt;br&gt;
No additional runtime.&lt;br&gt;
No installer surprises.&lt;br&gt;
Exactly what you'd expect from a platform component.&lt;br&gt;
10/10&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux 🐧
&lt;/h2&gt;

&lt;p&gt;Things became... more interesting.&lt;br&gt;
GTK WebKit works, but suddenly packaging starts to matter.&lt;br&gt;
An AppImage built on one distribution may refuse to start on another because some required WebKitGTK library isn't available.&lt;br&gt;
Your application itself is perfectly fine.&lt;br&gt;
The user's system just doesn't happen to provide exactly the version your build expects.&lt;br&gt;
You quickly discover that "works on my machine" has many regional dialects.&lt;br&gt;
7/10&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows 🪟
&lt;/h2&gt;

&lt;p&gt;This one surprised me the most.&lt;br&gt;
Unlike macOS, the web view isn't really just "there."&lt;br&gt;
Using WebView2 means depending on the Edge WebView runtime.&lt;br&gt;
If the runtime isn't installed, congratulations—you now need another installer.&lt;br&gt;
So your installer may install something whose purpose is to allow your application to display HTML.&lt;br&gt;
Not exactly the dependency story I was hoping for.&lt;br&gt;
2/10&lt;/p&gt;

&lt;h2&gt;
  
  
  Meeting in the middle
&lt;/h2&gt;

&lt;p&gt;At some point I asked myself:&lt;br&gt;
Why am I spending time debugging operating-system packaging instead of building my application?&lt;/p&gt;

&lt;p&gt;So I tried CEF (Chromium Embedded Framework).&lt;br&gt;
Yes...&lt;br&gt;
The application becomes larger.&lt;br&gt;
Quite a bit larger.&lt;/p&gt;

&lt;p&gt;But in exchange:&lt;br&gt;
• Same rendering engine everywhere.&lt;br&gt;
• Same JavaScript engine everywhere.&lt;br&gt;
• Same debugging experience.&lt;br&gt;
• Same HTML/CSS behavior.&lt;br&gt;
• No Linux WebKit dependency lottery.&lt;br&gt;
• No separate WebView runtime installation on Windows.&lt;br&gt;
• One code path across all desktop platforms.&lt;br&gt;
Ironically, shipping your own browser turned out to be simpler than relying on the browser already "provided" by the operating system.&lt;br&gt;
It's one of those engineering decisions that looks wasteful on paper but ends up reducing complexity everywhere else.&lt;br&gt;
Sometimes carrying the extra megabytes is cheaper than carrying platform-specific surprises.&lt;/p&gt;

&lt;p&gt;Curious what others have settled on.&lt;/p&gt;

&lt;p&gt;Are you using native web views, CEF, or something else for cross-platform desktop applications?&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>crossplatform</category>
      <category>architecture</category>
    </item>
    <item>
      <title>A Generative UI approach for Human/AI interaction</title>
      <dc:creator>Valentyn Ivanov</dc:creator>
      <pubDate>Thu, 03 Sep 2026 12:27:25 +0000</pubDate>
      <link>https://dev.to/valentinivanov/a-generative-ui-approach-for-humanai-interaction-200a</link>
      <guid>https://dev.to/valentinivanov/a-generative-ui-approach-for-humanai-interaction-200a</guid>
      <description>&lt;p&gt;The "Gulf of Execution" in AI chat is real - and it’s exhausting.&lt;/p&gt;

&lt;p&gt;Staring at a blank prompt box, trying to engineer the perfect text, and back-and-forth messaging just to tweak a setting? That’s not productivity. That’s friction.&lt;br&gt;
Chatting about work isn't the same as doing work.&lt;/p&gt;

&lt;p&gt;The fix? Generative UI.&lt;/p&gt;

&lt;p&gt;Instead of forcing users to type everything out, AI should build the interface on the fly:&lt;br&gt;
Card-based UI: Quick, scannable micro-actions over walls of text.&lt;br&gt;
Auto-generated forms: Pre-fill what the AI knows; let the user tweak the rest in two clicks.&lt;br&gt;
Custom applets: Drop mini interactive tools right into the thread when visuals or calculators matter.&lt;/p&gt;

&lt;p&gt;If I ask an AI to configure a project, compare several options, review a diff, or choose from a tree of files, why should it respond with another wall of text?&lt;/p&gt;

&lt;p&gt;The model can decide to create a form, table, selector, confirmation dialog, diff view, etc. — without being specifically trained for GUI generation.&lt;br&gt;
The UI is retained locally, so sliders, checkboxes, typing, and other low-level interaction don’t require another LLM call. Only meaningful events such as Submit, Confirm, or Explain go back to the model.&lt;/p&gt;

&lt;p&gt;So the flow becomes:&lt;br&gt;
LLM → UI tools → interactive UI → semantic event → LLM&lt;br&gt;
instead of endless:&lt;br&gt;
LLM → text → user → text → LLM&lt;br&gt;
It feels a little like “Dear ImGui for AI agents.”&lt;/p&gt;

&lt;p&gt;Open standards like A2UI (Agent-to-User Interface) are making this seamless - letting agents output clean UI components directly into any app, not just text strings.&lt;/p&gt;

&lt;p&gt;The next era of AI UX isn't teaching people to prompt better. It's building interfaces that get out of the way.&lt;/p&gt;

&lt;p&gt;Are you still building pure chat, or moving toward Generative UI?&lt;/p&gt;

&lt;p&gt;I for one built a small PoC library allowing to expose custom UIs to ChatGPT and similar AIs. Imagine running the whole CAD or 3d slicer or video editor INSIDE the chat window.&lt;/p&gt;

&lt;p&gt;You can even play Pong while boss is not looking!&lt;/p&gt;

&lt;p&gt;Here's the link to the library: &lt;a href="https://github.com/valentinivanov/ai-gui-tools" rel="noopener noreferrer"&gt;Agent UI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pong:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/A4WBXVfiGes" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Configure CMake UI:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/hU1uXoRoMXg" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>ai</category>
      <category>a2ui</category>
      <category>programming</category>
      <category>ui</category>
    </item>
    <item>
      <title>I Tried Needle2 for Local Tool Calling. I Ended Up With llama.cpp + Granite</title>
      <dc:creator>Valentyn Ivanov</dc:creator>
      <pubDate>Tue, 01 Sep 2026 19:35:36 +0000</pubDate>
      <link>https://dev.to/valentinivanov/i-tried-needle2-for-local-tool-calling-i-ended-up-with-llamacpp-granite-1e0f</link>
      <guid>https://dev.to/valentinivanov/i-tried-needle2-for-local-tool-calling-i-ended-up-with-llamacpp-granite-1e0f</guid>
      <description>&lt;p&gt;I’ve been working on a small experiment around a semantic shell.&lt;/p&gt;

&lt;p&gt;The basic idea is that the user types something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copy report.pdf to backup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a small local model maps that to a known tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filesystem.copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shell then takes over. It validates arguments, asks for missing ones, shows confirmation UI when needed, and finally executes the operation.&lt;/p&gt;

&lt;p&gt;The model is not supposed to generate shell commands. It only needs to understand intent.&lt;/p&gt;

&lt;p&gt;That sounded like a very good fit for Needle2.&lt;/p&gt;

&lt;p&gt;Needle2 is tiny, focused on tool calling and structured extraction, and designed to run locally. On paper it looked almost purpose-built for what I needed.&lt;/p&gt;

&lt;p&gt;So I tried it.&lt;/p&gt;

&lt;p&gt;The first version worked. Then I started adding more realistic cases.&lt;/p&gt;

&lt;p&gt;And that’s where things became more interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five tools is very different from fifty
&lt;/h2&gt;

&lt;p&gt;Most examples of tool-calling models are some variation of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;turn on the kitchen light
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with two or three tools available.&lt;/p&gt;

&lt;p&gt;That’s fine as an API example, but it doesn’t tell you much about how the model behaves in a real application.&lt;/p&gt;

&lt;p&gt;Even my first filesystem package already had things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filesystem.copy
filesystem.move
filesystem.delete
filesystem.create_file
filesystem.create_directory
filesystem.list_directory
filesystem.navigate
filesystem.current_directory
filesystem.find
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Needle2 uses retrieval when the number of tools gets larger. It selects a small candidate set and then resolves the tool from there.&lt;/p&gt;

&lt;p&gt;That makes sense.&lt;/p&gt;

&lt;p&gt;But it also means there are really two decisions now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which tools should be considered?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which of those tools is the right one?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the correct tool does not make it into the shortlist, the second stage never gets a chance.&lt;/p&gt;

&lt;p&gt;For many applications that may be perfectly acceptable. In my case I wasn’t comfortable relying on it without knowing more about how often it happens.&lt;/p&gt;

&lt;p&gt;I started thinking about bypassing retrieval entirely by dividing tools into groups of five and running all groups.&lt;/p&gt;

&lt;p&gt;Needle is small enough that this is not completely ridiculous.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;group 1 -&amp;gt; result
group 2 -&amp;gt; result
group 3 -&amp;gt; result
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then take the strongest candidate.&lt;/p&gt;

&lt;p&gt;But immediately another question appears.&lt;/p&gt;

&lt;p&gt;Are confidence scores from different candidate groups actually comparable?&lt;/p&gt;

&lt;p&gt;Maybe they are. Maybe they are not.&lt;/p&gt;

&lt;p&gt;I couldn’t find enough information to feel confident about treating them as globally calibrated scores.&lt;/p&gt;

&lt;p&gt;That does not make Needle bad. It just means that once you move away from the demo path, you start needing answers that are not obvious from the examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool descriptions matter a lot
&lt;/h2&gt;

&lt;p&gt;Another thing I learned quickly was how sensitive a small model is to tool descriptions.&lt;/p&gt;

&lt;p&gt;A description like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Moves files from one place to another.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is not enough if the neighboring tools are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filesystem.copy
filesystem.navigate
filesystem.rename
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to be explicit.&lt;/p&gt;

&lt;p&gt;For example, “move” should probably say that the original item no longer remains at the source, and that this is not the same thing as changing the shell’s current directory.&lt;/p&gt;

&lt;p&gt;The descriptions start looking less like documentation and more like a tiny classification dataset written in English.&lt;/p&gt;

&lt;p&gt;That was workable, but it changed how I thought about the model.&lt;/p&gt;

&lt;p&gt;It is less “small agent” and more “probabilistic semantic parser with a constrained vocabulary.”&lt;/p&gt;

&lt;p&gt;Which is actually fine for this use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I tried the C++ runtime
&lt;/h2&gt;

&lt;p&gt;For the shell itself I wanted native integration.&lt;/p&gt;

&lt;p&gt;No Python process on the side, no extra service, and no awkward lifetime management. The C++ library looked like the right way to do it.&lt;/p&gt;

&lt;p&gt;This is where I hit the biggest practical problem.&lt;/p&gt;

&lt;p&gt;I was developing on an Intel Mac.&lt;/p&gt;

&lt;p&gt;The Cactus Engine code contains ARM NEON includes and intrinsics in many places. Not just one isolated backend file, but spread through engine and kernel code.&lt;/p&gt;

&lt;p&gt;That surprised me.&lt;/p&gt;

&lt;p&gt;If ARM is the main target, this is understandable. iOS, Android, and Apple Silicon are all important platforms.&lt;/p&gt;

&lt;p&gt;But from my side it meant x86 support was not just a matter of enabling another optimized backend.&lt;/p&gt;

&lt;p&gt;I ended up spending time patching things simply to answer a much more basic question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is Needle good enough for my use case to justify carrying this dependency?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At that point I decided to try a different route before spending more time on the port.&lt;/p&gt;

&lt;h2&gt;
  
  
  llama.cpp and Granite
&lt;/h2&gt;

&lt;p&gt;So I integrated llama.cpp.&lt;/p&gt;

&lt;p&gt;Then I tried Granite 4 350M for the same tool-calling task.&lt;/p&gt;

&lt;p&gt;I expected this to be more of a baseline than a solution.&lt;/p&gt;

&lt;p&gt;It turned out to work better than I expected.&lt;/p&gt;

&lt;p&gt;For the normal cases it selected the tools I wanted.&lt;/p&gt;

&lt;p&gt;More importantly, I tried a few deliberately awkward inputs where no good tool really existed, and instead of forcing a call it simply failed to find one.&lt;/p&gt;

&lt;p&gt;For my application, that is good behavior.&lt;/p&gt;

&lt;p&gt;I would much rather see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No suitable tool found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;than a confident guess.&lt;/p&gt;

&lt;p&gt;The shell can recover from that.&lt;/p&gt;

&lt;p&gt;It can ask the user to rephrase, narrow the scope, or choose between two possible interpretations.&lt;/p&gt;

&lt;p&gt;A wrong tool call is much harder to recover from once you start dealing with destructive operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  This changed the architecture less than I expected
&lt;/h2&gt;

&lt;p&gt;The funny part is that switching models did not really affect the shell design.&lt;/p&gt;

&lt;p&gt;The important part was already outside the model.&lt;/p&gt;

&lt;p&gt;The flow is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user input
    ↓
intent resolution
    ↓
known semantic capability
    ↓
argument validation
    ↓
ask for missing arguments
    ↓
policy / confirmation
    ↓
execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copy file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the model only needs to resolve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filesystem.copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shell can notice that source and destination are missing and show proper selectors.&lt;/p&gt;

&lt;p&gt;If two tools are plausible, for example copy versus move, the shell can show two buttons.&lt;/p&gt;

&lt;p&gt;There is no need to force the model to solve every ambiguity.&lt;/p&gt;

&lt;p&gt;That ended up being one of the more useful conclusions from the experiment.&lt;/p&gt;

&lt;p&gt;A small local model does not need to be brilliant if the surrounding system is designed to handle uncertainty.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I wish documentation focused on more
&lt;/h2&gt;

&lt;p&gt;I still think Needle2 is interesting.&lt;/p&gt;

&lt;p&gt;What I missed was more information about the edges.&lt;/p&gt;

&lt;p&gt;Not another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;turn on the light
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;example.&lt;/p&gt;

&lt;p&gt;I wanted answers to things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how accuracy changes as the tool catalogue grows;&lt;/li&gt;
&lt;li&gt;how often retrieval drops the correct tool;&lt;/li&gt;
&lt;li&gt;whether confidence remains comparable across different candidate sets;&lt;/li&gt;
&lt;li&gt;how similar tools should be described;&lt;/li&gt;
&lt;li&gt;what happens on no-match input;&lt;/li&gt;
&lt;li&gt;how confidence behaves on incorrect calls;&lt;/li&gt;
&lt;li&gt;how much fine-tuning helps with ambiguous tools;&lt;/li&gt;
&lt;li&gt;what the realistic native-platform support is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those details are not as flashy, but they are what decides whether something works in a real system.&lt;/p&gt;

&lt;p&gt;The same applies to structured extraction.&lt;/p&gt;

&lt;p&gt;Showing that a model can extract an invoice total is useful.&lt;/p&gt;

&lt;p&gt;Showing how it behaves when there are subtotal, tax, total, previous balance, OCR errors, and two dates on the same page is much more useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I am now
&lt;/h2&gt;

&lt;p&gt;For the moment I’m continuing with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llama.cpp
Granite 4 350M
typed semantic tools
deterministic argument resolution
small contextual UI
policy-controlled execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That does not mean Needle2 is a bad model.&lt;/p&gt;

&lt;p&gt;It may be an excellent fit for the platforms and use cases Cactus is targeting.&lt;/p&gt;

&lt;p&gt;It just stopped being the obvious choice for mine.&lt;/p&gt;

&lt;p&gt;And that was probably the main thing I got from the experiment.&lt;/p&gt;

&lt;p&gt;A component can look almost perfect from the feature list and still be the wrong foundation once you start testing the boring parts: portability, failure modes, ambiguity, scaling, and integration cost.&lt;/p&gt;

&lt;p&gt;For this kind of software, I’m becoming much more interested in how a model fails than in how impressive its best demo looks.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>shell</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop Calling Tribal Knowledge “Collaboration”</title>
      <dc:creator>Valentyn Ivanov</dc:creator>
      <pubDate>Fri, 21 Aug 2026 10:45:28 +0000</pubDate>
      <link>https://dev.to/valentinivanov/stop-calling-tribal-knowledge-collaboration-1baj</link>
      <guid>https://dev.to/valentinivanov/stop-calling-tribal-knowledge-collaboration-1baj</guid>
      <description>&lt;p&gt;Developers have a strange relationship with documentation.&lt;/p&gt;

&lt;p&gt;We love well-documented libraries.&lt;/p&gt;

&lt;p&gt;We appreciate clear APIs, useful examples, configuration references, migration notes, architecture diagrams, and a README that tells us what we actually need to know.&lt;/p&gt;

&lt;p&gt;Then we look at our own codebase and suddenly documentation becomes outdated.&lt;/p&gt;

&lt;p&gt;“The code should explain itself.”&lt;/p&gt;

&lt;p&gt;“If you need to know something, just ask.”&lt;/p&gt;

&lt;p&gt;And sometimes teams take this even further.&lt;/p&gt;

&lt;p&gt;They turn the lack of documentation into a virtue. The argument goes something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We don’t document everything because we want developers to communicate with each other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, this sounds reasonable. Software development is collaborative. People should talk. Knowledge shouldn’t live in isolated silos.&lt;/p&gt;

&lt;p&gt;But there is a problem. Asking the same question for the tenth time is not collaboration. It is a missing database query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet John and Jack
&lt;/h3&gt;

&lt;p&gt;John is working on a service he hasn’t touched before. He sees this in the deployment configuration:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MAGIC_SERVICE_MODE=2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There is no comment. No documentation. No example. No explanation in the repository.&lt;/p&gt;

&lt;p&gt;But Jack knows what it means. Jack implemented it three years ago. Unfortunately, Jack lives in another time zone. So John asks him on Slack. Then John waits. Maybe for an hour. Maybe for six.&lt;/p&gt;

&lt;p&gt;Eventually Jack wakes up, reads the message, remembers what the variable means, and answers.&lt;/p&gt;

&lt;p&gt;John continues working. Problem solved. Except it isn’t.&lt;/p&gt;

&lt;p&gt;Two weeks later, Mary encounters the same variable. She asks Jack. A month later, Peter joins the team. He asks Jack. Then a production issue happens and someone from another team asks Jack.&lt;/p&gt;

&lt;p&gt;At this point we should stop pretending this is a healthy communication culture.&lt;/p&gt;

&lt;p&gt;Jack has become infrastructure.&lt;/p&gt;

&lt;p&gt;More specifically, Jack has become a very inefficient distributed database with terrible availability characteristics. And Jack is constantly being interrupted by &lt;code&gt;SELECT&lt;/code&gt; queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication Has a Cost
&lt;/h3&gt;

&lt;p&gt;There is a tendency in software teams to treat communication as free.&lt;/p&gt;

&lt;p&gt;It isn’t.&lt;/p&gt;

&lt;p&gt;Every question has at least two costs.&lt;/p&gt;

&lt;p&gt;The person asking has to stop what they are doing and wait for an answer. The person answering has to stop what they are doing and reconstruct the context.&lt;/p&gt;

&lt;p&gt;Sometimes that cost is tiny. Sometimes it destroys half an hour of concentration. Now multiply this across a team.&lt;/p&gt;

&lt;p&gt;“What does this environment variable mean?”&lt;/p&gt;

&lt;p&gt;“Which database do we use in staging?”&lt;/p&gt;

&lt;p&gt;“Why is this timeout set to 17 seconds?”&lt;/p&gt;

&lt;p&gt;“Can I run this service locally?”&lt;/p&gt;

&lt;p&gt;“Which of these three endpoints is still supported?”&lt;/p&gt;

&lt;p&gt;“Why can’t this component be deployed independently?”&lt;/p&gt;

&lt;p&gt;“Who owns this?”&lt;/p&gt;

&lt;p&gt;If these questions are asked once, that is normal. If they are asked repeatedly, the problem is not communication. The problem is missing documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation Does Not Replace Communication
&lt;/h3&gt;

&lt;p&gt;This is the part that often gets lost. Good documentation is not an alternative to communication. It creates space for better communication. There are things developers absolutely should discuss.&lt;/p&gt;

&lt;p&gt;Should we split this service?&lt;/p&gt;

&lt;p&gt;What consistency guarantees does this protocol need?&lt;/p&gt;

&lt;p&gt;Should this API be synchronous or asynchronous?&lt;/p&gt;

&lt;p&gt;What are the failure modes of this architecture?&lt;/p&gt;

&lt;p&gt;How do we migrate this without downtime?&lt;/p&gt;

&lt;p&gt;What trade-off are we making between latency and complexity?&lt;/p&gt;

&lt;p&gt;These are valuable conversations because the answer does not already exist. The participants are creating something new together.&lt;/p&gt;

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

&lt;p&gt;Asking someone what an environment variable means is not collaboration. It is information retrieval. And information retrieval should usually not require another human being.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tribal Knowledge Feels Fast Until It Doesn’t
&lt;/h3&gt;

&lt;p&gt;A poorly documented team can actually feel very productive for a while. Everyone knows everything. The original developers sit next to each other. Questions get answered in seconds. Decisions happen verbally. Nobody wastes time writing things down. Great velocity.&lt;/p&gt;

&lt;p&gt;Then the team grows. People leave. People work remotely. A service moves to another team. Someone goes on vacation. Someone gets sick. A new developer joins. Now the invisible dependency graph becomes visible. Half the system depends on three people remembering why things work the way they do.&lt;/p&gt;

&lt;p&gt;The organization discovers that what looked like velocity was actually borrowing against the future.&lt;/p&gt;

&lt;p&gt;And now the interest is due.&lt;/p&gt;

&lt;h3&gt;
  
  
  “The Code Should Be Self-Documenting”
&lt;/h3&gt;

&lt;p&gt;There is some truth in this idea.&lt;/p&gt;

&lt;p&gt;Good names matter. Clear abstractions matter. Readable code matters. Comments should not explain what perfectly obvious code already says.&lt;/p&gt;

&lt;p&gt;But code can only explain so much.&lt;/p&gt;

&lt;p&gt;Code can tell you what it does. It often cannot tell you why it exists. It cannot always explain why another seemingly simpler approach was rejected. It cannot explain operational assumptions. It cannot explain which weird production incident caused that strange validation rule. It cannot tell a new developer which parts of the system are historical leftovers and which ones are intentional architecture.&lt;/p&gt;

&lt;p&gt;And it certainly cannot explain what &lt;code&gt;MAGIC_SERVICE_MODE=2&lt;/code&gt; means to someone who does not already know.&lt;/p&gt;

&lt;p&gt;The best code and the best documentation solve different problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  “But Documentation Gets Outdated”
&lt;/h3&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;So does code. So do tests. So do dependencies. So do deployment scripts.&lt;/p&gt;

&lt;p&gt;We do not stop writing tests because they might become outdated. We maintain them because they are useful.&lt;/p&gt;

&lt;p&gt;Documentation should be treated the same way.&lt;/p&gt;

&lt;p&gt;The real question is not whether documentation can become stale. The question is whether the cost of maintaining it is lower than the cost of repeatedly rediscovering the same knowledge.&lt;/p&gt;

&lt;p&gt;For important parts of a system, the answer is very often yes.&lt;/p&gt;

&lt;p&gt;And documentation does not need to mean a thousand-page specification. Sometimes the right documentation is five lines next to the configuration. Sometimes it is a short ADR. Sometimes it is a diagram. Sometimes it is a README explaining how to run the service. Sometimes it is one sentence saying: &lt;code&gt;MAGIC_SERVICE_MODE=2&lt;/code&gt; enables compatibility mode for the legacy billing pipeline. Do not change it without coordinating with Billing.&lt;/p&gt;

&lt;p&gt;That sentence might save hours of future interruptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Goal Is Not More Documentation
&lt;/h3&gt;

&lt;p&gt;This is important too.&lt;/p&gt;

&lt;p&gt;The goal is not to produce documentation for its own sake. Nobody needs another abandoned wiki full of pages nobody reads.&lt;/p&gt;

&lt;p&gt;The goal is to remove unnecessary dependence on human memory. Write down the things people repeatedly need. Write down the things that are surprising. Write down decisions whose reasoning will otherwise disappear. Write down operational knowledge that someone will desperately need at 2 AM. Write down information that crosses team boundaries.&lt;/p&gt;

&lt;p&gt;And keep it close to the thing it describes whenever possible.&lt;/p&gt;

&lt;p&gt;Documentation is not bureaucracy when it prevents the same question from being asked fifty times.&lt;/p&gt;

&lt;p&gt;It is a productivity tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let People Talk About New Things
&lt;/h3&gt;

&lt;p&gt;A healthy engineering culture should absolutely encourage communication.&lt;/p&gt;

&lt;p&gt;But communication is a limited resource.&lt;/p&gt;

&lt;p&gt;Spend it well.&lt;/p&gt;

&lt;p&gt;Do not spend your senior developer’s attention explaining for the twentieth time how to start the staging environment.&lt;/p&gt;

&lt;p&gt;Do not make a new engineer wait until someone in California wakes up to understand a configuration flag.&lt;/p&gt;

&lt;p&gt;Do not confuse access to tribal knowledge with collaboration.&lt;/p&gt;

&lt;p&gt;Document the things we already know. Then use the time we saved to discuss the things we don’t know yet.&lt;/p&gt;

&lt;p&gt;That is where communication becomes valuable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation doesn’t replace communication. It buys time for better collaboration.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
