<?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: Jordan Henderson</title>
    <description>The latest articles on DEV Community by Jordan Henderson (@jordanh).</description>
    <link>https://dev.to/jordanh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2659791%2F0cccb2ed-eeed-4c25-b91d-fb6b5ec9b872.jpg</url>
      <title>DEV Community: Jordan Henderson</title>
      <link>https://dev.to/jordanh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jordanh"/>
    <language>en</language>
    <item>
      <title>Everbench: A document management system with Local Intelligence</title>
      <dc:creator>Jordan Henderson</dc:creator>
      <pubDate>Mon, 25 May 2026 05:38:48 +0000</pubDate>
      <link>https://dev.to/jordanh/everbench-a-document-management-system-with-local-intelligence-5fj8</link>
      <guid>https://dev.to/jordanh/everbench-a-document-management-system-with-local-intelligence-5fj8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Everbench
&lt;/h3&gt;

&lt;p&gt;For more background, &lt;a href="https://dev.to/jordanh/an-introduction-and-my-gemma-4-challenge-submission-2i82"&gt;here's&lt;/a&gt; a link to an extended blog post.&lt;/p&gt;

&lt;p&gt;Everbench is a low-cost, efficient document research platform for those concerned about privacy.&lt;/p&gt;

&lt;p&gt;I've been working on a project I called Everknown.  It would be an Open Source Evernote replacement.  Lately, I've stalled on that, having discovered a commercial service that had most of what I wanted, but I have the bones of the app developed and, when I saw this challenge, I decided to put together a small version of Everknown for link/bookmark management and page summarization functions, two of the things that Everknown was going to do for me.&lt;/p&gt;

&lt;p&gt;Thus, the odd name Everbench.  It's a "workbench" for Everknown.  It has a very simple architecture, but that's good!  Small, composable software that can be modified easily to fit needs.&lt;/p&gt;

&lt;p&gt;Everbench conveniently captures web pages, efficiently converts them to Markdown for storage in an Obsidian Vault, creating a summary and tags for categorization.  It uses an efficient HTML-&amp;gt;MD conversion written in C with a Gemma 4 quality gate to check if the conversion was successful.  Some pages can't be converted (paywalls, login walls, empty SPA shells, mostly-navigation pages, etc.) but Gemma 4 can quickly determine that and characterize the failures.  I've found that if the conversion fails, the page has serious problems.&lt;/p&gt;

&lt;p&gt;Using a deterministic C parser isn't just about extraction quality; it's also a small security boundary. The parser strips &amp;lt;script&amp;gt;, &amp;lt;style&amp;gt;,&lt;br&gt;
&amp;lt;noscript&amp;gt;, and CSS-hidden content before anything reaches Gemma 4, so the model never sees what the page is hiding from the user. Feeding raw HTML to an LLM is an open invitation for prompt injection via hidden divs, alt text, JavaScript-emitted content, or whatever the next clever trick happens to be. Prompt injection can be a significant challenge, but we have a place here in processing to insert heuristics to actively guard against it. Gumbo lets me reason about what crosses that boundary.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&amp;lt;!-- Embed a video walkthrough or share a link to your deployed project. --&amp;gt; &lt;a href="https://youtu.be/AYHjIB7VXto" rel="noopener noreferrer"&gt;Here's a link to the video walkthrough&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;p&gt;&lt;a href="https://github.com/jordanlhenderson/everbench" rel="noopener noreferrer"&gt;Everbench&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;



&lt;p&gt;Gemma 4 is used for document summarization and categorization, but the novel use of it is as a quality gate for the output from the Gumbo C HTML parser.&lt;/p&gt;

&lt;p&gt;The prompt given to Gemma 4 is currently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are evaluating whether a web page was successfully extracted into readable Markdown.

URL: &amp;lt;captured url&amp;gt;
Title: &amp;lt;captured title&amp;gt;

Extracted Markdown (first 2000 chars):
&amp;lt;extracted markdown&amp;gt;

Decide if this extraction is GOOD or BAD.

GOOD means: the main article content is present and readable.
BAD means: the content is mostly navigation, advertising, login walls, JavaScript placeholders, or otherwise unusable as a reference.

Respond in exactly this format:
VERDICT: GOOD|BAD
REASON: &amp;lt;one short sentence&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model is not the processing pipeline; it is the judge inside the pipeline.&lt;/p&gt;

&lt;p&gt;In Everknown, I had intended to use local and cloud models for LLM work, interchangeably, configured where it made sense.  In Everbench, I just needed an LLM that could categorize (via tags) and summarize documents well.   I found Gemma-4-26B-E4B to be excellent at that. The smaller models didn't do a very good job at some of the things I needed an LLM for, and 31B was too slow and not notably better.&lt;/p&gt;

