<?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>Forem: Harry Wynn</title>
    <description>The latest articles on Forem by Harry Wynn (@harrywynn).</description>
    <link>https://forem.com/harrywynn</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%2F3608210%2Fbf666c2a-ecf3-4d89-81c1-0fc8fe2ed30f.png</url>
      <title>Forem: Harry Wynn</title>
      <link>https://forem.com/harrywynn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/harrywynn"/>
    <language>en</language>
    <item>
      <title>Why I Built My Own MySQL Client for macOS (SQL Gnome)</title>
      <dc:creator>Harry Wynn</dc:creator>
      <pubDate>Mon, 13 Apr 2026 16:02:25 +0000</pubDate>
      <link>https://forem.com/harrywynn/why-i-built-my-own-mysql-client-for-macos-sql-gnome-n6i</link>
      <guid>https://forem.com/harrywynn/why-i-built-my-own-mysql-client-for-macos-sql-gnome-n6i</guid>
      <description>&lt;p&gt;I’ve been building software professionally for more than 25 years, and like most developers, I spend a lot of time inside databases. MySQL in particular shows up everywhere: analytics systems, internal tools, production apps, and quick debugging sessions.&lt;/p&gt;

&lt;p&gt;Over the years I’ve used a lot of database clients. Some were good. Some were frustrating. Eventually I reached a point where I kept thinking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Why does this feel harder than it should?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question is what led me to build &lt;strong&gt;SQL Gnome&lt;/strong&gt;, a native MySQL client for macOS focused on speed and simplicity.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With Existing Tools
&lt;/h2&gt;

&lt;p&gt;Most database clients fall into one of a few categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Electron apps
&lt;/h3&gt;

&lt;p&gt;A lot of modern tools are built with Electron. That’s not inherently bad, but it often means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;high memory usage&lt;/li&gt;
&lt;li&gt;slow startup&lt;/li&gt;
&lt;li&gt;UI lag when browsing large tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you're opening a database client dozens of times a day, those little delays add up.&lt;/p&gt;




&lt;h3&gt;
  
  
  Feature overload
&lt;/h3&gt;

&lt;p&gt;Some clients try to do everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;schema design&lt;/li&gt;
&lt;li&gt;migrations&lt;/li&gt;
&lt;li&gt;visual query builders&lt;/li&gt;
&lt;li&gt;dashboards&lt;/li&gt;
&lt;li&gt;collaboration layers&lt;/li&gt;
&lt;li&gt;cloud integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For some teams that’s great.&lt;/p&gt;

&lt;p&gt;But most of the time I just want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run queries&lt;/li&gt;
&lt;li&gt;browse tables&lt;/li&gt;
&lt;li&gt;inspect results&lt;/li&gt;
&lt;li&gt;move on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The extra complexity ends up getting in the way.&lt;/p&gt;




&lt;h3&gt;
  
  
  Subscription fatigue
&lt;/h3&gt;

&lt;p&gt;Another trend is database clients moving to subscription pricing.&lt;/p&gt;

&lt;p&gt;For teams that makes sense. But for individual developers, it can feel strange paying monthly just to run SQL queries.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Wanted Instead
&lt;/h2&gt;

&lt;p&gt;When I started thinking about building my own client, I kept coming back to a few simple goals.&lt;/p&gt;

&lt;p&gt;I wanted something that was:&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;launches instantly&lt;/li&gt;
&lt;li&gt;runs queries without lag&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Simple
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clean interface&lt;/li&gt;
&lt;li&gt;minimal setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Native
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;built specifically for macOS&lt;/li&gt;
&lt;li&gt;not a cross-platform wrapper&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Focused
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;query execution&lt;/li&gt;
&lt;li&gt;table browsing&lt;/li&gt;
&lt;li&gt;result inspection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No dashboards.&lt;br&gt;&lt;br&gt;
No workflow engines.&lt;br&gt;&lt;br&gt;
No unnecessary complexity.&lt;/p&gt;

