A geophysicist loses his job in late 2025, builds a Claude Code workflow to run his own search, applies 69 times, gets 20 first interviews, signs one contract, and open-sources the machinery in March 2026. Seven months later the repository has 50,406 stars. That story is on the README, in the first screen, and it is the reason people fork it.
The story that is not on the README is in the issue tracker. Between August 19 and August 28, two different users reported that this workflow had already published personal data to GitHub — once through the fork the quick start tells you to create, once through a gh default-repository behaviour that files your application notes on someone else’s public tracker. I cloned the repo, ran its own checks, sampled 120 of its forks, and read both issues. What follows is what the numbers and the code actually support.
The numbers, before anything else
Everything below comes from the GitHub REST API on 2026-10-18 unless marked otherwise.
| Metric | Value |
|---|---|
| Stars | 50,406 |
| Forks | 16,937 (33.6% of stars) |
Watchers (subscribers_count) | 187 (0.37% of stars) |
| Commits | 336 |
| Contributors | 78 |
| Releases | 10 tags, v1.0.0 (2026-07-22) → v1.7.2 (2026-09-29) |
Commits on master after v1.7.2 | 38 |
| Created | 2026-03-18 |
Two of those ratios are unusual enough to be worth a table of their own. I pulled the same five fields for five comparable repositories on the same day:
| Repository | Stars | Forks | Forks/stars | Watchers | Watchers/stars |
|---|---|---|---|---|---|
| MadsLorentzen/ai-job-search | 50,406 | 16,937 | 33.6% | 187 | 0.37% |
| affaan-m/ECC | 282,510 | 41,987 | 14.9% | 1,408 | 0.50% |
| anthropics/skills | 181,796 | 21,531 | 11.8% | 1,117 | 0.61% |
| obra/superpowers | 301,222 | 26,896 | 8.9% | 1,110 | 0.37% |
| akitaonrails/ai-memory | 9,920 | 716 | 7.2% | 55 | 0.55% |
| android/skills | 8,426 | 555 | 6.6% | 92 | 1.09% |
A 33.6% fork ratio is not automatically suspicious here, and it would be lazy to frame it that way. This is a template that tells you to fork it (“Fork it and own it”) — high forks are the intended behaviour. What the fork ratio does tell you is that “used this repository” and “starred this repository” are measuring different populations.
What 120 public forks actually contain
The repository has exactly two tracked files where /setup writes a candidate’s identity: CLAUDE.md and .claude/skills/job-application-assistant/01-candidate-profile.md. Both ship with literal placeholder tokens — [YOUR_NAME], [YOUR_EMAIL], [YOUR_PHONE].
So I sampled forks and fetched those two files over raw.githubusercontent.com: the first 40 returned by sort=newest, the first 40 by sort=oldest, and the first 40 by sort=stargazers — 120 fork rows in total, with possible overlap between the sort orders. Each file was classified as still containing the template tokens, tokens gone (personalized), missing (404), or empty.
| File | Placeholder intact | Personalized | Missing |
|---|---|---|---|
CLAUDE.md | 113 | 3 | 3 (+1 empty) |
01-candidate-profile.md | 113 | 4 | 3 |
4 of 120 forks (3.3%) had replaced the placeholder tokens in at least one of the two files. The other 96.7% are byte-for-byte template copies at those paths.
I want to be careful about what this proves, because the obvious reading is wrong. SETUP.md explicitly offers “committing locally without pushing” as a legitimate way to run this, so an untouched fork does not mean an unused fork. What the sample does establish is narrower and still useful: the fork count cannot be read as an installation count, and if you were going to worry about leaked profiles at scale, the empirical leak rate is small — roughly 560 forks if the 3.3% rate held across all 16,937, which is a projection, not a measurement.
The 187 watchers matter for the same reason. I ran three Hacker News queries through the Algolia API — “MadsLorentzen”, “ai-job-search”, and “AI job search Claude Code” — and the only submissions belonging to this project scored 1, 2, and 1 points with zero comments. A repository at 50,000 stars with no Hacker News discussion did not travel through Hacker News. GitHub Trending, a Trendshift badge, and LinkedIn did that work. None of this is wrongdoing; it is just what the number means.
Leak one: the quick start publishes the profile
The README’s step 1 is:
gh repo fork MadsLorentzen/ai-job-search --clone
cd ai-job-search
Step 3 is /setup, which writes your name, address, phone, email, LinkedIn, employment history with dates, salary floor, deal-breakers and behavioural self-assessment into CLAUDE.md, .claude/skills/job-application-assistant/01-…07-*.md, cv/main_example.tex and .claude/skills/job-scraper/search-queries.md. All of those are tracked, and they have to be tracked — that is how upstream updates three-way-merge around your personalization instead of colliding with it. The genuinely sensitive material (documents/, salary_data.json, generated CVs and cover letters, the application archive) is gitignored; the profile is not.
GitHub does not allow a private fork of a public repository. So step 1 guarantees a public remote, step 3 guarantees tracked personal data, and the natural step afterwards is git push.
Issue #345, filed 2026-08-19, is that sequence happening to a real person. The reporter’s own words:
I hit this myself: I copy-pasted the README command, ran
/setup, and only discovered the exposure afterwards when I went looking for how VCS was meant to work in this repo.
The issue’s analysis of why the existing safeguards missed it is sharper than the summary:
The warning existed, but downstream of the decision.
SETUP.mdline 293 had it, correctly and in full — but it was step 1 of §8, six sections after §2 “Fork and clone” told the user to fork.
And on /setup’s own privacy note: it printed in “Step 4: Confirm & Next Steps” — after every file had been written. At that point the advice “do not push these commits” required abandoning the remote that step 1 had just told you to create.
That is a documentation bug with a data-loss shape, and the maintainer treated it as one. The current README carries an [!IMPORTANT] block directly under the fork command, and /setup now runs a pre-flight check before writing anything:
Run
git remote get-url origin; if the command fails (no remote, or not a git checkout), skip this check silently. If there is a GitHuborigin, check it withgh repo view <owner/repo> --json visibility,isForkwhenghis available. If the origin is a public fork of the template — or its visibility cannot be determined — warn now and wait …
Two details in that fix are worth appreciating. It fails toward warning when visibility cannot be determined, and the fix is pinned by tests/test_onboarding_privacy.py, which asserts that the warning text sits inside the same Markdown section as the gh repo fork command in both README and SETUP.md. A regression that moves the warning away from the decision fails CI. That is a more serious treatment of a documentation problem than most projects give a code problem.
But notice what the fix does not do. It adds a warning and a prompt. It does not make the safe path the default.
Leak two: gh files your job search on a stranger’s tracker
Issue #389, filed nine days later on 2026-08-28, is the part I had not seen in any repository of this kind, and it is the more dangerous of the two.
gh repo fork --clone sets the upstream repository as gh’s default repository, and gh uses the default for gh issue create. A personalized fork is exactly where a user wires up automation — “file a tracking issue for each application” is a natural request to hand an agent. No --repo, no prompt, nothing to confirm. The issue lands on MadsLorentzen/ai-job-search.
The reporter did not hypothesise about this. They cited four live instances from two independent users inside one week: #386/#387/#388, described as one user’s application plans — target companies, fit scores, personal decision constraints, in Japanese — and #381, another user’s incident log referencing their private repo layout.
I checked those four numbers on 2026-10-18. All four return HTTP 410 Gone — removed, not closed. That is a fact with an awkward double edge. On one hand it demonstrates the maintainer can clean up a mess users cannot clean up themselves (only repository admins can delete an issue; authors cannot). On the other hand, it means the primary evidence for the incident no longer resolves for anyone who reads #389 today: the issue body points at four URLs that are now dead, and GitHub keeps no public tombstone.
The current SETUP.md response is a hard rule rather than a warning:
The
set-defaultline is not optional.gh repo fork --clonesets the upstream repo as gh’s default repository … Without it, any latergh issue createrun from this clone — by you or by an agent you have asked to track your applications — silently files on the upstream public tracker, publishing whatever the issue contains under your GitHub identity, on a repo where you cannot delete it (#389).
That is the correct fix, and it is also the one that most needs a code guard rather than a paragraph — because the whole failure mode is an agent acting without a human reading a paragraph. There is no such guard. The CI job that could plausibly catch it (the placeholder-integrity grep) is scoped to the upstream repository only.
Where the numbers and the code disagree about safety
Here is the structural problem, and it is not the maintainer’s sloppiness — it is a design tension the repository states openly in .github/workflows/ci.yml:
Fork-friendly by design: forks personalize CLAUDE.md, the skill files, and cv/main_example.tex via /setup, so the placeholder-integrity job and the exact page-count/content assertions run only on the upstream template repo.
Read that twice. The job whose error message is expected placeholder token $2 - personal data may have been committed is deliberately switched off in exactly the place where personal data gets committed: your fork. It cannot be switched on, because a personalized fork is the expected state. The only barrier between a first-time user and a public profile is a blockquote that says “wait”.
I ran the guard that does exist, against the upstream clone:
security_guards: OK (permissions allowlist, hooks allowlist, gitignore rules, package manifests)
That job is worth understanding before you dismiss this repository. It fails pull requests that widen .claude/settings.json permissions (the CLIs run pre-approved), that weaken the personal-data .gitignore rules, or that add npm lifecycle scripts. Actions are pinned to commit SHAs and the token is read-only. The workflow header even states its own limit:
a PR can edit this workflow itself, so these guards catch accidents and casual attempts, not a determined author — branch protection with required checks and human review of workflow/settings diffs remain the real backstop.
The parts nobody forks it for are the good parts
If you only read the star count you would expect a prompt pack. What is in the tree is stranger and better.
tools/robots_check.py implements RFC 9309 with fail-closed semantics, and it documents the specific ways naive parsers fail open.
- longest-match wins; on equal specificity Disallow wins
- a Disallow for either “*” or “Claude-User” blocks the retry
- blank lines inside a record do not end it (Python’s robotparser drops rules in that case, which fails open — see tests)
- one leading UTF-8 byte-order mark is skipped (left in, it hides a first “User-agent” line and drops that whole group, which fails open)
- 404 means no published policy, which is permission
- any other failure to read robots.txt leaves permission unconfirmed, and the retry does not happen — including a User-agent, Allow or Disallow line holding U+FFFD
Two of those are bugs I have seen in production crawlers. The soft-200 case is handled too: a host answering /robots.txt with an HTML error page parses to zero rules, and zero rules read as “allowed”, so the script treats a non-empty body with no recognised directive as unreadable rather than as permission. There is even a comment explaining that unpinned decoding on a Turkish Windows machine read a file as cp1254, the pipe reader thread died, stdout came back None, and a real domain read as UNCONFIRMED. That is a bug report turned into a code comment, which is what good engineering looks like.
The suite passes. I built a venv with pytest and pyyaml and ran it:
598 passed, 3 skipped, 328 subtests passed in 51.87s
Fifty-one seconds of green on a 50,000-star repository is not the norm. Neither is pinning a warning’s location in Markdown with a test.
The application pipeline has a real fairness check. /apply compiles both PDFs (lualatex for the CV, xelatex for the cover letter), then measures the rendered output with tools/verify_layout.py — orphaned entry titles, footer collisions, bullets falling back to the body font. /apply also runs an ATS pass on the PDF’s extracted text layer, because an applicant-tracking system reads the embedded text, not the page, and LaTeX can silently produce a PDF whose contact details extract as icon glyphs. When a CV overflows two pages it does not cut the oldest section; it scores each line by relevance to the posting, uniqueness in the document, and whether the cover letter depends on it.
The fabrication rule is written down, and its limits are written down next to it. The README claims: “All claims in the CV and cover letter are verified against your actual profile. The system never fabricates skills or experience.” The implementation is a “Grounding Audit” against three sources (01-candidate-profile.md, the master CV, and CLAUDE.md’s profile section), plus a drafter-reviewer split where a second agent with fresh context critiques the draft.
That is prompt-level discipline, not a deterministic check — and the repository says so itself, in the part I would have quoted even if it made the project look worse:
This is not bookkeeping. A fact that exists only in chat will be treated as unsupported by a later session and stripped from drafts as a fabrication. Anything absent from the sources does not exist as far as future drafting is concerned, and the loss is silent — a real achievement quietly disappears from every subsequent CV.
A tool that strips true statements because it cannot verify them is the honest version of a tool that claims never to invent. Both failure modes come from the same mechanism.
Four things that are still open
1. There is no remediation path for data that is already out. Neither issue, nor SETUP.md, nor the README describes what to do after a profile has been pushed: no git filter-repo, no force-push guidance, no deletion procedure. /reset profile clears local files. The /reset command “shows exactly what will be deleted and requires you to type RESET to confirm” — and what gets deleted is on your disk. GitHub cannot make your fork private; the README says so plainly. The pre-flight check reduces the chance of the mistake; nothing reduces its cost.
2. A global audience, a Danish tool surface. Six portal CLIs ship. Four are Danish job boards (Jobindex, Jobnet, Jobbank, Jobdanmark). The two that are country-agnostic are linkedin-search and freehire-search — and the second is described as tech-focused, so a nurse in Lisbon and a logistics manager in Osaka get LinkedIn or nothing. /add-portal scaffolds a new portal CLI and test-runs one live query before registering it, which is a genuinely good answer; it is also work you do yourself. The salary tool is worse than the README’s “works with any salary data you provide” suggests: its company-name matcher hardcodes Danish legal suffixes (a/s, aps, i/s, p/s, k/s, ivs, amba) and Danish transliteration (ø→o, æ→ae, å→aa). Supply your own JSON and it works; expect it to normalise “GmbH” or “S.p.A.” and it will not.
3. The release channel has stalled while master moves. The last tag is v1.7.2 on 2026-09-29. Since then, 38 commits have landed on master, including 14 on October 15 and 10 on October 17. SETUP.md’s §8 opens with “Prefer releases over raw master. Tagged releases are vetted checkpoints” — and then step 3 of the same section instructs git merge upstream/master. Both statements are in the document. For a fork that follows step 3, “vetted checkpoint” stops describing what you are running.
4. The track record is unverifiable and honestly labelled. 69 applications, 20 first interviews, one signed contract. There are no logs in the repository, and the README points to the author’s LinkedIn for the long version. It is presented as personal experience, not as a study, which is the right way to present it — but it is not evidence that the workflow will produce a 29% first-interview rate for you, and nothing in the repo pretends otherwise.
How to run it without publishing anything
The project documents this, in §8 of a file most users never open. Collected in one place:
- Do not fork. Create a private repository, then
git remote add upstream https://github.com/MadsLorentzen/ai-job-search.git. Every update workflow in §8 still works — merge a tag, runtools/check_upstream_updates.py, or triage commits withtools/upstream_triage.py. - If you did fork, set the default immediately:
gh repo set-default <your-username>/ai-job-search. Otherwise an agent you asked to “file a tracking issue” writes to the upstream tracker. - Decide the commit question before
/setup, not after. Committing the personalization locally is fine; pushing it to a fork is not; pushing it to a private repo is fine. - Know what
/resetcovers: local profile files and localdocuments/. Not your remote, not your history, not an issue someone else owns. - Read any portal skill before you run it. The repository refuses to ship an installer for community skills, and gives the reason: “an installer that fetched them from third-party repos for you would skip the one check that matters: you, reading the code first.”
And one quote worth keeping verbatim if you use the LinkedIn CLI at all:
Intended for personal use only — automated access is against LinkedIn’s Terms of Service, so keep volume low.
The CI file is explicit that this is why portal smoke tests are not in CI: “CI-automated requests would violate that.” Personal use is the line the project draws, and it draws it in the pipeline rather than only in a README footnote.
FAQ
Is it free? MIT licensed. The toolchain is not: Claude Code has “no free tier” per the README, so budget a Claude Pro/Max/Team subscription or API credits, plus Bun and a LaTeX distribution.
Does /setup publish my CV by itself? No. It writes into tracked files on your disk. Publication happens on git push to a public remote — which is what the README’s step 1 creates, and why issue #345 exists.
Can I undo it if I already pushed? Not from anything in this repository. GitHub will not convert a public fork to private, /reset is local-only, and issues filed on the upstream tracker belong to that repository’s admins. Treat the push as irreversible.
Is 50,406 stars evidence that it works? It is evidence that it spread. 33.6% of those stars correspond to forks, 0.37% to watchers, 113 of 120 sampled forks are untouched templates, and no Hacker News thread on it exceeded 2 points. The design is coherent and the tests pass; those are better signals than the star count.
Will it invent experience on my CV? The prompts forbid it and the Grounding Audit strips ungrounded claims against three sources. It is instruction-level, not a deterministic check, and the repo documents the trade-off: a true fact that never made it into the profile gets stripped as a fabrication. Read every generated line.
Does it work outside Denmark? The core pipeline (profile, fit evaluation, drafter-reviewer, PDF verification) is market-agnostic. The portal layer is not: four of six CLIs and the salary matcher’s normalisation rules are Danish. Use linkedin-search or freehire-search, or write your own portal with /add-portal.
Is scraping the portals legal? The project gates its one browser-header retry behind an RFC 9309 robots.txt check that fails closed, and labels LinkedIn automation as a ToS violation for anything beyond personal use. That is a defensible stance, not a legal opinion — the decision remains yours.
What this repository is
It is not a hype artefact with a prompt folder. There is an RFC 9309 parser here with comments about a Turkish Windows codec, 598 passing tests, a PDF layout measurer, a patch-id-based triage tool for forks, and a CI job that fails a pull request for adding an npm postinstall script.
It is also a repository whose two most-viewed onboarding steps each published somebody’s personal data, and whose own CI is architecturally unable to notice when that happens in the place it happens most. The fix for the first was a warning moved to the point of decision. The fix for the second was a sentence — correct, well-argued, and unenforceable by code, in a workflow where an agent does the filing.
If you are going to run it, the difference between a good experience and a bad one is not the star count. It is whether you read §8 before step 1.