An AI Job Search That Compiles the PDF and Then Reads It Back

The genre of "AI job application" tools has a credibility problem, and it is not technical. Everyone suspects the output is a keyword-stuffed PDF that a recruiter will smell in four seconds.
So the first thing worth reporting about ai-job-search, an MIT-licensed framework by Mads Lorentzen that turns Claude Code into a job search pipeline, is what the author did with it: 69 applications, 20 first-round interviews, and a signed offer as an AI engineer. He also says he told every employer he used it. That is either a very good sign or a very lucky one. Probably both.
The second thing worth reporting is that the interesting engineering is not in the writing. It is in the checking.
The three commands that matter
/setup fills your profile. Three ways in: point it at a documents/ folder, paste a single CV, or answer interview questions. The author is blunt that profile depth is the single biggest factor in output quality — a thin profile produces generic applications, and no amount of clever prompting fixes that.
/scrape searches job portals, deduplicates, and ranks by match. Portal support is market-specific: the bundled ones cover Denmark (Jobindex, Jobnet, Jobbank, Jobdanmark), plus two cross-border skills — one for LinkedIn's public unauthenticated endpoint with a region flag, one for a free REST API focused on tech roles. Other markets need /add-portal, which generates and tests a new skill.
/apply <url> is the interesting one. It runs eight steps: parse the posting, score the match, draft a tailored LaTeX CV and cover letter, hand both to a separate review agent with its own context to research the company and criticise the draft, revise, compile, inspect the rendered PDF, then run an ATS check.
Why compiling and looking at the PDF is the whole trick
Anyone who has generated a LaTeX document with a language model knows the failure mode. The source looks perfect. The PDF has an orphaned heading at the bottom of page one, the cover letter has spilled onto a second page with one line on it, and a list has silently fallen back to a different font.
This project closes that loop. The CV must compile with lualatex to exactly two pages with no orphan headings. The cover letter must compile with xelatex to exactly one page with the signature visible. The agent reads the rendered pages and iterates until the constraints hold.
When the CV runs long, it does not chop the oldest job. It scores every line on relevance to this posting, uniqueness within the document, and whether the cover letter depends on it, then removes the lowest total. That is a small detail and a large difference: it is the behaviour of someone who has actually trimmed a CV for a specific role, not someone following a rule.
The ATS check is the part nobody else does
Applicant tracking systems do not read your beautiful layout. They read the embedded text layer, and LaTeX is notoriously capable of producing a text layer that is technically present and practically garbage — icon fonts that render as an email symbol and extract as nothing, ligatures that break keyword matching, columns that scramble reading order.
The framework extracts the text layer with pypdf or pdftotext, verifies that contact details appear as literal text, checks for mojibake and reading order, and then compares keyword coverage against the posting. If neither tool is installed, it degrades to a visual keyword check rather than silently skipping.
That is the difference between a tool that produces documents and a tool that produces documents that survive contact with a hiring system.
The honest constraint: it refuses to invent
The stated rule is no fabricated skills or experience. Keywords the profile cannot support get marked as gaps rather than stuffed in. This is both an ethical position and a practical one — the interview is where invented experience gets found out, and the tool's job is to get you to the interview.
There is also a language gate. /setup collects every working language and level; undeclared languages are a hard reject, and insufficient levels get flagged rather than auto-rejected. Most job tools ignore this entirely, which is how you end up with a fluent-sounding application for a role that requires German at C1.
The privacy footgun you must not step on
This is the part I would put in bold on the download page, and the author does, but it deserves repeating: a fork of a public repository is always public. GitHub does not allow private forks of public repos. /setup writes your name, contact details, work history, and salary expectations into git-tracked files.
Fork it, run setup, push, and you have published your CV and salary expectations to the internet with a commit history.
The correct path, documented in the project's setup guide, is to create a private repository and add the original as an upstream remote. You get the same update flow without the exposure. Fork only if you intend to contribute code.
Security posture, stated plainly
Job postings are treated as untrusted input: embedded instructions are not executed, links inside them are not followed. The author is careful to say this is instruction-level defence, not a sandbox. Portal skills run on your machine without approval, so borrowed skills from other forks should be read line by line — check where the network requests go, check the package manifest for dependencies and lifecycle scripts, run the tests offline. Copying the folder is deliberately manual for exactly that reason.
The LinkedIn skill comes with its own warning: automation violates the platform's terms, and it should be used at low frequency, for personal use.
The cost of the loop
None of this is free, and the author says so. Claude Code has no free tier; you need a subscription or API credit. The compile-and-look step burns extra tokens, because the agent is reading rendered pages and iterating — sometimes three or four times on a single CV.
Whether that trade is worth it depends on what you think your time costs. Four revision cycles on a document you will send once is a lot. Four revision cycles on a document that would otherwise have an orphaned heading in the bottom margin is cheap, because that heading is the difference between "careful" and "sloppy" in a reader's first impression.
There is a second cost that is easy to miss: the profile work. /setup rewards specificity — projects, tools, quantified outcomes, what you actually did versus what your team did. A thin profile produces the generic application everyone in this category produces. The tool cannot invent the material it does not have, and the author is unusually direct that this is the limiting factor rather than the model.
What it does not do
It does not get you a referral, and referrals are where most jobs are actually won. It does not negotiate, and the only thing it knows about salary is the number you typed in during setup. It does not know that the hiring manager is a former colleague, or that the posting has been open for seven months because the team cannot agree on the role.
What it does is remove the excuse. The application will be tailored, the PDF will compile, the text layer will be parseable, and the language requirements will be respected. What you do with that is still the job search.
What this actually is
Strip away the AI framing and this is a build system for job applications: source in, artifact out, with a verification stage between them. The model is the compiler. The PDF inspection and the ATS text check are the tests. The review agent is code review.
That framing is why it is more interesting than the category it belongs to. It does not promise to get you a job. It promises that the document you send will be two pages, readable by a machine, honest about your gaps, and tailored to the posting — and it will tell you when those promises fail.
Sixty-nine applications and twenty interviews is a decent sample. It is not proof. But it is a better evidence base than most tools in this space have, and the pipeline that produced it is one you can read.
Related articles
The Three Giveaways of AI-Made Work: Four Pixels Off, an Invisible Stamp, and Nobody's Name
A diagram project's 4px rule, SynthID's invisible stamp and the Nikon scandal, and the publishers using AI without telling authors: three layers of “AI-ness,” only two of which technology can patch.
CLI-Anything Gives Desktop Software a Command Line So Agents Can Use It
Instead of teaching agents to click, HKU's lab generates Click-based CLIs from application source code, with tests, JSON output, and a package you pip install. Real backends, real renders, honest limits.
CLI-Anything Gives Desktop Software a Command Line So Agents Can Use It
Instead of teaching agents to click, HKU's lab generates Click-based CLIs from application source code, with tests, JSON output, and a package you pip install. Real backends, real renders, honest limits.
XERJ Searches Your Code So Agents Stop Reading Whole Files
A Rust search engine with autoindex, tree-sitter symbol awareness, and an Elasticsearch-compatible wire protocol. Its benchmark says 2.7x fewer tokens than grep. Its maintainer says the star count is inflated 13x.