PurujitP/JobForge

Python

0

21 commits

updated Oct 4, 2026

See the code

See what people are saying

SourceMessageScoreDate

Built a cv tailor that turns a JD into a 1-page ATS PDF — open source (r/SideProject)

Built this while job hunting. Paste a JD + your profile → it ranks your bullets, rewrites them for that role, and spits out a Jake’s-style one-page ATS PDF. Guardrails so it can’t invent metrics, tools, or JD keywords you didn’t earn. Try it:…

0

Oct 4, 2026

README

Resume Tailor

CLI (and web app) that turns a JD + data/profile.json into a Jake's-style one-page ATS PDF. Uses Gemini (by default) to rank warehouse bullets, then rewrites them role by role (src/resume_tailor/prompts/: rewrite.md + blacklist.md + verb-bank.md). A code guard rejects any rewrite that adds a number, tool, or unbacked JD term; the original is kept.

Layout

src/resume_tailor/   # engine: pipeline.py runs rank → rewrite → pack → render; cli.py wraps it
  prompts/ templates/
api/                 # FastAPI backend, calls resume_tailor.pipeline
frontend/            # Next.js UI, fetch('/api/...')
tests/               # test_core.py + example.tex golden
data/                # local state (gitignored except profile.example.json)
inputs/ outputs/     # your JDs / generated resumes (gitignored)

Setup

python3 -m venv .venv && source .venv/bin/activate
pip install -e .              # CLI only; pip install -e ".[web]" for the web app too
cp .env.example .env          # set GEMINI_API_KEY
# place tectonic at bin/tectonic (or on PATH)

Run every command from the repo root: data/, outputs/, bin/ and .env are relative to it.

Profile

python -m resume_tailor init-profile   # data/profile.example.json → data/profile.json

Fill data/profile.json from your existing resume:

  1. Copy identity, skills, education, experience bullets and projects in.
  2. Strip LaTeX (\textbf{}, \,, {,}) into plain text.
  3. Tag each bullet with 3–8 lowercase keywords for JD overlap.
  4. Fill keyword_bank with stack tokens you want matched.

Keep data/profile.example.json free of real contact info; it is the only tracked file in data/.

Usage

python -m resume_tailor tailor inputs/jd.example.txt
python -m resume_tailor tailor inputs/jd.example.txt --no-llm    # keyword select only
python -m resume_tailor tailor inputs/jd.example.txt --no-rewrite  # rank only, original bullet text
python -m resume_tailor tailor inputs/jd.example.txt --no-pdf
python -m resume_tailor tailor inputs/jd.example.txt --profile path/to/profile.json

Writes First-Last-Resume.pdf and gaps.md (JD gaps + bullets that still need a real number). Enforces: bullet caps (5/5/2), max 5 skills per line, no coursework for experienced roles, metric bolding, PDF ≤ 1 page.

Tests

python tests/test_core.py   # no network; the pipeline/golden check needs tectonic

Web UI (Next.js) + API (FastAPI)

pip install -e ".[web]"
# terminal 1, repo root
python -m api.main                # :8765, store in data/mongita
# terminal 2
cd frontend && npm run dev        # :3000 proxies /api → :8765

Signup → profile fields; login → generate page. Edit profile via top-right menu. A user's API key (set on signup/edit) is used for their generations; otherwise GEMINI_API_KEY.

PurujitP/JobForge

Python

0

21 commits

updated Oct 4, 2026

See the code

See what people are saying

SourceMessageScoreDate

Built a cv tailor that turns a JD into a 1-page ATS PDF — open source (r/SideProject)

Built this while job hunting. Paste a JD + your profile → it ranks your bullets, rewrites them for that role, and spits out a Jake’s-style one-page ATS PDF. Guardrails so it can’t invent metrics, tools, or JD keywords you didn’t earn. Try it:…

0

Oct 4, 2026

README

Resume Tailor

CLI (and web app) that turns a JD + data/profile.json into a Jake's-style one-page ATS PDF. Uses Gemini (by default) to rank warehouse bullets, then rewrites them role by role (src/resume_tailor/prompts/: rewrite.md + blacklist.md + verb-bank.md). A code guard rejects any rewrite that adds a number, tool, or unbacked JD term; the original is kept.

Layout

src/resume_tailor/   # engine: pipeline.py runs rank → rewrite → pack → render; cli.py wraps it
  prompts/ templates/
api/                 # FastAPI backend, calls resume_tailor.pipeline
frontend/            # Next.js UI, fetch('/api/...')
tests/               # test_core.py + example.tex golden
data/                # local state (gitignored except profile.example.json)
inputs/ outputs/     # your JDs / generated resumes (gitignored)

Setup

python3 -m venv .venv && source .venv/bin/activate
pip install -e .              # CLI only; pip install -e ".[web]" for the web app too
cp .env.example .env          # set GEMINI_API_KEY
# place tectonic at bin/tectonic (or on PATH)

Run every command from the repo root: data/, outputs/, bin/ and .env are relative to it.

Profile

python -m resume_tailor init-profile   # data/profile.example.json → data/profile.json

Fill data/profile.json from your existing resume:

  1. Copy identity, skills, education, experience bullets and projects in.
  2. Strip LaTeX (\textbf{}, \,, {,}) into plain text.
  3. Tag each bullet with 3–8 lowercase keywords for JD overlap.
  4. Fill keyword_bank with stack tokens you want matched.

Keep data/profile.example.json free of real contact info; it is the only tracked file in data/.

Usage

python -m resume_tailor tailor inputs/jd.example.txt
python -m resume_tailor tailor inputs/jd.example.txt --no-llm    # keyword select only
python -m resume_tailor tailor inputs/jd.example.txt --no-rewrite  # rank only, original bullet text
python -m resume_tailor tailor inputs/jd.example.txt --no-pdf
python -m resume_tailor tailor inputs/jd.example.txt --profile path/to/profile.json

Writes First-Last-Resume.pdf and gaps.md (JD gaps + bullets that still need a real number). Enforces: bullet caps (5/5/2), max 5 skills per line, no coursework for experienced roles, metric bolding, PDF ≤ 1 page.

Tests

python tests/test_core.py   # no network; the pipeline/golden check needs tectonic

Web UI (Next.js) + API (FastAPI)

pip install -e ".[web]"
# terminal 1, repo root
python -m api.main                # :8765, store in data/mongita
# terminal 2
cd frontend && npm run dev        # :3000 proxies /api → :8765

Signup → profile fields; login → generate page. Edit profile via top-right menu. A user's API key (set on signup/edit) is used for their generations; otherwise GEMINI_API_KEY.

Languages

Python

70.3%

TypeScript

17.4%

CSS

5.8%

TeX

3.8%

Jinja

1.5%