A Claude Code plugin that runs your entire job application pipeline: it parses your resume, finds matching jobs, tailors a distinct resume for each job, renders it as a polished PDF that looks like your original and matches its length, invents nothing, and then auto-fills the application — either pausing for you to submit (assisted) or submitting on its own (autonomous).
Give it your resume (PDF, DOCX, or TXT). It will:
- Parse the resume into a structured profile (titles, skills, employers, dates, metrics, education, contact).
- Search for matching jobs across web boards, your logged-in LinkedIn session, and/or job URLs you supply, then rank and show you the top K (configurable, default 10) for confirmation.
- Capture the original's design — fonts, colors, layout, section order — into a per-resume template so every tailored version looks identical to your original.
- Tailor the resume to each chosen job, reordering and rephrasing your real content to surface the job's requirements — never adding anything you didn't already have.
- Verify + render a length-matched PDF. A fact-checker hard-fails on any invented number, date, or contact; a page-count gate re-renders until the length matches the original.
- Apply — fills the portal form and uploads the tailored PDF, then either pauses for your review (assisted) or submits and retries transient failures (autonomous).
| Guarantee | How it's enforced |
|---|---|
| Looks like your original | style-capture reproduces the original's formatting/colors/layout; render_pdf.py uses prefer_css_page_size so the template's CSS @page fully controls page geometry |
| Same length as the original | render_pdf.py counts rendered pages and exits non-zero on overflow → the tailoring loop trims and re-renders until it matches |
| No invented facts | verify_facts.py extracts every number, date, and contact from the tailored resume and hard-fails if any is absent from the original |
┌─────────────────────────────┐
resume.(pdf|docx|txt) ───────▶│ /job-hunt (orchestrator) │
└──────────────┬──────────────┘
│ drives the pipeline
┌───────────────────────────────────────┼───────────────────────────────────────┐
▼ ▼ ▼ ▼ ▼
┌────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│/parse- │ │/find-jobs │ │style-capture│ │/tailor- │ │/apply │
│ resume │ │ │ │ (skill) │ │ resume │ │ │
└─────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘
│ skill: │ skill: │ │ skills: │ skill:
│ resume-parsing │ job-matching │ │ resume-tailoring │ application-
▼ ▼ ▼ │ + pdf-rendering │ filling
┌────────────┐ ┌──────────────┐ ┌───────────────┐ ▼ ▼
│extract_ │ │ WebSearch / │ │ Read original │ ┌────────────────┐ ┌──────────────┐
│resume.py │ │ WebFetch + │ │ (visual) → │ │ verify_facts.py│ │ Playwright │
│ │ │ Playwright │ │ resume_ │ │ (hallucination│ │ MCP browser │
│ PDF/DOCX/ │ │ (LinkedIn) + │ │ template.j2 │ │ gate, exit 1)│ │ fills form + │
│ TXT → text │ │ user URLs │ │ (matches look)│ └───────┬────────┘ │ uploads PDF │
└─────┬──────┘ └──────┬───────┘ └───────┬───────┘ │ └──────┬───────┘
▼ ▼ │ ▼ │
profile.json ranked top-K ───────────────┘ ┌────────────────┐ │
(structured) [you confirm] │ render_pdf.py │ ▼
│ Jinja+Chromium │ assisted → you submit
│ → PDF, page- │ autonomous → submit
│ count gate │ + retry
│ (exit 2 = trim)│
└───────┬────────┘
▼
applications/<company>-<role>/tailored_resume.pdf
Layers
- Commands (
commands/*.md) — the slash-command entry points you invoke. - Skills (
skills/*/SKILL.md) — the "how-to" each step follows. - Scripts (
scripts/*.py) — deterministic mechanical work (extraction, rendering + length gate, fact verification). - Playwright MCP — one Chromium powers both browser automation (LinkedIn, form filling) and HTML→PDF rendering.
- Claude Code (CLI, desktop, or IDE extension).
- Python 3.9+ with
pip. - Node.js /
npx— for the Playwright MCP server (auto-run on first use).
Install directly from this GitHub repo — no cloning required:
# Add the marketplace, then install the plugin
claude plugin marketplace add rupakc/job-hunter
claude plugin install job-hunter@job-hunterOr, from inside a Claude Code session:
/plugin marketplace add rupakc/job-hunter
/plugin install job-hunter@job-hunter
This installs at user scope by default (available across all your projects).
Use --scope project to install it only for the current project. Verify with:
claude plugin list # job-hunter@job-hunter → Status: ✔ enabledRestart Claude Code / start a new session after installing — plugins load at session start, so the
/job-huntcommands appear in the next session.
The plugin's scripts need Python packages and a Chromium browser (used for both PDF rendering and browser automation):
pip install pdfplumber python-docx jinja2 pyyaml
playwright install chromiumOn first use, approve the playwright MCP server when Claude Code prompts.
git clone https://github.com/rupakc/job-hunter.git
claude plugin marketplace add ./job-hunter # local path is also a valid marketplace
claude plugin install job-hunter@job-hunter
pip install -r job-hunter/job-hunter/requirements.txt
playwright install chromiumVerify the scripts pass their tests:
cd job-hunter/job-hunter && python -m pytest -q # expect: all tests passing/job-hunt path/to/resume.pdf --top-k 10 --mode assisted
Runs parse → style-capture → find-jobs → (you confirm the list) → tailor → verify → render → apply, for each confirmed job.
Flags
| Flag | Default | Meaning |
|---|---|---|
--top-k N |
10 |
How many ranked matches to present for confirmation |
--mode assisted|autonomous |
assisted |
Fill-and-pause vs. fill-and-submit |
--sources web,linkedin,urls |
web |
Which job sources to search |
[urls...] |
— | Specific job posting URLs to tailor/apply to directly |
/parse-resume path/to/resume.pdf
/find-jobs --top-k 15 --sources web,linkedin
/find-jobs https://boards.greenhouse.io/acme/jobs/123 # or apply to a specific URL
/tailor-resume applications/acme-senior-engineer
/apply applications/acme-senior-engineer --mode assisted
# Broad hunt across web boards, review 10, fill forms but you click submit
/job-hunt ~/Documents/resume.pdf
# Include your logged-in LinkedIn, look at 20, hand-pick, then autonomous submit
/job-hunt ~/resume.docx --top-k 20 --sources web,linkedin --mode autonomous
# Tailor + apply to three specific postings you already found
/job-hunt ~/resume.txt https://job1 https://job2 https://job3
- assisted (default) — opens the portal in a browser you're logged into, fills every field and uploads the tailored PDF, then stops for you to review and click Submit. Handles login / CAPTCHA / 2FA naturally.
- autonomous (opt-in) — fills and submits, retrying transient failures (network, stale element) with a bounded retry count. Never bypasses CAPTCHA/2FA (pauses and hands to you). Shows a ToS/account-risk warning first.
⚠️ LinkedIn & portal automation carries ToS and account-ban risk. Assisted mode is the safe default. Use autonomous mode and logged-in LinkedIn scraping at your own discretion.
Each application gets its own folder:
applications/<company>-<role>/
├── job.md # the job posting content
├── resume_template.html.j2 # design captured from your original resume
├── resume_data.json # tailored, fact-verified content
├── tailored_resume.html # rendered source
├── tailored_resume.pdf # the polished, length-matched resume you submit
├── answers.md # screening / cover-letter answers
└── status.json # application state + action log
job-hunter/
├── .claude-plugin/plugin.json # plugin manifest
├── .mcp.json # Playwright MCP server declaration
├── commands/ # /job-hunt, /parse-resume, /find-jobs, /tailor-resume, /apply
├── skills/ # resume-parsing, style-capture, job-matching,
│ # resume-tailoring, pdf-rendering, application-filling
├── scripts/ # extract_resume.py, render_pdf.py, verify_facts.py
├── templates/resume.html.j2 # fallback template (used only if design can't be captured)
├── tests/ # pytest suite + fixtures
├── requirements.txt
└── README.md
docs/superpowers/ # design spec + implementation plan
- DOCX/TXT page count is a line-count heuristic; PDF originals are exact.
- The numeric anti-hallucination check is set-based — e.g. "led 40 engineers"
passes if
40appears anywhere in your original. It catches invented values, not every reassignment of existing ones. - Pixel-perfect visual fidelity isn't guaranteed for complex multi-column PDF originals; style-capture reproduces the design faithfully but approximately.
- The length gate only flags overflow (too long); it doesn't force a shorter resume up to the original's page count.
cd job-hunter
python -m pytest -v # run the full test suiteDesign spec and implementation plan live under docs/superpowers/.
No license file yet — add one before distributing.