Skip to main content

ATS-optimized, recruiter-ready resume tailoring from the command line

Project description

tailor-resume

Open in Streamlit CI

ATS-optimized, recruiter-ready, single-page resume tailoring — powered by Claude Code.

Paste a job description and your work history. Get a tailored LaTeX resume with quantified bullets, skills gap analysis, and ATS score — in minutes. No fabrication. No templates with your name baked in.


Project Status

Tier 1 — Zero infrastructure, immediate reach

Feature Status Notes
Core pipeline (parse → gap → render) ✅ Done stdlib only, 190 tests
Claude Code skill (/tailor-resume) ✅ Done per-project + global install
MCP plugin (4 typed tools) ✅ Done stdio, auto-registered
ATS Relevance Gate (score bands + honest ceiling) ✅ Done ≥80→97+, 60-79→90+, <50→decline
make install-global ✅ Done one-command global install
Auto-invoke from natural language ✅ Done CLAUDE.md hook
Streamlit web app (3-tab browser UI) ✅ Done profile→tailor→download + SQLite save/load sidebar
PyPI package (pip install tailor-resume) ✅ Done pyproject.toml + tailor_resume/ package + Python API
Docker image (docker run narendranathe/tailor-resume) 📋 #33 bundles Python + pdflatex + deps; one command → PDF
Streamlit Community Cloud deploy ✅ Live https://tailor-resume-ai.streamlit.app/
Fly.io MCP deploy 📋 Pending fly deploy — needs FLY_API_TOKEN secret in GitHub
PyPI publish 📋 Pending configure trusted publisher, push v0.1.0 tag

Tier 2 — Hosted web app (1–2 weeks)

Feature Status Notes
Hosted MCP server (HTTP/SSE, Fly.io) ✅ Done server.py + Dockerfile + fly.toml + CI deploy
FastAPI backend (/tailor + /profile + /health) 📋 #34 Clerk auth · Fly.io · TRACER for all integrations
React web app (gap chart + ATS score + download) 📋 #35 Vite + Recharts · Vercel deploy · Clerk auth

Tier 3 — Integrations (high leverage)

Feature Status Notes
autoapply-ai integration 📋 #36 high-score job → "Tailor Resume" in sidepanel → .tex in vault
Chrome extension button (LinkedIn/Greenhouse/Lever) 📋 #37 content script → scrapes JD → calls API → ATS + download
JobScout webhook 📋 #38 dream job alert fires → auto-tailor + .tex link in Discord/Telegram

Tier 4 — Multi-user SaaS

Feature Status Notes
Profile persistence (Supabase + Pinecone) 📋 #39 upload once, all future JDs pull from RAG store
Cover letter companion 📋 #40 same pipeline, 1-page LaTeX cover letter output
Subscription tiers (Free + Pro via Stripe) 📋 #41 5/mo free · unlimited + Pinecone + cover letters = Pro

Scaling Roadmap

Week 1-2  (done) Streamlit app + PyPI package      → any Python dev or browser user
Week 3-4  (done) Hosted MCP (Fly.io)               → any Claude Code user globally, zero install
Month 2          FastAPI+React web app + Clerk/Supabase → true multi-user product
                 Docker image                        → zero-dep single-command PDF
Month 2-3        autoapply-ai integration            → job appears → resume auto-generated
                 Chrome ext "Tailor Resume" button   → works on LinkedIn/Greenhouse/Lever
Month 3+         JobScout webhook                   → score threshold → auto-tailor + attach PDF
                 Cover letter companion              → same pipeline, different template
                 Profile persistence (Supabase)     → upload once, reuse forever
                 Subscription tiers (Stripe)        → Free + Pro tiers

Install

Local (use only from this repo):

git clone https://github.com/narendranathe/tailor-resume ~/projects/tailor-resume
cd ~/projects/tailor-resume
pip install -r requirements.txt
python -m pytest tests/ -v   # 190 tests, no API keys required

Via pip (no clone needed):

pip install tailor-resume
tailor-resume --jd jd.txt --artifact resume.md --name "Jane Smith" --email "jane@example.com"

