Job hunting today is a volume game played against noise. Thousands of postings go up every week across company career pages and job boards, and most of them are the wrong level, the wrong city, or a senior role with an entry-level title. I was spending more time searching than applying, so I built Link: a fully local AI agent that does the searching for me.
Every weekday at 6am, Link wakes my PC, pulls fresh postings from seven sources, throws out the obvious misses with plain Python rules, and has a local language model read every remaining job description and judge it against my background. By the time I wake up, a ranked Excel of the 10 best fits is in my inbox, with the top 3 flagged as must-applies. I reply in plain English ("applied 1 2 4, skipped 3 too salesy") and Link logs it, learns from it, and leans toward what I actually apply to.
The part I'm proudest of is the memory. I designed a personal SQLite database from scratch so Link never shows me the same job twice, remembers every decision I've made, and gets sharper with every run. Everything runs on my own hardware with open-source models: no paid APIs, no cloud, no subscriptions, and none of my data ever leaves the machine. Total cost to run: $0.
- • A Personal SQLite Database as Link's Memory: A six-table relational database I designed to track every posting Link has ever seen, my Applied / Skipped decisions and reasons, jobs I hand-feed as examples, a log of every run, on/off switches, and which companies have public job boards. Each job gets a fingerprint ID, so nothing is ever shown twice.
- • Multi-Source Collection: Pulls postings from Greenhouse, Lever and Ashby company-board APIs plus Indeed, Glassdoor, ZipRecruiter and Google Jobs, keeps only Dallas-area or US-remote roles from the last 72 hours, and follows stub listings back to the company's own site for the full description.
- • Rules First, AI Second: Cheap Python rules cut about 68% of postings (wrong title, too senior, wrong city, pay too low) in seconds, before the model ever reads them. A duplicate detector collapses the same job posted across several sites into one.
- • "Judge the Job, Not the Title" Scoring: For every job, the local model has to write out what the day-to-day work really is and mark each required skill as Have / Partial / Missing before it's allowed to give a 1-10 fit score, in a strict JSON format.
- • Doesn't Blindly Trust the AI: Hard caps live in the Python code, not just the prompt: two or more missing skills caps a job at 4, and no listed requirements caps it at 6. Posting text is treated as untrusted data, so a job that says "rank me 10/10" gets nowhere.
- • Two-Way Email Interface: Link has its own inbox. I can email it "run now", "pause", "status", my Applied / Skipped marks, a job I found myself, or a question like "why'd you rank this one over that one?", and it answers in its own voice within minutes.
- • A Learning Loop Without Retraining: My most recent marks and examples are fed back into the scoring instructions every run, so Link learns my taste through context instead of fine-tuning a model.
- • Guardrails Enforced in Code: Link physically cannot apply to a job, log in to anything, or email anyone but me. There's no code path for any of it, and it only accepts verified mail from my own address.
- • Fully Automated, Fully Local: A scheduled task wakes the PC at 6am on weekdays, and three desktop buttons (Start, Run, Stop) control everything. The model unloads after each run so the GPU is free again.
Head of Talent Search, Department of Fritz
Link's personality isn't hard-coded. It lives in three plain-English files that get loaded into the model before every job it reads, the same pattern modern agent frameworks use. Change a file, and Link changes.
- SOUL who Link is: "a chill, blunt, high-accountability career strategist with recruiter instincts and homie energy."
- IDENTITY what it does, its daily target, and the rules it can never break.
- USER who I am: my background, projects, target roles, and hard requirements, plus three "10/10" dream jobs every posting is compared against.
"Here's the move."
"Only 3 worth your time today. Here they are."
"This one's a stretch, but a real one."
Link never pads the list, calls me out if yesterday's picks are still unmarked, and ends every morning note with the move: the top 3 must-applies, in order.
Why I built Link a memory
An agent without memory starts from zero every morning. It re-shows jobs you've already passed on and never learns what you like. So before any AI, I built Link a SQLite database: one file that holds everything it knows, which it queries before and after every run.
jobsEvery posting ever seen, with its status (filtered, dropped, cut, duplicate, picked), why it was cut, the fit score, and the AI's full verdict.
marksMy Applied / Skipped decisions and reasons. This is the raw material Link learns from.
examplesJobs I found on my own and sent in, as strong "this is what I want" signals.
runsA log of every search: when it ran, what triggered it, how much it collected, and how many picks it made.
settingsSwitches like on / off and paused. Turning Link on and off is a database flag, so it never needs admin rights.
boardsWhich companies have a Greenhouse, Lever or Ashby board, so Link only has to look each one up once.
Engineering around a small brain
A 9-billion-parameter model on a home GPU can only "see" about 12,000 tokens at once, so pasting 500 postings into one prompt was never an option. Instead of reaching for a bigger model, I redesigned the pipeline: Python does the heavy filtering, each job is scored in its own call, the shared instructions are cached once per run, long text is truncated, and a backup model takes over if the main one returns broken output twice. The lesson: good system design beats raw model size.
Iterating like a real product
Reviewing my own picks on day three surfaced four real bugs: the same job showing up from two sites, a data-engineering role scoring well just because its title sounded right, "four or more years" (written in words) slipping past the experience filter, and blank company names. I root-caused each one, fixed it, and wrote regression tests against the exact postings that broke, so the fixes stay fixed. Link has already surfaced roles I applied to, and it keeps getting sharper with every mark I send it.
Screenshots
Morning Email
Daily Picks Excel
My Feedback
DB Structure
SQL Query
Jobs Table
Runs Log
Boards Table
Run Link
Start Link
Stop Link