&lt;p&gt;Just a solid tool for working with MySQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  How SQL Gnome Works
&lt;/h2&gt;

&lt;p&gt;The goal with &lt;strong&gt;SQL Gnome&lt;/strong&gt; is to make working with MySQL quick and straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect to a database
&lt;/h3&gt;

&lt;p&gt;Add your connection details and connect instantly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cxb13rzt0urok7qipy4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cxb13rzt0urok7qipy4.webp" alt="SQL Gnome Conenction Screen" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Run queries quickly
&lt;/h3&gt;

&lt;p&gt;Write your SQL and execute it immediately.&lt;/p&gt;

&lt;p&gt;The editor is intentionally minimal and focused on speed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3o4r4zz0ofk7m8gpoy7.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3o4r4zz0ofk7m8gpoy7.webp" alt="SQL Gnome Query Screen" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Browse tables
&lt;/h3&gt;

&lt;p&gt;You can quickly explore schemas and inspect table contents without needing to write queries for everything.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4li7sskakflavtkrmwry.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4li7sskakflavtkrmwry.webp" alt="SQL Gnome Content Screen" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Explore table structure
&lt;/h3&gt;

&lt;p&gt;Understanding a database quickly often starts with understanding its schema.&lt;/p&gt;

&lt;p&gt;SQL Gnome lets you inspect table structure instantly — columns, data types, keys, and indexes — without writing &lt;code&gt;DESCRIBE&lt;/code&gt; or &lt;code&gt;SHOW CREATE TABLE&lt;/code&gt; queries.&lt;/p&gt;

&lt;p&gt;This makes it easy to understand unfamiliar databases or debug schema issues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxgg1ok1ngj4dlzy5i3w.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxgg1ok1ngj4dlzy5i3w.webp" alt="SQL Gnome Structure Screen" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why the Name "SQL Gnome"?
&lt;/h2&gt;

&lt;p&gt;Honestly?&lt;/p&gt;

&lt;p&gt;I like tools with personality.&lt;/p&gt;

&lt;p&gt;Not every development tool has to look like a corporate dashboard.&lt;/p&gt;

&lt;p&gt;The idea was a small, helpful tool that quietly does its job while you focus on your work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned While Building It
&lt;/h2&gt;

&lt;p&gt;Building a developer tool teaches you a lot about what developers actually care about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Speed matters more than features
&lt;/h3&gt;

&lt;p&gt;Developers forgive missing features.&lt;/p&gt;

&lt;p&gt;They don't forgive slow tools.&lt;/p&gt;




&lt;h3&gt;
  
  
  Simplicity is surprisingly hard
&lt;/h3&gt;

&lt;p&gt;Adding features is easy.&lt;/p&gt;

&lt;p&gt;Deciding &lt;strong&gt;what not to build&lt;/strong&gt; takes much more discipline.&lt;/p&gt;




&lt;h3&gt;
  
  
  Small details matter
&lt;/h3&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keyboard shortcuts&lt;/li&gt;
&lt;li&gt;query formatting&lt;/li&gt;
&lt;li&gt;scrolling behavior&lt;/li&gt;
&lt;li&gt;rendering large result sets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers notice these details immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try SQL Gnome
&lt;/h2&gt;

&lt;p&gt;SQL Gnome is still early, and I’m continuing to improve it based on feedback.&lt;/p&gt;

&lt;p&gt;If you spend a lot of time working in MySQL, I’d love to hear what would make a tool like this better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download SQL Gnome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://sqlgnome.com" rel="noopener noreferrer"&gt;https://sqlgnome.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback and suggestions are very welcome.&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>devtools</category>
      <category>programming</category>
      <category>swift</category>
    </item>
    <item>
      <title>Why Most Applicant Tracking Systems Are Overkill for Small Teams (So I Built My Own)</title>
      <dc:creator>Harry Wynn</dc:creator>
      <pubDate>Sun, 08 Mar 2026 20:06:56 +0000</pubDate>
      <link>https://forem.com/harrywynn/why-most-applicant-tracking-systems-are-overkill-for-small-teams-so-i-built-my-own-3191</link>
      <guid>https://forem.com/harrywynn/why-most-applicant-tracking-systems-are-overkill-for-small-teams-so-i-built-my-own-3191</guid>
      <description>&lt;p&gt;After 25 years building software and working with recruiting systems, I've developed a strong opinion about ATS platforms:&lt;/p&gt;