Global (use /tailor-resume and MCP tools from any project — recommended):

git clone https://github.com/narendranathe/tailor-resume ~/projects/tailor-resume
cd ~/projects/tailor-resume
pip install -r requirements.txt
make install-global           # copies skill, registers MCP, installs optional deps
# Restart Claude Code, then type /tailor-resume from any project

make install-global is idempotent — safe to run again after git pull to pick up skill updates.


Two ways to use it in Claude Code

This repo ships with both a skill (slash command) and an MCP plugin (structured tools). Use whichever fits your workflow.

Skill (/tailor-resume) MCP Plugin
How to activate /tailor-resume slash command Automatic on project open
How Claude uses it Reads instructions, runs shell commands Calls typed Python functions directly
Input Paste text in chat Structured JSON arguments
Best for Interactive, conversational tailoring Programmatic use, scripting, agents

Python API (after pip install tailor-resume)

from tailor_resume import extract_profile, analyze_gap, render_latex, run_pipeline

# Parse a resume
profile = extract_profile(open("resume.md").read(), format="markdown")

# Score against a JD
gap = analyze_gap(open("jd.txt").read(), open("resume.md").read())
print(f"ATS score: {gap.ats_score_estimate}/100")
print("Top gaps:", [g.category for g in gap.top_missing[:3]])

# Full pipeline in one call
result = run_pipeline(
    jd_text=open("jd.txt").read(),
    artifact_text=open("resume.md").read(),
    artifact_format="markdown",
    output_path="out/resume.tex",
    name="Jane Smith",
    email="jane@example.com",
    linkedin="https://linkedin.com/in/jane",
)
print(f"Wrote {result['output_path']} · ATS: {result['ats_score']}/100")

Option A: Claude Code skill (slash command)

Per-project (recommended — no copy needed)

If you cloned the repo, the skill is already at .claude/skills/tailor-resume/. Claude Code detects it automatically when you open the project folder.

Open the project in VS Code with the Claude Code extension, or run Claude Code from the repo root:

cd tailor-resume
claude

The skill appears in Claude's available skills list immediately.

Global install (use from any project)

make install-global

This single command:

  1. Registers the MCP server in ~/.claude/.mcp.json
  2. Copies the skill to ~/.claude/skills/tailor-resume/
  3. Installs optional deps (pinecone, openai) for RAG + semantic search

Restart Claude Code once. The skill and MCP tools are then available in every project.

Auto-invoke from natural language (optional)

Add this section to your global ~/.claude/CLAUDE.md so Claude invokes the skill automatically when you mention resume work — no slash command needed:

## Auto-invoke skills

When the user expresses any of the following intents, immediately invoke the `/tailor-resume` skill
without waiting to be asked — do not respond conversationally first:

- Editing, updating, or improving a resume or CV
- Tailoring a resume to a job description or role
- Skills gap analysis against a job posting
- Generating a LaTeX or PDF resume
- Extracting achievements from LinkedIn, GitHub, or a work history blob
- Aligning experience to a job description

The skill is at `~/.claude/skills/tailor-resume/`. Invoke it with `/tailor-resume`.

After adding this, saying "edit my resume" or "tailor this to the JD" in any Claude Code session triggers the skill immediately.

Use the skill

Or invoke explicitly from any Claude Code chat:

/tailor-resume

Claude will ask for:

  1. Job description — paste the full JD text
  2. Your experience — choose one or more input formats (see below)

Input formats

Work experience blob (easiest):

Company: DataWorks Inc
Title: Senior Data Engineer
Dates: Jan 2022 – Present

- Built governed semantic layer on Databricks, cutting metric discrepancies from 12/week to zero
- Owned CI/CD via Azure DevOps, compressing deployments from 8 weeks to 6 days
- Reengineered ETL to CDC merge upserts, cutting runtime from 45 min to 9 min and costs by 68%

Key metrics:
- Baseline: 45 min runtime → Outcome: 9 min
- Cost: $4,100/month saved