&lt;p&gt;Locally, I can only run one model at a time and I'm hoping that Gemma-4-26B-E4B with its MoE architecture will work out as a good general-purpose local model that I might be able to get some agentic tool-using work out of as I expand projects.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
    <item>
      <title>An Introduction, and my Gemma 4 Challenge Submission</title>
      <dc:creator>Jordan Henderson</dc:creator>
      <pubDate>Sun, 24 May 2026 15:16:21 +0000</pubDate>
      <link>https://dev.to/jordanh/an-introduction-and-my-gemma-4-challenge-submission-2i82</link>
      <guid>https://dev.to/jordanh/an-introduction-and-my-gemma-4-challenge-submission-2i82</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is not my Gemma 4 challenge submission.  This is my first blog post and a pointer to my Gemma 4 challenge submission.&lt;/p&gt;

&lt;p&gt;I wanted to rant freely about background and philosophy and not tire the contest judges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/jordanh/everbench-a-document-management-system-with-local-intelligence-5fj8"&gt;Submission Link&lt;/a&gt;&lt;br&gt;
&lt;a href="https://youtu.be/AYHjIB7VXto" rel="noopener noreferrer"&gt;Video Link&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/jordanlhenderson/everbench" rel="noopener noreferrer"&gt;Repo Link&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;First, a little about me. I’m an old programmer. I learned programming in Pascal, Fortran 77, and Lisp back in the late 70s. I got involved in C and Unix early and then spent years doing VMS (later named OpenVMS) and Unix in control-system software.&lt;/p&gt;

&lt;p&gt;In the intervening years, I've used SNOBOL4, C++, Java, JS, Perl, Tcl, Lua, and probably a number of other languages that don't immediately come to mind.&lt;/p&gt;

&lt;p&gt;I've seen a lot of fads and trends pass.&lt;/p&gt;
&lt;h2&gt;
  
  
  Churn, Objects, and Interfaces
&lt;/h2&gt;

&lt;p&gt;One thing that has disturbed me is all the churn in the software landscape.  Just when a language or technology starts to get traction, when the tooling gets really good and it seems like progress can be made, it gets supplanted by the latest thing that offers not much more than novelty.&lt;/p&gt;

&lt;p&gt;I think software vendors and academia are somewhat to blame here.  Vendors make more money on new systems and academics can't publish on established technologies.&lt;/p&gt;

&lt;p&gt;Open source has helped counteract this. Commercial software often has to sell the next migration. Academic work often has to emphasize novelty. Open source can preserve useful work long after the fashion cycle has moved on.&lt;/p&gt;

&lt;p&gt;A good open-source library can be improved, audited, ported, wrapped, and reused for decades. That matters to me. Some of the most valuable software in the world is not glamorous. It is boring, portable, well-tested code that sits underneath everything else.&lt;/p&gt;

&lt;p&gt;That is one reason I keep coming back to C libraries. A good C library is often boring in the best sense. It does one job, has been used for years, and can be wrapped without dragging in a whole new world.&lt;/p&gt;

&lt;p&gt;I'll say it out loud: object-oriented programming as the only paradigm is oversold.  Everything does not need to be modeled as an object. Object-oriented languages may treat numbers, strings, and functions as objects, and that can make for pleasant syntax. But pleasant syntax is not the same thing as a good system model.&lt;/p&gt;

&lt;p&gt;Object-oriented languages have their place. They grew partly out of simulation work, and simulations are a natural home for them.&lt;/p&gt;

&lt;p&gt;I won't deny some good things have come from the obsession with object orientation: It has led to a deep commitment to abstraction and encapsulation.  It has also led to massive brittle hierarchies of method invocations and factories that obscure solutions.  A deep commitment to abstraction is what we need.  Deep object hierarchies that are only very narrowly useful are not what we need.&lt;/p&gt;

&lt;p&gt;I prefer abstract data types, ADTs, over classical object hierarchies.  I like Rob Pike's software design principles (&lt;a href="https://www.lysator.liu.se/c/pikestyle.html" rel="noopener noreferrer"&gt;https://www.lysator.liu.se/c/pikestyle.html&lt;/a&gt;).&lt;br&gt;
Here we read:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I argue that clear use of function pointers is the heart of object-oriented programming.  Given a set of operations you want to perform on data, and a set of data types you want to respond to those operations, the easiest way to put the program together is with a group of function pointers for each type.  This, in a nutshell, defines class and method.  The OO languages give you more of course - prettier syntax, derived types and so on - but conceptually they provide little extra."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That preference also fits Tony Hoare’s maxim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"There are two methods in software design. One is to make the program so simple, there are obviously no errors. The other is to make it so complicated, there are no obvious errors."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;APIs are a good direction in software.  They generally implement ADTs in one way or another, so that's a good thing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Scheme and C
&lt;/h2&gt;

