A Sieve That Refuses to Guess
Most job tools either scrape aggressively or hallucinate a verdict from a title. This one refuses to decide when it cannot read, and says so.
Job SearchDeterministic SystemsAIProduct Design
Job search is mostly reading and rejecting. Alert emails carry a title, a company, a location, and a link. Never a description. Most tools either scrape aggressively and get blocked, or hallucinate a verdict from the title alone. Neither is honest.
I wanted a sieve that refuses to guess. A posting it cannot read is needs_research, not a pass and not a rejection. That single decision shaped everything else.
The problem with guessing
A title like “Senior Backend Engineer” tells you almost nothing useful. It could be a Go role at a fintech, a Java role at a bank, or a Python role at a startup. The company name narrows it slightly, but not enough to decide. Yet most automated tools will produce a verdict anyway, because a verdict is what the user asked for.
The honest answer is often “I don’t know yet.” But “I don’t know” is unsatisfying, so tools round it up to “probably fine” or round it down to “not a match.” Either way, the user is misled. The tool has performed work, produced output, and created the impression of a decision where none existed.
I have made this mistake myself. Early versions of the gate treated a missing description as a soft pass, on the theory that the user could check later. That meant the shortlist was full of jobs nobody had actually read. The fix was to make uncertainty a first-class verdict: needs_research sits alongside strong_match, potential_match, and not_suitable as a legitimate outcome, not a failure.
What the gate actually does
The gate is deterministic. No LLM in the verdict path. Each posting is evaluated against a profile (stack, location and authorisation, years of experience, pay floor) and each verdict cites the exact quoted requirement it evaluated. If the description is incomplete, the verdict is needs_research and the posting stays in the queue until someone reads it.
This means the tool can be wrong about a posting, but it cannot be dishonest about why. A rejection says “requires 5 years Python, profile shows 3.” A needs-research says “description too short to evaluate.” The user always knows what happened and what to do next.
Four account-free sources feed one SQLite ledger: RemoteOK, Remotive, Arbeitnow, and Hacker News Hiring. Descriptions are fetched politely, one at a time, with backoff on 429. Nothing is sent, applied to, or submitted. There is no mail transport, HTTP client, or browser in the decision path. Those are intentional boundaries, not missing features.
What I got wrong first
The first version of the gate treated uncertainty as a soft pass. The reasoning was reasonable: the user can check later, and a tentative “maybe” is more useful than silence. In practice, the shortlist filled with jobs nobody had read, and the user trusted the tool’s optimism. The failure was not in the logic but in the assumption that a tentative verdict is harmless. It is not: a tentative verdict that looks like a real one is worse than no verdict at all.
The second mistake was narrower. The gate originally evaluated against a single combined score: match the stack, match the location, match the years, and produce a number. That number was easy to read and easy to trust, and it was wrong in a specific way. A posting that matched on stack but failed on location would still score well, because the stack match dominated. The fix was to make each gate independent and report which one failed. A posting now gets a verdict per dimension, and the shortlist shows the failing gate, not just a score.
What it cannot do
The four sources are tech-leaning. Non-tech roles are underrepresented, and the gate’s strongest signal (technology match) is software-specific. Compensation is quoted and flagged, never converted at an invented rate. Real-network fetches are tested with injected fetchers, not live endpoints.
The tool will not search the web for you. It will not apply on your behalf. It will not run in the background. It is a sieve, not a robot: you feed it postings, it tells you which ones deserve your attention and why.
Why this matters beyond job search
The pattern generalises. Any system that produces a verdict from incomplete data faces the same temptation: round uncertainty into something that looks like a decision. A credit score, a medical triage, a code review. The pressure is always to produce an answer, and the answer is often “not enough information.”
The fix is not to improve the guessing. It is to make the absence of information a first-class output, with the same weight and visibility as any other verdict. needs_research is not a failure state. It is the honest one.
Jobsearch Pipeline is MIT licensed and open source. Source repository · Case study · PyPI