&lt;p&gt;Most of them are &lt;strong&gt;wildly overbuilt for what small teams actually need.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Startups and small agencies usually just want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;track candidates&lt;/li&gt;
&lt;li&gt;move them through a pipeline&lt;/li&gt;
&lt;li&gt;search resumes&lt;/li&gt;
&lt;li&gt;leave notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead they get massive enterprise systems full of CRM layers, automation engines, and reporting dashboards nobody uses.&lt;/p&gt;

&lt;p&gt;So I decided to build something different:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An open source ATS designed specifically for small teams.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I call it &lt;strong&gt;&lt;a href="https://hiregnome.com" rel="noopener noreferrer"&gt;Hire Gnome&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Modern ATS Platforms Are Built for Enterprises
&lt;/h2&gt;

&lt;p&gt;If you've worked with systems like Bullhorn, Greenhouse, Lever, or Workday, you know the pattern.&lt;/p&gt;

&lt;p&gt;They are designed around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;large recruiting teams
&lt;/li&gt;
&lt;li&gt;complex workflows
&lt;/li&gt;
&lt;li&gt;heavy integrations
&lt;/li&gt;
&lt;li&gt;enterprise reporting requirements
&lt;/li&gt;
&lt;li&gt;expensive licensing models
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that complexity trickles down to smaller organizations that don't actually need it.&lt;/p&gt;

&lt;p&gt;Typical small-team requirements are much simpler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track candidates&lt;/li&gt;
&lt;li&gt;Store resumes&lt;/li&gt;
&lt;li&gt;Move people through a hiring pipeline&lt;/li&gt;
&lt;li&gt;Add notes&lt;/li&gt;
&lt;li&gt;Search candidates&lt;/li&gt;
&lt;li&gt;Maybe collaborate with one or two other people&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;But instead they end up paying for systems that include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;complex permission models&lt;/li&gt;
&lt;li&gt;giant CRM layers&lt;/li&gt;
&lt;li&gt;sales pipelines&lt;/li&gt;
&lt;li&gt;automation engines&lt;/li&gt;
&lt;li&gt;enterprise compliance tooling&lt;/li&gt;
&lt;li&gt;reporting dashboards nobody actually uses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is &lt;strong&gt;tools that are expensive, slow, and hard to customize.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Idea: A Simple ATS That Developers Can Actually Run
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgg1eicb3iuuz9yhm0d8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgg1eicb3iuuz9yhm0d8.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core idea behind Hire Gnome is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An ATS that developers can run themselves.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of SaaS lock-in, the project is designed around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;self-hosting&lt;/li&gt;
&lt;li&gt;open source transparency&lt;/li&gt;
&lt;li&gt;simple architecture&lt;/li&gt;
&lt;li&gt;easy customization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mental model is closer to tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plausible analytics&lt;/li&gt;
&lt;li&gt;Metabase&lt;/li&gt;
&lt;li&gt;Ghost&lt;/li&gt;
&lt;li&gt;Outline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install it, run it, own your data.&lt;/p&gt;

&lt;p&gt;Small teams get a lightweight ATS.&lt;/p&gt;

&lt;p&gt;Developers get something they can extend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Design Principles
&lt;/h2&gt;

&lt;p&gt;Before writing code, I wrote down a few rules the project had to follow.&lt;/p&gt;

&lt;p&gt;These guardrails have helped keep the scope from exploding.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Simple First
&lt;/h3&gt;

&lt;p&gt;If a feature doesn't help a small team hire someone faster, it probably doesn't belong.&lt;/p&gt;

&lt;p&gt;That eliminates a surprising amount of ATS complexity.&lt;/p&gt;

