Every New Job Post, Graded Before 6am
Scrapes job boards every morning, scores each posting against one candidate's real record, emails the shortlist
The Problem
A serious job search means reading five hundred to eight hundred fresh postings a day across LinkedIn and Indeed, and almost none of them fit. The same jobs reappear day after day under slightly different titles, so you re-read work you already did. Judging fit honestly is the hard part: it is easy to talk yourself into a role that will screen you out, and easy to skip one you would actually win.
What It Does
Every morning before 6am it runs 25 saved searches across LinkedIn and Indeed, pulling only postings from the last 24 hours. It folds both sources into one common record and collapses the duplicates inside the run, then throws out anything non-US, on-site outside the local area, or carrying a title it has already learned to reject. What survives is checked against everything already tracked, so repeats only get their last-seen date bumped instead of being re-read. Genuinely new postings go to a language model carrying a written scoring rubric, which grades fit 1 to 10 and names every requirement met, partially met, and missing. The results land in Airtable and arrive as one email: apply, maybe, and a collapsed list of everything skipped, with the day's counts at the top.
Anyone running a long, specific job search who wants a short honest list waiting for them in the morning instead of a feed to scroll. It works hardest for a candidate with an unusual record that keyword search handles badly.
Outcome
In eleven days it graded and tracked 3,117 postings and put 8 to 24 worth applying to on the list each morning. On the first day the shortlist was worked, every application was submitted by noon, an interview request came in at 13:07 that same afternoon, and the interview happened the next day. That interview came from a posting the first version of the rubric had scored a 6, below the apply line, and a later rescore moved up.
Screenshots