&lt;p&gt;Lately, I've been working with Agents in hobbyist programming, mostly Claude, but I've also used codex, Gemini and even OpenCode with various LLMs backing them.&lt;/p&gt;

&lt;p&gt;I've always been attracted to the simplicity of Lisp-like languages and Scheme. They are excellent for programming with ADTs.&lt;/p&gt;

&lt;p&gt;Legacy Software is a Great Good.&lt;/p&gt;

&lt;p&gt;I know "legacy" is often used as a pejorative. But software that has survived real use, real bugs, real ports, real users, and real abuse has earned a kind of trust that new software has not earned yet. That is one reason I keep coming back to proven Open Source C libraries.&lt;/p&gt;

&lt;p&gt;Putting this all together, I’ve been building a platform of Scheme with C FFI (Foreign Function Interfaces) into simple composable software.  I chose &lt;a href="https://synthcode.com/wiki/chibi-scheme" rel="noopener noreferrer"&gt;Chibi-Scheme&lt;/a&gt; for the high-level language and settled on libraries that are compatible with C11 as a minimum standard there.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Opportunity with Agent-Assisted Programming
&lt;/h2&gt;

&lt;p&gt;I'm impressed by the abilities of LLMs.  They code well enough and handle so many of the chores of programming that often bog down development.  I think I make great progress toward goals using agent assistants. &lt;/p&gt;

&lt;p&gt;The Chrome extension in this project is a small concrete example. MV3,&lt;br&gt;
~150 lines of JavaScript, hotkey capture and a JSON POST to the local server — I one-shotted it with Claude. It took longer to test than to&lt;br&gt;
build. That kind of leverage on a small, well-defined component is where&lt;br&gt;
I think these tools shine. Not "build me a system," but "build me this&lt;br&gt;
sharp tool that does one thing." Everbench is several of those stitched&lt;br&gt;
together.&lt;/p&gt;

&lt;p&gt;I'm not a believer in the imminent arrival of the Singularity or that LLMs will replace developers.  LLMs don't want anything and goals are a bad substitute for desires.  I believe humans will be in the loop creating with these new tools. If they aren't, we're obsolete anyway. Either way, we may as well act like humans still matter.&lt;/p&gt;

&lt;p&gt;I see the opportunity with these tools is not creating grander and more elaborate software, but rather to simplify, to create powerful tools for specific purposes, run endless tests and learning loops, finding what works best and modifying code to improve it along every desired axis.&lt;/p&gt;

&lt;p&gt;I hope there's a hint of that in my submission.&lt;/p&gt;
&lt;h2&gt;
  
  
  Everknown and Everbench
&lt;/h2&gt;

&lt;p&gt;Mostly, I've just tooled around, first trying this thing and then that.  I started working on a project I called Everknown.  It would be an Open Source Evernote replacement.  Lately, I've stalled on that, having discovered a commercial service that had most of what I wanted, but I have the bones of the app developed and, when I saw this challenge, I decided to put together a small version of Everknown for link/bookmark management and page summarization functions, two of the things that Everknown was going to do for me.&lt;/p&gt;

&lt;p&gt;Thus, the odd name Everbench.  It's a "workbench" for Everknown.  It has a very simple architecture, but that's good!  Small, composable software that can be modified easily to fit needs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Gemma 4
&lt;/h2&gt;

&lt;p&gt;In Everknown, I had intended to use local and cloud models for LLM work, interchangeably, configured where it made sense.  Here, I just needed an LLM that could categorize (via tags) and summarize documents well.   I found Gemma-4-26B-E4B to be excellent at that. The smaller models didn't do a very good job at some of the things I needed an LLM for, and 31B was too slow and not notably better.&lt;/p&gt;

&lt;p&gt;Locally, I can only run one model at a time and I'm hoping that Gemma-4-26B-E4B with its MoE architecture will work out as a good general-purpose local model that I might be able to get some agentic tool-using work out of as I expand projects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Everbench Architecture
&lt;/h2&gt;

&lt;p&gt;Below is a simple overview of the Everbench architecture.&lt;/p&gt;