&lt;p&gt;No giant CRM layer.&lt;/p&gt;

&lt;p&gt;No unnecessary automation engine.&lt;/p&gt;

&lt;p&gt;No 50-step workflow configuration.&lt;/p&gt;

&lt;p&gt;Just a pipeline and candidates moving through it.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Search Matters More Than Everything Else
&lt;/h3&gt;

&lt;p&gt;One of the biggest frustrations with ATS systems is &lt;strong&gt;bad search&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Recruiters often rely on keyword matching that fails constantly.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Frontend engineer with modern JavaScript frameworks"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the resume says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"React developer"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Traditional ATS search misses this.&lt;/p&gt;

&lt;p&gt;Hire Gnome is being built with &lt;strong&gt;semantic search as a first-class feature&lt;/strong&gt;, not an afterthought.&lt;/p&gt;

&lt;p&gt;This is an area where modern AI tooling actually makes a meaningful difference.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Developers Should Be Able to Extend It
&lt;/h3&gt;

&lt;p&gt;Most ATS systems are black boxes.&lt;/p&gt;

&lt;p&gt;If you want to integrate something custom — good luck.&lt;/p&gt;

&lt;p&gt;Hire Gnome is intentionally built so developers can easily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add integrations&lt;/li&gt;
&lt;li&gt;modify workflows&lt;/li&gt;
&lt;li&gt;extend the data model&lt;/li&gt;
&lt;li&gt;build custom reporting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means keeping the architecture straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture (So Far)
&lt;/h2&gt;

&lt;p&gt;The current stack is intentionally boring.&lt;/p&gt;

&lt;p&gt;That's a good thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;A Node.js service responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;candidate CRUD&lt;/li&gt;
&lt;li&gt;pipeline management&lt;/li&gt;
&lt;li&gt;search indexing&lt;/li&gt;
&lt;li&gt;API access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A clean REST API makes integrations easier down the road.&lt;/p&gt;




&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;p&gt;A relational database holds the core entities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Candidates&lt;/li&gt;
&lt;li&gt;Resumes&lt;/li&gt;
&lt;li&gt;Pipeline stages&lt;/li&gt;
&lt;li&gt;Notes&lt;/li&gt;
&lt;li&gt;Activities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps reporting straightforward and avoids unnecessary complexity.&lt;/p&gt;




&lt;h3&gt;
  
  
  Resume Storage
&lt;/h3&gt;

&lt;p&gt;Resumes are stored as structured text rather than relying purely on raw document formats.&lt;/p&gt;

&lt;p&gt;This enables better indexing and search.&lt;/p&gt;

&lt;p&gt;A simple transformation pipeline converts uploads into normalized text.&lt;/p&gt;




&lt;h3&gt;
  
  
  Search Layer
&lt;/h3&gt;

&lt;p&gt;Search is where things get interesting.&lt;/p&gt;

&lt;p&gt;Instead of traditional keyword-only search, Hire Gnome uses a hybrid approach:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyword + semantic matching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal is to allow queries like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Find backend engineers with API experience"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and return candidates who mention things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node&lt;/li&gt;
&lt;li&gt;REST&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;li&gt;microservices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;even if the exact words don't match.&lt;/p&gt;

&lt;p&gt;This dramatically improves candidate discovery.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm Trying to Avoid
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to ruin software is letting it slowly accumulate features.&lt;/p&gt;

&lt;p&gt;ATS systems are especially prone to this.&lt;/p&gt;

&lt;p&gt;Some examples of things I'm deliberately &lt;strong&gt;not&lt;/strong&gt; building (at least not yet):&lt;/p&gt;

&lt;h3&gt;
  
  
  Sales CRM
&lt;/h3&gt;

&lt;p&gt;Many ATS products try to combine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;recruiting&lt;/li&gt;
&lt;li&gt;sales pipelines&lt;/li&gt;
&lt;li&gt;account management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are different problems.&lt;/p&gt;