Existing resume file — paste the content directly:

  • LaTeX (.tex) — paste raw LaTeX
  • Markdown (.md) — paste markdown
  • PDF/DOCX — paste extracted text

LinkedIn PDF: Export your LinkedIn profile as PDF, paste the extracted text.

GitHub repos: Share repo URLs — Claude reads READMEs and project descriptions to surface achievements.

What Claude produces

  1. Skills gap analysis — top 5 signals the JD requires that your resume doesn't show
  2. Tailored bullets — rewritten per role using the Accomplished X as measured by Y by doing Z formula
  3. Professional summary — 4–5 sentences, JD-aligned, no buzzwords
  4. Single-page LaTeX — ready to compile
  5. PDF export instructions

Claude runs up to 3 refinement passes automatically (draft → tighten metrics → compress to one page).


Option B: MCP plugin (structured tools)

The MCP plugin exposes the pipeline as four typed tools that Claude Code calls directly — no slash command needed. Claude invokes the right tool automatically based on what you describe.

Install

pip install -r requirements-optional.txt   # adds mcp>=1.0

Activate

The plugin is pre-configured in .claude/.mcp.json. Open the project in Claude Code and restart it. The four tools appear automatically:

tailor-resume: extract_profile
tailor-resume: analyze_gap
tailor-resume: render_latex
tailor-resume: run_pipeline

No slash command required. Just describe what you want in chat — Claude picks the right tool.

The four tools

extract_profile(text, format) Parse any resume text into a structured profile JSON.

  • text: raw resume content
  • format: blob | markdown | latex | linkedin (default: blob)
  • Returns: JSON with experience, projects, skills, education, certifications

analyze_gap(jd_text, resume_text, top_n) Score a resume against a job description.

  • Returns: ATS score (0-100), top gap signals with priorities and closing angles, keyword gaps, recommendations

render_latex(profile_json, output_path, name, email, ...) Render a resume.tex from a profile dict.

  • PII (name, email, phone, linkedin, github, portfolio) injected at runtime
  • Returns: absolute path to the written .tex file

run_pipeline(jd_text, artifact_text, artifact_format, output_path, name, email, ...) Full pipeline in one call: parse → gap analysis → render.

  • Returns: profile dict, gap report, output path

Example: full pipeline in one chat message

Here is my JD: [paste JD]
Here is my work history: [paste blob]
My name is Jane Smith, email jane@example.com, LinkedIn https://linkedin.com/in/jane
Write the resume to out/resume.tex

Claude calls run_pipeline(...) and returns the gap report + confirms the .tex path.

Connect globally (use from any project)

To use the MCP plugin outside this repo, add it to your global Claude Code config:

~/.claude/.mcp.json:

{
  "mcpServers": {
    "tailor-resume": {
      "command": "python",
      "args": ["/absolute/path/to/tailor-resume/.claude/skills/tailor-resume/scripts/mcp_server.py"]
    }
  }
}

Export to PDF

After Claude produces resume.tex:

Local (requires a LaTeX distribution — MiKTeX or TeX Live):

pdflatex resume.tex

Overleaf (no install needed):

  1. Go to overleaf.com and create a new blank project
  2. Upload resume.tex
  3. Set compiler to pdfLaTeX
  4. Click Recompile → download PDF

ATS tip: verify your resume is machine-readable by selecting and copying text from the exported PDF.


Option C: Streamlit web app (browser-based, no Claude Code required)

Open in Streamlit

A browser-based UI — paste your resume and JD, get an ATS score, gap analysis, and a downloadable .tex file. No Claude Code or terminal required.

Run locally:

pip install streamlit
streamlit run streamlit_app/app.py

Deploy to Streamlit Community Cloud (free):

  1. Fork this repo to your GitHub account
  2. Go to share.streamlit.io → New app
  3. Set main file: streamlit_app/app.py
  4. Click Deploy

The 3-tab interface:

Tab What it does
📄 Profile Paste resume/blob → parse into structured profile; save/load via sidebar
🎯 Tailor Paste JD → ATS score + gap table + tailored .tex
⬇️ Download Download resume_tailored.tex → upload to Overleaf for PDF