How It's Built
A code node builds the run's search plan: one item per source and search term, each carrying the scraper actor ID and its input payload, so changing what gets searched is a config edit rather than a rewiring. A batch loop feeds those three at a time to an HTTP node calling Apify's run-sync endpoint, with continue-on-error so one dead actor call does not take down the run. A normalize node folds the two very different actor response shapes into one record, detects US location and work arrangement by regex, converts hourly pay to annual, and collapses duplicates inside the run on a normalized company plus title key. A prefilter node then applies cheap rule-based drops before anything costs money, tagging every item pass or drop with a reason rather than silently discarding it. Survivors are checked against existing dedupe keys pulled from Airtable, and a switch splits them three ways: new, re-seen, or nothing at all. New ones are wrapped one at a time into a chat completions call carrying the scoring rubric as the system prompt and a strict JSON schema as the response format. A parse node re-applies the rubric's caps and floors in code, so pay, seniority, degree, core-craft and pivot rules hold even when the model forgets them, then emits Airtable field names directly. Re-seen postings only get Last Seen and Times Seen bumped. A three-input merge waits for every branch before the digest node builds the email HTML and the run log row, which go to Gmail and then to a Run Log table.
By the numbers
- postings scraped per 24-hour run
- 472 to 805
- postings scraped on the initial backfill run, 2026-09-03, which used a seven-day window instead of 24 hours
- 1,403
- postings surviving the prefilter per 24-hour run
- 146 to 326
- new postings scored per 24-hour run
- 121 to 280
- postings scoring 7 or higher per run, since the v1.5 rubric
- 8 to 24
- postings graded and held in the Jobs table as of 2026-09-14
- 3,117
- repeats caught by dedupe rather than re-scored
- 518 postings seen more than once, 631 re-seen events
- duplicates collapsed inside a single run before the prefilter, 2026-09-09
- 385 of 805 scraped, leaving 420 unique
- rows rescored after the rubric audit
- 102
- rescored rows that fell below the apply threshold
- 59 of 102, mean drop 1.2 points
- applications submitted from the tracker in roughly the first week
- 46
- searches per run
- 25 (11 terms across 2 sources, plus 3 local LinkedIn searches)
- ceiling on postings pulled per run
- 955 (40 per search, 25 on the three local searches)
- OpenAI spend across all of Ryan's workflows combined, not this one alone
- about $3 per day
Key Decisions
Run at 05:45 Central
So the list is ready when he wakes up and is ready to apply. The work happens before the day starts, not during it.
Two filtering layers, regex before model
A title regex costs nothing and a model call does not. Anytime you can name a category of opportunity that will never be a fit, eliminate it ruthlessly and early. The prefilter kills healthcare, trucking, software engineering, early-career and non-US postings before a single token is spent.
Drops are tagged, not deleted
Every item carries pass or drop plus a reason all the way to the digest, so the email reports what was thrown out and why. Silent filtering is how you stop trusting your own pipeline.
Every run writes a row to a log table, whether or not it found anything
The counts at each stage are the only way to see the pipeline failing while it still looks healthy. Four straight mornings of zero recommendations is invisible in an inbox and obvious in a table.
The rubric's caps and floors are re-enforced in code after the model answers
The model is good at reading a posting and bad at remembering fifteen numeric rules. The model supplies the judgment, the code supplies the arithmetic.
Must-haves are tagged HARD or SOFT and only HARD ones move the score
Communication, analytical thinking and attention to detail are met by nearly everyone. Counting those the same as the actual craft is what let unqualified roles score high.
A too-junior posting is capped at 5, not boosted
Exceeding every requirement is a mismatch, not a fit. A twenty-year operator applying to a coordinator role gets screened as overqualified or hired underpaid.
A 9 or 10 requires the posting to name a tool he actually builds in
The top of the scale should mean something specific. If the posting does not name n8n, Make, Zapier, Airtable, Apps Script or custom GPTs, the score is capped at 8 no matter how well the prose reads.
Dedupe on normalized company plus title, not URL or source ID
The same job appears on both boards with different IDs and reposts with new URLs. Stripping punctuation, parentheticals and Inc/LLC is what makes a repeat look like a repeat.
Three searches per batch, 40 results per search, two scoring calls per four seconds
None of these were picked up front. They came down after rate limits showed up in testing. It is about keeping the workflow flowing smooth without flooding the system with too many at one time.
The pipeline always emits at least one item
A day with zero new postings still needs to write a run log row and send a digest. Empty output would skip both, and silence reads the same as a broken workflow.
The model call is the only per-posting cost, so the prefilter is the cost lever
Everything else in the run is effectively free. Quality is very high right now and the next version is about holding that quality while cutting the bill: more inexpensive filters first, then the expensive model on the nitty-gritty details. A posting that is clearly not a fit a third of the way in should stop there. There is no reason to finish grading every requirement to a qualified yes or no once the answer no longer matters.
What broke & how it was fixed
It was wrong in both directions, and the run log caught one of them before a human did. For four consecutive mornings, 2026-09-04 through 2026-09-07, it scraped between 472 and 790 postings and recommended zero. The scoring was trying to gate on too many things at once, so a posting had to clear every requirement at full strength to survive, and nothing did. At the same time, a manual deep screen of postings it HAD scored 8 or higher came back with 2s through 5s. Same root cause seen from two sides: soft-skill requirements were counted the same as the actual craft, so eight soft matches could carry a role over the line while a genuinely good role died on one strict gate. Three more causes turned up in the same audit on 2026-09-08: no seniority check, so junior and graduate-program roles scored high precisely because the candidate exceeded them; 'X or similar' counted as met even when the posting named several enterprise platforms he had never touched; and years in general marketing were being credited as years in a named specialty. Version 1.5 split must-haves into HARD and SOFT so only the craft lines move the score, added a core-craft check ahead of the tally, added a seniority field that caps at 5, raised the pay floor to $85K, and added an explicit floor rule that forces a 7 when every gate passes. A second audit the same day added 1.5.1, because postings listing a national location while the body said three days a week in the office were still getting through. A separate rescore workflow then re-ran 102 already-scored rows under the new rubric. Fifty-nine of them, 58 percent, dropped below the apply threshold, with an average fall of 1.2 points, and others rose. Every rescored row carries a note saying what it was, what rubric scored it, and what it is now.
Where else this applies
This is the shape of every high-volume screening problem: pull from sources with incompatible schemas, normalize to one record, drop the obvious no's with rules, spend model tokens only on survivors, and enforce the non-negotiable rules in code rather than trusting the model to remember them. Swap the rubric and it screens inbound leads, grant opportunities, RFPs, resumes against a role, or properties against buy-box criteria. The part worth stealing is the audit loop: a scoring system nobody spot-checks drifts, and it drifts toward being too generous, because a generous score feels like good news. Versioning the rubric and stamping the version on every row is what makes it possible to find out how wrong you were and fix the back catalog.