&lt;p&gt;Hire Gnome focuses on &lt;strong&gt;hiring pipelines only&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Over-Engineered Workflow Systems
&lt;/h3&gt;

&lt;p&gt;Some ATS platforms allow you to build extremely complex hiring workflows.&lt;/p&gt;

&lt;p&gt;In practice, most teams use something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Applied&lt;br&gt;
Screen&lt;br&gt;
Interview&lt;br&gt;
Offer&lt;br&gt;
Hired&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's enough.&lt;/p&gt;

&lt;p&gt;Flexibility without excessive configuration.&lt;/p&gt;




&lt;h3&gt;
  
  
  Giant Analytics Dashboards
&lt;/h3&gt;

&lt;p&gt;Analytics are useful, but most teams only care about a few metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;time to hire&lt;/li&gt;
&lt;li&gt;pipeline health&lt;/li&gt;
&lt;li&gt;candidate volume&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those can be added later without building a massive reporting subsystem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Open Source Model
&lt;/h2&gt;

&lt;p&gt;Hire Gnome is being built as &lt;strong&gt;open source first&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The idea is similar to the model used by many developer tools:&lt;/p&gt;

&lt;p&gt;The core platform is free and self-hosted.&lt;/p&gt;

&lt;p&gt;Revenue (eventually) comes from things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;managed hosting&lt;/li&gt;
&lt;li&gt;setup and deployment&lt;/li&gt;
&lt;li&gt;custom integrations&lt;/li&gt;
&lt;li&gt;support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small teams that can run it themselves pay nothing.&lt;/p&gt;

&lt;p&gt;Teams that want help can pay for services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Name "Hire Gnome"
&lt;/h2&gt;

&lt;p&gt;Because every hiring team deserves a small helper behind the scenes doing the hard work.&lt;/p&gt;

&lt;p&gt;Also, most good startup names were taken sometime around 2008.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;Right now the focus is on building the core pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;candidate ingestion&lt;/li&gt;
&lt;li&gt;pipeline management&lt;/li&gt;
&lt;li&gt;resume indexing&lt;/li&gt;
&lt;li&gt;semantic search&lt;/li&gt;
&lt;li&gt;simple UI for recruiters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once those pieces are stable, the roadmap likely includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;email ingestion&lt;/li&gt;
&lt;li&gt;calendar integration&lt;/li&gt;
&lt;li&gt;resume parsing improvements&lt;/li&gt;
&lt;li&gt;API integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the priority is keeping the system &lt;strong&gt;simple and reliable first&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons So Far
&lt;/h2&gt;

&lt;p&gt;Even early in development, a few lessons have already been clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Simplicity is harder than complexity
&lt;/h3&gt;

&lt;p&gt;It's surprisingly easy to add features.&lt;/p&gt;

&lt;p&gt;It's much harder to say &lt;strong&gt;no&lt;/strong&gt; to them.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Search is the real value
&lt;/h3&gt;

&lt;p&gt;Tracking candidates is easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding the right candidate later is the hard part.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Open source forces better design
&lt;/h3&gt;

&lt;p&gt;When people can see your code, you naturally build cleaner systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Recruiting software doesn't have to be bloated enterprise tooling.&lt;/p&gt;

&lt;p&gt;For small teams, hiring should be simple:&lt;/p&gt;

&lt;p&gt;Collect candidates → evaluate them → hire someone great.&lt;/p&gt;

&lt;p&gt;Hire Gnome is an attempt to build an ATS that reflects that philosophy.&lt;/p&gt;

&lt;p&gt;Small.&lt;/p&gt;

&lt;p&gt;Transparent.&lt;/p&gt;

&lt;p&gt;Developer-friendly.&lt;/p&gt;

&lt;p&gt;And hopefully useful.&lt;/p&gt;




