The who's-hiring thread, searchable, with no model in the loop
Grepwork turns HN's monthly Who is hiring? thread into a filterable board. It parses a few hundred messy, human-written job posts with regex, not an LLM. Here is why that works.
Once a month, an account called whoishiring
posts "Ask HN: Who is hiring?" and a few hundred companies reply, each with a freeform job listing
as a comment. It is one of the best job sources a developer has: no recruiter noise, no LinkedIn
spam, written by the people actually doing the hiring. It is also a flat wall of plain text in
whatever order things got posted, with no search and no filters. Answering "which of these are
remote and use TypeScript" means reading all of them.
Grepwork turns that thread into the job board it always should have been: search across every post, filter by remote type, stack, and seniority, browse past months, expand any card to the untouched original comment. The interesting part is what it does not use to get there.
No model reads the posts
The obvious way to structure a few hundred inconsistent human-written blurbs in 2026 is to hand each one to an LLM and ask for JSON. Grepwork does not. Extraction is deterministic: regex and keyword lists tuned to how these posts are actually written, run once at build time.
That sounds like the worse choice until you look at what these posts have in common. HN's thread
has a decade-old convention: the opening line is usually Company | Location | REMOTE | stack,
pipe-delimited, because that is what everyone before you did. Stacks are named from a finite,
slow-moving vocabulary (there are only so many ways to write "Postgres"). Remote status shows up in
a handful of recognizable phrasings. It is messy, but it is messy in patterned ways, and pattern
matching is exactly the tool for patterned mess.
The payoff is that every extraction is explainable. When a post gets tagged remote and rust, I
can point at the substring that triggered it. The keyword lists live in the repo and are a
one-line change to extend. It costs nothing to run, produces the same output every time, and never
hallucinates a company that was not there. An LLM buys you a little more recall on the weird posts
and pays for it in opacity, cost, and the occasional confident fabrication. For this shape of data,
that trade is not worth it.
Honesty about the ones it can't parse
The flip side of deterministic parsing is that you know exactly when it fails. Plenty of posts ignore the convention: no pipes, company name buried in prose, location never stated. A parser that guesses anyway would quietly present a wrong company as fact, which is worse than saying nothing.
So Grepwork flags those. When a post does not follow the usual Company | Location opening, the
card marks the auto-guessed fields as unconfirmed rather than dressing a guess up as data. Same
spirit on the filters: an explicit "no remote" post gets classed as onsite, not swept into the
remote bucket because the word "remote" appeared in a sentence saying they don't do it. The stack
and seniority chips are ranked by how often each tag actually shows up in the active month, so the
signal-heavy filters sit first instead of a wall of one-hit tags.
It's just static files
There is no backend. scripts/build-data.ts fetches the six
most recent threads through HN's public Algolia Search API, which is
free, unauthenticated, and already indexes full comment trees, so there is no HTML scraping and no
rate-limit risk. Parsing happens at build time, and the output ships as a plain HTML/CSS/JS bundle
with relative asset paths. Cheap to host, nothing to protect, and it works served from any subpath.
TypeScript runs end to end, with the parser and the UI sharing one JobPosting type, so a change
to what gets extracted is a compile error in the UI until it is handled.
Try it
Open the board, type your stack into the search box, and flip the remote filter to "remote". You will have the handful of posts worth reading in about ten seconds, down from scrolling a few hundred comments. Use the month picker to run the same filter over past threads, and expand any card when you want to read the real post in the poster's own words.
This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.
Loading comments…