CareerOS

A job search that cannot say anything I have not done. By construction.

Every tool in this space writes your resume for you, and every one of them will quietly inflate a number to make a posting fit. CareerOS is the opposite bet: a pipeline where each sentence on the page must trace to a recorded piece of evidence, and where the thing that catches an overclaim is a gate that refuses it rather than a disclaimer that warns about it.

Watch 10,034 postings narrow → Try the containment gate Backend source Frontend source

FastAPI + Next.js  ·  281 commits  ·  457 backend tests  ·  nine job boards

The problem

The tools that write your resume are the ones you can least afford to trust.

A resume generator that invents a plausible figure has not made a small error. It has put a sentence in front of a hiring manager that you will be asked about in a room, and you will not know where it came from. The failure is silent at the moment it happens and expensive weeks later.

What CareerOS does

  • Scores a posting against a recorded evidence library, deterministically — no model in the scoring path.
  • Selects bullets by marginal coverage of that posting’s requirements, not by per-bullet score.
  • Refuses generated wording that reaches past the claim behind it.
  • Reports what it did not evaluate, so a ranked list is never mistaken for a complete one.

What it refuses to do

  • Nothing auto-submits. It prepares an application and stops; the person applies.
  • No scraping of boards whose terms prohibit it — the gap is named on the page instead.
  • No invented figures, tools or employers, whoever wrote the sentence.
  • No fabricated confidence: an unrecognised requirement is a gap, never a pass.

Two demos, both in your browser

The two decisions worth watching happen at opposite ends.

One narrows ten thousand postings to ten. The other decides whether a single sentence is allowed onto the page. Neither needs a backend — they run entirely in the tab.

10,034 → 10

Ten thousand postings, in 3D

One real discovery run rendered as it happened: every posting fetched, then eliminated in turn by location, eligibility, title prescreen and evidence score until ten remain. The eliminations are the interesting part — the scoring budget only reaches 600 of them, and the visualisation shows which ones it never looked at rather than pretending the ranking was exhaustive.

Open the pipeline →
3 verdicts

The containment gate

Type a resume bullet and watch the checks run: invented figures, proper nouns the claim never mentioned, substantive words that smuggle in scope, and seniority escalated past the recorded verb. Pass, review or reject — and the policy is deliberately asymmetric, because a model may not vouch for a claim about someone else’s career while the candidate editing their own history always may.

Try the gate →

Discovery

Nine boards, and three named refusals.

Every source is a real, publicly documented, unauthenticated API, except Handshake, which publishes a sitemap of public job pages in its own robots.txt with a schema.org block on each — structured data put out for machines to read, which is the same bargain a board API offers.

GreenhouseAshbyLever WorkdaySmartRecruitersThe Muse ArbeitnowRemoteOKHandshake LinkedInIndeedWellfound

The three struck through are not missing — they are declined, and the reason is served to the interface rather than left to look like an oversight. LinkedIn and Wellfound both prohibit automated access to pages that render publicly; Wellfound’s terms name “automated or non-automated harvesting, collection or scraping” specifically. Most of what Wellfound lists is reachable anyway: on a sampled page, 18 of 31 postings were served from the employer’s own Greenhouse or Ashby board, so the way to cover it is to add those employers rather than to crawl it.

Decisions that cost real debugging

Every one of these was a bug first.

Scoring

An unrecognised requirement is a gap, never a pass

Requirement extraction runs two layers: a canonical vocabulary and open-vocabulary detection of requirement-shaped terms it does not recognise. With only the closed list, anything outside it was not merely unscored but unseen, so it could never be reported as a gap. A mortgage compliance posting requiring HMDA and LOS extracted five generic requirements, matched all five, and scored 98/100 with “no gaps” for a job the candidate was not qualified for.

Selection

The budget must be spent on the axis you are sorting by

Full scoring parses whole descriptions, so it cannot run on every posting. Search used to score the first 120 in fetch order and sort those by fit — a ranked list that was not a ranking, with a 98-scoring role sitting unscored at position 452. Sorting by date had the identical defect one layer up: the budget still selected on title fit, so “newest” reordered a fit-shaped subset. 517 postings were from the last day and past the relevance floor; 441 never reached the scorer.

Writing

Containment is asymmetric on purpose

The same sentence gets three different outcomes depending on who wrote it. From the assistant, any doubt is fatal. From a model proposing a rewrite, a clean one applies and a questionable one queues for review. From the candidate, failures are warnings rather than vetoes — they know things the evidence file has not caught up with, and refusing their own history would be the wrong call. The text saves, marked unverified, and the resume says so.

Honesty

The backend knowing something is not the same as the page saying it

This is the failure that kept recurring. The liveness check knew which postings had closed and wrote it down; nothing read it, so eight “ready” applications were against postings that no longer existed. The health endpoint’s source list was hand-maintained and two adapters out of date. A board filter that ran after the scoring budget would have shown 11 of Handshake’s 29 roles and called it all of them. Same shape every time: the system knows, and the surface throws it away.

What is in it

236Commits across the FastAPI backend and Next.js frontend.180 api · 101 web
421Backend tests across 60 files, including the ones that pin past bugs.python
9Job boards polled, each isolated so one failure is named rather than silent.+3 declined
0Applications submitted automatically. The tool prepares and stops.by design

Scoring and bullet selection are deterministic and model-free — a stated design position, not an omission. A language model touches wording only, and every generated sentence passes the same containment gate before it can reach a document. A missing API key produces today’s deterministic resume, not a broken one.