Option D: Hosted MCP server (zero-install, remote tools)

Register the hosted MCP server in Claude Code and the four tools are available from any project — no local clone, no Python install:

{
  "mcpServers": {
    "tailor-resume": {
      "url": "https://tailor-resume-mcp.fly.dev/mcp"
    }
  }
}

Add this to ~/.claude/settings.json under mcpServers. The same four tools (extract_profile, analyze_gap, render_latex, run_pipeline) work exactly as the local MCP plugin but call the remote server.

Self-host on Fly.io:

fly auth login
fly launch --no-deploy   # reads fly.toml
fly secrets set ANTHROPIC_API_KEY=...  # if needed
fly deploy

Use the scripts directly (no Claude required)

The scripts under .claude/skills/tailor-resume/scripts/ are standalone Python — core pipeline uses stdlib only.

Parse a work history blob into profile JSON:

python .claude/skills/tailor-resume/scripts/profile_extractor.py \
  --input fixtures/sample_blob.txt \
  --format blob \
  --output out/profile.json

Run JD gap analysis:

python .claude/skills/tailor-resume/scripts/jd_gap_analyzer.py \
  --jd fixtures/sample_jd.txt \
  --profile out/profile.json

Render LaTeX resume:

python .claude/skills/tailor-resume/scripts/latex_renderer.py \
  --profile out/profile.json \
  --template .claude/skills/tailor-resume/templates/resume_template.tex \
  --output out/resume.tex \
  --name "Your Name" \
  --email "you@example.com" \
  --linkedin "https://linkedin.com/in/yourhandle" \
  --portfolio "https://yoursite.com"

Full pipeline in one command (cli.py):

mkdir -p out
python .claude/skills/tailor-resume/scripts/cli.py \
  --jd fixtures/sample_jd.txt \
  --artifact fixtures/sample_blob.txt:blob \
  --name "Jane Smith" --email "jane@example.com" \
  --linkedin "https://linkedin.com/in/jane-smith" \
  --output out/resume.tex

Optional: RAG profile persistence

Store your profile as an embedding so future sessions skip re-ingestion.

With Pinecone (cloud, persistent across devices):

cp .env.example .env
# Edit .env and set PINECONE_API_KEY and OPENAI_API_KEY
pip install -r requirements-optional.txt

python .claude/skills/tailor-resume/scripts/rag_store.py \
  store --profile out/profile.json --user-id yourname

Without any API keys (local SQLite fallback — works out of the box):

python .claude/skills/tailor-resume/scripts/rag_store.py \
  store --profile out/profile.json --user-id yourname

Profiles are stored at ~/.tailor_resume/profiles.db. On subsequent runs, Claude can retrieve your profile without re-uploading your resume.


Run tests

# Core test suite (no API keys needed)
python -m pytest tests/ -v

# With coverage report
python -m pytest tests/ --cov=.claude/skills/tailor-resume/scripts --cov-report=term-missing

Repo structure

