An Enthusiast Purchase That Aged Well
The graphics card in my desktop was purchased to play games. That was the entire justification, and it was a good one at the time. A few years later, that GeForce RTX 4090 spends most of its working hours running language models locally, and gaming has become the side activity.
The most recent project it powers is a job search system that runs entirely on that one machine. No cloud service, no account, no subscription, and no data leaving the building. What follows is an explanation of what the system does, how it is built, and what the process revealed about the real limitations of small language models running on consumer hardware.
The Problem With Job Boards
Job boards are built to serve the employer's hiring funnel, not the candidate's search. The consequences are familiar to anyone who has looked for work recently. Search results are noisy. The same posting appears five times across four aggregators. Listings marked remote frequently are not remote. Salary and work location details are buried or absent entirely. Hours disappear into reading descriptions in order to find the handful worth an application.
This tool exists because I regularly help former students and colleagues who are searching. The most demoralizing pattern in a job hunt is finding a role that fits almost perfectly, then discovering a single hard requirement that will keep the application from ever reaching a human reviewer. That happens repeatedly, and it costs hours each time. A system that ranks postings by likely fit, and explains the reasoning behind the ranking, means effort goes only toward applications worth submitting.
Why the Model Runs Locally
An effective job search profile contains information that does not belong on someone else's server. Salary floor. Geographic constraints. The reason a candidate left a previous employer. Notes about which employers to avoid. Family or health considerations that affect scheduling. This is precisely the category of information that improves match quality and that no one should hand to a third party in exchange for a free service.
Running the model locally resolves that tension. The full profile, including the parts that would never appear on a resume, stays on hardware I own. Postings are fetched anonymously from public endpoints. Scoring happens on the graphics card through Ollama. Nothing is transmitted anywhere. Data minimization is a foundational principle of information security, and local inference is one of the few places where applying that principle costs nothing.
The Architecture: A Cost-Escalating Funnel
The central design constraint is that good analysis is expensive and there are a great many postings. A 27 billion parameter model reading a full job description takes roughly seven seconds. Running that model across every posting the system tracks would require days of continuous compute.
The solution is a funnel in which each stage costs more per posting than the stage before it. Every stage exists to shrink the pile before the next one touches it.
Stage 1, Fetch. Fifty-five company boards are read through public applicant tracking system APIs. Roughly 0.2 milliseconds per posting.
Stage 2, Filter. Deterministic rules handle title tokens, geography, posting age, and salary floor. Microseconds per posting.
Stage 3, Triage. A small local model scores every survivor from zero to ten. Roughly 0.7 seconds per posting.
Stage 4, Deep score. The 27 billion parameter model reads the full description. Roughly seven seconds per posting.
Stage 5, Screen. The system fetches the real application form and counts the burden. One HTTP request.
Stage 6, Review. A human decides. This is the only stage that spends the candidate's attention.
A representative run tracked 12,606 postings. Filters reduced that to 260. Triage passed 60 forward. Thirty-four survived deep scoring and reached the shortlist. A full cold run takes about five minutes. A cached rerun takes six seconds.
The system itself is Node 24, thirty-five modules, roughly 4,400 lines, zero runtime dependencies, and 272 tests. Storage is either a single JSON file or SQLite through the runtime's built-in driver, with no external database to install. Twelve thousand postings with full descriptions occupy about 70 megabytes.
Reading the Source Instead of the Aggregator
The system reads company career pages directly, through the same public interfaces that serve those pages in a browser. Seven connectors sit behind a single contract, and each normalizes its results into one flat record. The practical effect is no duplicates, no sponsored ranking, and access to postings that small employers never syndicate to the large boards.
Two undocumented parameters on one widely used applicant tracking platform do a disproportionate amount of work. The first returns structured pay data, present on roughly half of postings overall and on nearly all postings at certain employers. The second returns the actual application questions. That means the system can report that a form has twenty-six required fields before a candidate begins filling it out. An eight-field application and a twenty-six-field application with three essay questions are entirely different decisions, and candidates presently have no way to know which one they are about to start.
What Small Models Actually Get Wrong
Most of the engineering effort went into defending against the specific ways small models fail. Those failures are not dramatic. They are quiet, plausible, and very easy to ship.
They silently drop work. A model asked to rate eight postings in a single prompt returned one rating object. The response was valid JSON and contained no error of any kind. Every batch is now reconciled against what was requested, and missing entries are asked again individually.
They misalign results. A model returned the correct number of ratings, attached to the wrong postings. A senior director of enterprise applications came back with reasoning written about an ITAR compliance role. Nothing was malformed, so no parser would ever catch it. Every rating now echoes the title of the posting it claims to describe, and any rating whose echo does not match is rejected and asked again.
They copy the example. Placing a concrete value in the response schema, specifically a score of five, caused thirty-six of forty-two postings to score exactly five. Schemas now use placeholders rather than sample values, and an automated check raises a warning whenever seventy percent or more of a scoring pass shares one value.
None of these failures produced an error message. All three would have produced a shortlist that looked entirely reasonable and was wrong. That is the practical lesson for anyone deploying language models in a workflow that matters: the dangerous output is not the one that crashes, it is the one that looks correct.
Making "Do Not Invent Experience" Enforceable
Resume parsing produces what the system treats as a fact ledger. Every extracted fact carries the verbatim sentence it came from. Any fact whose supporting quote cannot be located in the source document is discarded in ordinary code, below the model, before scoring ever sees it.
That distinction matters more than it may appear. Instructing a model not to fabricate experience is a request. Verifying that every claim traces back to a real sentence is an enforceable property of the system. Inferences are stored separately from facts and displayed as assumptions, along with the facts they were derived from and a confidence level, so a wrong guess is visible and correctable rather than quietly skewing every score that follows. Fields associated with protected classes are never extracted at all, and a test enforces that.
Filters That Explain Themselves
Every run reports why postings were dropped: title not matched, 7,393; location, 196; below salary floor, 30. When a shortlist looks thin, the cause is visible rather than mysterious.
That diagnostic caught the worst defect in the project. The title filters were excluding the words director and senior manager, discarding 253 senior roles before scoring ever ran. Without per-rule reporting, the only symptom would have been a shortlist that felt mildly disappointing, and the defect would still be there today.
Geography and the Public Sector
Location handling requires more nuance than a keyword match. A posting listed as remote in California and Oregon is closed to an Arizona resident, and a role whose country appears only in the title is caught as well.
Public sector employers are treated as first-class sources rather than an afterthought. Federal listings, State of Arizona listings, and the enterprise systems used by Arizona State University, Maricopa County, Banner Health, and HonorHealth are read directly. Retirement systems are tagged at the employer level rather than searched for as keywords, because a pension system is a property of the employer and will never reliably appear in the text of a posting. For candidates in the Phoenix metropolitan area, those employers represent a substantial share of stable technology work, and they are systematically underrepresented on commercial job boards.
Interview Practice
The feature now in development extends the same approach to preparation. The model reads a posting, identifies comparable roles, and generates twenty-five interview questions likely to be asked. The candidate answers by voice. The recording is transcribed, and the model evaluates the response against the STAR structure and against the candidate's own fact ledger.
The feedback is specific rather than encouraging. An answer may score well on situation and task and poorly on result, with a note that the response described a migration and the actions taken but never stated what actually changed, alongside a reminder that the resume already contains the relevant figure. Coaching at that level of specificity is normally expensive and rarely available on demand at eleven o'clock at night, which is when most people actually practice.
What This Says About the Current Moment
Three years ago, a system like this would have required a cloud account, a monthly bill, and an agreement to surrender the most sensitive parts of a job search to a company with its own commercial interests. Today it runs on a graphics card that was purchased to play video games, at a recurring cost of zero, with nothing leaving the machine.
That shift matters for anyone entering the technology workforce. The barrier to building genuinely useful private systems is no longer hardware or model access. The barrier is understanding how the pieces fit together: how networks and application programming interfaces actually move data, how storage and operating systems behave under load, and how to reason clearly about where information travels and who is able to see it. Those are the fundamentals that industry certification training covers, and they remain the difference between assembling a demonstration and building something that can be trusted with real decisions.
The most valuable thing artificial intelligence contributed to this project was not the scoring. It was returning the hours that would otherwise have been spent reading 12,606 job descriptions in search of the thirty-four worth an application.