&lt;p&gt;It's all very simple, composed of small pieces I've built on top of well-established C libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Chrome extension          Local HTTP server        SQLite queue
   +--------------+          +--------------+         +--------------+
   | Ctrl+Shift+E | -------&amp;gt; |  /capture    | ------&amp;gt; |   queue      |
   | grabs HTML   |  POST    |  /export/:id |         |  (pending /  |
   +--------------+          |  /retry/:id  |         |   done /     |
                             |  review UI   | &amp;lt;------ |   failed)    |
                             +--------------+  reads  +--------------+
                                                            |
                                                            | drains
                                                            v
                              +-----------------------------------------+
                              |             Worker daemon               |
                              |                                         |
                              |   Gumbo_MD -&amp;gt; Markdown                  |
                              |   Gemma 4   - quality gate (GOOD / BAD) |
                              |   Gemma 4   - summarize                 |
                              |   Gemma 4   - tag                       |
                              +-----------------------------------------+
                                                            |
                                                            | approved
                                                            v
                                                  +------------------+
                                                  |  Obsidian vault  |
                                                  |  *.md + YAML     |
                                                  +------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Chrome Extension
&lt;/h3&gt;

&lt;p&gt;MV3, ~150 lines of JavaScript. Ctrl+Shift+E grabs the active tab's HTML and POSTs {url, title, html} to the local server. One-shotted with Claude (see above).&lt;/p&gt;

&lt;h3&gt;
  
  
  Bloschi
&lt;/h3&gt;

&lt;p&gt;Bloschi is my port of Blosxom, a very old, very simple blogging platform built on files, not databases, but supporting page skins.  For this project, I added some POST endpoints that the Scheme processing loop of Bloschi handles.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQLite interfaces
&lt;/h3&gt;

&lt;p&gt;SQLite is a prime example of the legacy of powerful C code that is very well-tested and reliable.  It is now the most popular DB software in the world, used in literally millions of desktop and mobile applications.&lt;/p&gt;

&lt;p&gt;Note that in the LLM agent programming world, if you find you need a different RDBMS, it is typically a few hours' work with an agent to drop in PostgreSQL or something else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gumbo
&lt;/h3&gt;

&lt;p&gt;I believe Gumbo is one of the best C libraries for HTML parsing. I've created a Scheme FFI to Gumbo and also modified the C core to perform robust HTML-to-Markdown conversion. I call this piece Gumbo_MD.&lt;/p&gt;

&lt;p&gt;In developing this app, I reviewed many web pages and refined Gumbo_MD to perform better extractions.  I believe that a goal-directed loop could be set up with agentic programming to refine this further, but at this point, Gumbo_MD appears to do a great job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality Gate
&lt;/h3&gt;

&lt;p&gt;This is an important use of Gemma 4 in this project.  I could have had Gemma 4 produce the Markdown, but would it have been any good, and would I have had to employ a more powerful model to judge it? By producing Markdown deterministically with Gumbo_MD and only calling on the model to judge the result, I believe I've produced a sharp tool in Gumbo_MD and saved work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summarize and Tagging
&lt;/h3&gt;

&lt;p&gt;Gemma-4-26B-E4B does an excellent job summarizing articles and generating tags. I mentioned this above, but it bears repeating: Gemma 4 31B did a good job here, but not notably better, and it was much slower.&lt;/p&gt;

&lt;p&gt;Even if you can't run Gemma-4-26B-E4B on your own hardware, models in this class should be inexpensive to use through inference providers. For the document conversions I'm doing, the API cost should be a fraction of a penny per article. These models will probably keep getting cheaper and more capable.&lt;/p&gt;

&lt;p&gt;If you need local inference for privacy and control, the hardware to support this is increasingly in reach.&lt;/p&gt;

&lt;p&gt;The three Gemma 4 calls per page are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quality gate&lt;/strong&gt;: Is this actually an article, or is it ads, a login wall, an empty SPA shell, or otherwise unusable? It returns &lt;code&gt;GOOD&lt;/code&gt; or &lt;code&gt;BAD&lt;/code&gt; with a specific reason.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Summarize&lt;/strong&gt;: Distill the page into a short paragraph.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tag&lt;/strong&gt;: Generate three to five specific topical tags.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Approved entries get a button to export to an Obsidian vault as Markdown with YAML frontmatter. Failed entries show why they were rejected, so I can see when the gate is working and when the extractor needs tuning.&lt;/p&gt;

&lt;p&gt;Obsidian was a natural target because the notes are plain Markdown files. I wanted Everbench to produce something I could keep, search, edit, and move around without trapping the result inside another application.&lt;/p&gt;

&lt;p&gt;There is interesting work going on around hooking Obsidian into agentic workflows, and I hope to take advantage of that later.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