&lt;p&gt;If you're interested in the project or want to follow along as it develops, I'd love to hear feedback from other developers or recruiters who have suffered through the current generation of ATS tools.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>node</category>
      <category>startup</category>
    </item>
    <item>
      <title>Building a Production RAG System for Resume Search: What Actually Worked (and What Didn't)</title>
      <dc:creator>Harry Wynn</dc:creator>
      <pubDate>Thu, 13 Nov 2025 00:07:31 +0000</pubDate>
      <link>https://forem.com/harrywynn/building-a-production-rag-system-for-resume-search-what-actually-worked-and-what-didnt-3jaa</link>
      <guid>https://forem.com/harrywynn/building-a-production-rag-system-for-resume-search-what-actually-worked-and-what-didnt-3jaa</guid>
      <description>&lt;p&gt;After 25 years in software development, I recently tackled a problem that's becoming increasingly common: implementing a production-ready RAG (Retrieval-Augmented Generation) system using AWS Bedrock Knowledge Bases. The use case was resume search for a recruiting database, and the results were significant enough that I wanted to share what worked, what didn't, and the gotchas I hit along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Keyword Search Isn't Enough
&lt;/h2&gt;

&lt;p&gt;Recruiters were drowning in manual work. They'd run keyword searches against the resume database, then spend hours manually sifting through results trying to match candidates to job descriptions. The core issue? Basic keyword search doesn't understand context or semantic meaning.&lt;/p&gt;

&lt;p&gt;A job description asking for "frontend expertise with modern JavaScript frameworks" might miss excellent candidates whose resumes say "React developer" or "Vue.js specialist" because the exact keywords don't match. Recruiters were compensating by running dozens of search variations, then manually evaluating each result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pain point:&lt;/strong&gt; Searches that should take an hour were taking 2 days or more to compile a quality candidate list.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: AWS Bedrock Knowledge Base with Semantic Search
&lt;/h2&gt;

&lt;p&gt;Instead of making recruiters search harder, I inverted the problem. The system takes a job description, generates an optimized semantic query, and searches the knowledge base for candidates whose experience actually matches what the role needs - not just the keywords used to describe it.&lt;/p&gt;

&lt;p&gt;The architecture is straightforward:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data source:&lt;/strong&gt; Bullhorn ATS
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data transformation:&lt;/strong&gt; Resumes exported and converted to Markdown files with recruiter notes embedded for additional context
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; Transformed files in S3
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector store:&lt;/strong&gt; AWS Bedrock Knowledge Base with OpenSearch Serverless
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embeddings:&lt;/strong&gt; Cohere Embed model
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query processing:&lt;/strong&gt; Job descriptions converted to optimized prompts before querying&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Markdown transformation was critical - it provided a clean, consistent format while preserving the recruiter context that often makes the difference between "technically qualified" and "actually a good fit."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Chunking Strategy That Actually Worked
&lt;/h2&gt;

&lt;p&gt;This was the most critical decision and took the most trial and error.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Tried First (That Didn't Work Well)
&lt;/h3&gt;

&lt;p&gt;My initial approach used semantic splitting - breaking documents at natural boundaries based on content meaning. The theory was sound: keep related information together. The results were... okay. Not terrible, but not targeted enough. Search results felt scattered, like the system was giving me pieces of information from across someone's entire career instead of the relevant parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Actually Worked: Fixed-Size Chunks with Overlap
&lt;/h3&gt;

&lt;p&gt;I switched to &lt;strong&gt;400-character chunks with 20% overlap&lt;/strong&gt; (80 characters of overlap between adjacent chunks).&lt;/p&gt;

&lt;p&gt;Why this worked better:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency matters for vector search.&lt;/strong&gt; Fixed-size chunks create more uniform embeddings, which means more predictable search results. When chunks vary wildly in size (which happens with semantic splitting on resumes), you get inconsistent matching quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overlap prevents context loss.&lt;/strong&gt; A candidate's key qualification might span a chunk boundary. The 20% overlap ensures that critical context doesn't get split awkwardly. If someone's resume says "Led migration from Angular to React, reducing bundle size by 40%," you want that whole thought captured somewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shorter chunks = more precise matching.&lt;/strong&gt; At 400 characters, each chunk represents a focused piece of someone's experience. When a query matches, you're getting specific relevant context, not an entire job history.&lt;/p&gt;

&lt;p&gt;The difference was noticeable immediately. Search results became more focused and relevant sections of resumes consistently bubbled to the top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metadata: What Mattered and What Didn't
&lt;/h2&gt;

&lt;p&gt;This is where the real power comes in. Raw semantic search is good; semantic search + metadata filtering is game-changing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metadata I Attached to Each Chunk:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Title (job title)&lt;/li&gt;
&lt;li&gt;Department&lt;/li&gt;
&lt;li&gt;Recruiter (who sourced them)&lt;/li&gt;
&lt;li&gt;Skills (extracted skill list)&lt;/li&gt;
&lt;li&gt;Companies (employment history)&lt;/li&gt;
&lt;li&gt;Education&lt;/li&gt;
&lt;li&gt;Location&lt;/li&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Actually Got Used:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Department filtering&lt;/strong&gt; was huge. Being able to search within "Accounting" vs "Creative" vs "HR" immediately cuts noise and improves relevance. When you're filling a finance role, you don't want creative professionals showing up just because they mentioned "budgets" in their portfolio management section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills metadata&lt;/strong&gt; let recruiters combine semantic search with hard requirements. "Find candidates whose experience matches this job description AND have Python + AWS in their skills list" catches people who might describe their work differently but have the required technical background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Location filtering&lt;/strong&gt; became essential for roles that weren't fully remote. No point showing Dallas candidates for a NYC office-required position.&lt;/p&gt;

&lt;p&gt;The other metadata fields were valuable for the application layer but didn't significantly improve search quality itself. They're worth capturing, but they're not doing heavy lifting in the retrieval step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Results: 2 Days or More to 2 Hours
&lt;/h2&gt;

&lt;p&gt;The numbers tell the story:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; Compiling a quality candidate list for a specialized role took 2 days or more of recruiter time - running multiple keyword searches, manually reviewing resumes, cross-referencing requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt; Same task took 2 hours. The recruiter reviews the job description, the system returns ranked candidates with relevant experience highlighted, and they spend their time on actual evaluation instead of archaeological searches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quality validation:&lt;/strong&gt; When we tracked placements, candidates that were actually hired appeared in the top search results the majority of the time. The system wasn't just faster - it was finding the right people.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Biggest Gotcha: Indexing Strategy
&lt;/h2&gt;

&lt;p&gt;This cost me the most time. My initial implementation used inline documents (sending resume content directly to Bedrock via API). It worked, but indexing was painfully slow - we're talking days to process and index resumes from Bullhorn.&lt;/p&gt;

&lt;p&gt;One important note: resumes are only indexed if they have been updated witin the past 2 years. Anything older than that quickly loses relevance in the recruiting world - skills change, candidates move on, contact information goes stale. This scoping decision kept the database manageable and ensured search results stayed current.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; A two-step transformation process. First, I exported resumes from Bullhorn (filtering for the past 2 years) and converted them to Markdown files, embedding recruiter notes as additional context within the documents. Then I stored these transformed files in S3 and pointed the Knowledge Base at the bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Indexing time dropped from days to hours.&lt;/p&gt;

&lt;p&gt;Why did this work so much better?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Bedrock Knowledge Bases are optimized for S3-based workflows.&lt;/strong&gt; The service can parallelize file processing much more efficiently than handling inline content through API calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown provided structure and consistency.&lt;/strong&gt; Instead of dealing with varied resume formats (PDFs, Word docs, text files), everything became clean, parseable Markdown. This consistency improved both indexing speed and search quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recruiter notes added critical context.&lt;/strong&gt; When a recruiter writes "Strong cultural fit for startup environments" or "Excellent communicator, handled difficult client situations well," that context gets indexed alongside technical qualifications. The semantic search can now match on soft skills and work style, not just keywords.&lt;/p&gt;

&lt;p&gt;If I were starting over, I'd go straight to the Markdown transformation approach and save myself a week of frustration. Plus, updates became simpler - export from Bullhorn, transform to Markdown, drop in S3, trigger a sync, done.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Still Improve
&lt;/h2&gt;

&lt;p&gt;This system is production-ready, but it's not perfect. It's a work in progress, and there are areas I'd continue refining:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic chunk sizing based on content type.&lt;/strong&gt; Resumes aren't uniform - executive resumes vs junior developer resumes have different information density. Adaptive chunking might improve results further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better handling of acronyms and industry jargon.&lt;/strong&gt; The system sometimes misses matches when candidates use acronyms (e.g., "K8s") vs full terms (e.g., "Kubernetes"). Some preprocessing or synonym expansion could help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query optimization based on role type.&lt;/strong&gt; Different job categories (engineering vs sales vs finance) might benefit from different query formulations. There's room to tune the prompt generation based on department.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with fixed-size chunking.&lt;/strong&gt; It's simpler, more predictable, and easier to tune than semantic splitting. You can always get fancier later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overlap is worth it.&lt;/strong&gt; The 20% overlap prevented edge cases where important context got split. The storage cost is negligible compared to the quality improvement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Metadata filtering is not optional.&lt;/strong&gt; Semantic search alone is good. Semantic search + metadata filtering is what makes the system production-ready.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transform your data into a consistent format.&lt;/strong&gt; Converting everything to Markdown before indexing improved both speed and quality. If you're working with an ATS or any heterogeneous data source, the transformation step is worth the effort.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use S3 for document storage from day one.&lt;/strong&gt; Don't make my mistake of starting with inline documents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embed human context wherever possible.&lt;/strong&gt; Recruiter notes added dimensions that pure resume text couldn't capture. If you have expert annotations, comments, or contextual notes in your source system, include them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measure what matters.&lt;/strong&gt; We tracked time-to-candidate-list and placement rates. Those metrics proved the system's value and guided optimization priorities.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Implementing RAG systems with AWS Bedrock isn't rocket science, but the details matter. The difference between "okay results" and "recruiters will use this every day" came down to chunking strategy, metadata design, data transformation, and infrastructure choices.&lt;/p&gt;

&lt;p&gt;For this use case, the combination of pulling from Bullhorn ATS, transforming to Markdown with recruiter context, using 400-character fixed chunks with 20% overlap, rich metadata filtering, and S3-based storage created a system that genuinely improved recruiter productivity. Searches that took 2 days or more became 2-hour searches, and the candidates being placed were consistently appearing in top results.&lt;/p&gt;

&lt;p&gt;If you're building similar systems - whether for recruiting, document search, customer support, or any other knowledge retrieval application - the principles transfer. Start simple, measure results, and optimize based on what your users actually need. And if you're working with data from an ATS, CRM, or any structured system, invest the time in a clean transformation pipeline. It pays dividends.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Need help implementing AWS Bedrock Knowledge Bases or optimizing your RAG system? I do consulting and implementation work through &lt;a href="https://conceptcache.com" rel="noopener noreferrer"&gt;Concept Cache&lt;/a&gt;. Feel free to reach out if you're hitting similar challenges.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Update: Turning This Into a Real Product
&lt;/h2&gt;

&lt;p&gt;Since publishing this article, I’ve started turning some of these ideas into a real project.&lt;/p&gt;

&lt;p&gt;I'm building an &lt;strong&gt;open source ATS for small teams called Hire Gnome&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lightweight candidate tracking&lt;/li&gt;
&lt;li&gt;strong resume search&lt;/li&gt;
&lt;li&gt;semantic search built in from the start&lt;/li&gt;
&lt;li&gt;something developers can self-host and customize&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of the lessons from this RAG system are shaping how search works inside the platform.&lt;/p&gt;

&lt;p&gt;If you're interested, you can read about the project here:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dev.toLINK_TO_NEW_POST"&gt;Why I Started Building Hire Gnome&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd also love feedback from anyone who has wrestled with ATS systems before.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