tailor-resume/
├── .claude/
│   ├── .mcp.json                 — MCP plugin config (auto-loaded by Claude Code)
│   └── skills/tailor-resume/
│       ├── SKILL.md              — skill instructions and 8-step workflow
│       ├── REFERENCE.md          — 2026 resume philosophy, bullet scoring rubric
│       ├── EXAMPLES.md           — invocation examples and blob format templates
│       ├── scripts/
│       │   ├── resume_types.py        — shared dataclasses (Bullet/Role/Profile/GapReport)
│       │   ├── text_utils.py          — shared utilities (extract_metrics, tokenize, ...)
│       │   ├── profile_extractor.py   — parse blobs, LaTeX, markdown, LinkedIn PDF
│       │   ├── jd_gap_analyzer.py     — JD gap analysis, ATS score, signal taxonomy
│       │   ├── latex_renderer.py      — profile dict → LaTeX resume
│       │   ├── rag_store.py           — Pinecone/SQLite profile persistence
│       │   ├── cli.py                 — single-command pipeline orchestrator
│       │   └── mcp_server.py          — MCP plugin server (4 tools for Claude Code)
│       └── templates/
│           └── resume_template.tex    — PII-free single-page LaTeX template
├── fixtures/
│   ├── sample_jd.txt              — sample Senior Data Engineer JD
│   ├── sample_blob.txt            — sample work experience blob
│   └── sample_profile.json        — pre-parsed profile for fast tests
├── tests/
│   ├── conftest.py                — shared fixtures and sys.path setup
│   ├── test_tracer_e2e.py         — end-to-end pipeline tests
│   ├── test_profile_extractor.py  — parser unit tests
│   ├── test_jd_gap_analyzer.py    — gap analysis unit tests
│   ├── test_latex_renderer.py     — renderer unit tests
│   ├── test_rag_store.py          — SQLite backend tests
│   └── test_cli.py                — CLI entry point tests
├── streamlit_app/
│   ├── app.py                     — Streamlit entrypoint (3-tab layout + sidebar)
│   └── tabs/
│       ├── profile_tab.py         — parse resume text into structured profile
│       ├── tailor_tab.py          — JD gap analysis + ATS score + LaTeX render
│       └── download_tab.py        — download tailored .tex
├── server.py                      — FastMCP HTTP/SSE entrypoint (Fly.io deploy)
├── Dockerfile                     — python:3.12-slim for Fly.io
├── fly.toml                       — Fly.io config (tailor-resume-mcp, ord region)
├── .github/workflows/
│   ├── ci.yml                     — lint + test on push
│   └── deploy-mcp.yml             — auto-deploy to Fly.io on main
├── Makefile                       — setup/demo/test/lint/render/clean targets
├── requirements.txt               — streamlit, pytest, ruff (core scripts use stdlib only)
├── requirements-optional.txt      — pinecone-client, openai, mcp
└── .env.example                   — documented env vars with safe defaults

Design principles

  • No PII hardcoded — all personal data passed at runtime, never committed
  • No fabrication — Claude only reframes evidence you provide; never invents metrics
  • Zero-config default — core pipeline runs on stdlib only; cloud features are opt-in
  • Single page — forces prioritization; the constraint is the feature
  • Factual integrity — if a metric is missing, Claude asks for it rather than guessing

Contributing

# Lint
python -m ruff check .claude/skills/tailor-resume/scripts/ tests/

# Test
python -m pytest tests/ -v

# Submit a PR to main

See open issues for the current backlog. Issue #1 is the parent PRD — read it before picking up any issue.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tailor_resume-0.1.0.tar.gz (103.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tailor_resume-0.1.0-py3-none-any.whl (52.6 kB view details)

Uploaded Python 3

File details

Details for the file tailor_resume-0.1.0.tar.gz.

File metadata

  • Download URL: tailor_resume-0.1.0.tar.gz
  • Upload date:
  • Size: 103.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tailor_resume-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ada8dd29bfed50a5c49b0411a454df372c12c5a6fb5f10cd113615e39fd080db
MD5 30caaf00f5f75c0191ff8e0819b0c892
BLAKE2b-256 adb5634b833efc3a86a146489cfc376d7daeaf1c5aeab64b4f43b75cb40b8505

See more details on using hashes here.

Provenance

The following attestation bundles were made for tailor_resume-0.1.0.tar.gz:

Publisher: publish-pypi.yml on narendranathe/tailor-resume

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tailor_resume-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: tailor_resume-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 52.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tailor_resume-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b30cf442c41ae1d5d9ffe87dda3558c866943f443e2657b82d0cb70ed066604c
MD5 6724d6262a0f93a02f3cd544683d55a8
BLAKE2b-256 4224675eedfb33ed8ba5803bbe7d17d3b4b69808403ea61fa679963f6b16aaec

See more details on using hashes here.

Provenance

The following attestation bundles were made for tailor_resume-0.1.0-py3-none-any.whl:

Publisher: publish-pypi.yml on narendranathe/tailor-resume

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page