Model or dataset
srbhr/Resume-Matcher avatar
srbhr/Resume-Matcher

Resume Matcher: a self-hosted resume tailor with a code-only ATS score and a localhost-only default

The #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.

29,277 stars5,134 forksPythonApache-2.0

At a glance

What is it?
Resume Matcher is an Apache-2.0 app that tailors a master resume to each job description using a model you choose, and stores everything in your own database. It suits engineers comfortable with a terminal; its ATS check and its no-invention rule both have edges worth knowing first.
Who is it for?
Resume Matcher fits job seekers who can run a terminal or a Docker container, want their resume kept in their own database, and are happy to pick their own model, local through Ollama or remote through an API key. It does not fit someone who wants a hosted website with no setup, or who expects the tool to fill gaps in experience.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • srbhr/Resume-Matcher29,277 ★ · +892
Star history
Repository2026-09-112026-11-13
srbhr/Resume-Matcher28.4k29.3k

892 Stars in the last 63 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

One master resume feeds every application

Resume Matcher is built around a single master resume that gets tailored per job. The flow has six steps: upload the master resume as PDF or DOCX, paste the job description you are targeting, review the AI-generated improvements and tailored content, generate a cover letter and optional interview preparation, customize layout and sections, and export a PDF with the template you prefer.

The templates lean toward engineering resumes. Deedy, Modern Deedy, and a LaTeX-style layout sit next to single-column and two-column options. Seven of the designs are also published as editable pdfLaTeX projects for Overleaf in the separate resume-matcher-templates repository, which helps if you want to keep editing outside the app.

The project ships often. v1.4.0, named Short Circuit, came out on October 21, 2026, after v1.3.0 in September 2026 and 1.2.0 in April 2026, and the last push to main was on November 2, 2026. It is licensed Apache-2.0 and funded through sponsors and individual donations.

FastAPI, Next.js and a SQLite file on your own machine

Nothing runs on someone else's server unless you send it there. The app is a FastAPI backend, a Next.js frontend, and a SQLite file. You either clone the repository or start one Docker container, you do not create an account, and the resume stays in your own database. The repository keeps both halves under apps/, with the ATS code at apps/backend/app/services/.

The Docker route uses the image ghcr.io/srbhr/resume-matcher, published as a single container named resume-matcher that listens on port 3000. Its data lives in a named volume:

code
    volumes:
      - resume-data:/app/backend/data

That volume is the whole state of the app, so back it up before upgrading the image. A second compose file, docker-compose.postgres.yml, sits at the repository root as an alternative to the default one; compare the two before switching, so you know which database your volume holds.

Installing takes a terminal, and the project says as much: most people running it write software. Installation steps are on resumematcher.fyi/docs/installation and in SETUP.md, which is also translated into Spanish, Japanese, Portuguese, and Simplified Chinese.

The compose port binds to 127.0.0.1 until you change two variables

The default compose file makes the app reachable from the machine running it and nowhere else. The port mapping reads:

code
      - "${BIND_ADDRESS:-127.0.0.1}:${PORT:-3000}:3000"

If you start the container on a home server and try to open it from a laptop or phone, it will not answer. Two settings change that, and you need both. BIND_ADDRESS=0.0.0.0 opens the port on all interfaces, and ALLOWED_HOSTS has to list the address you will type, for example 192.168.1.20 for LAN access. ALLOWED_HOSTS is a comma-separated list of extra hostnames the app answers for besides localhost and the FRONTEND_BASE_URL host, and "*" allows any host.

FRONTEND_BASE_URL defaults to http://localhost:3000 and is the setting to change when the app sits behind a reverse proxy on a real domain. Setting ALLOWED_HOSTS to "*" on a machine exposed to the internet means anyone who finds the port can reach a database holding your work history, since there is no account system in front of it.

Your model choice decides whether the resume leaves the machine

Resume Matcher does not ship a model. You bring an API key for OpenAI, Anthropic, Gemini, DeepSeek, OpenRouter, or Groq, or you run a local model with Ollama. Only the Ollama route keeps the resume on your machine; with a hosted provider, the text you tailor is sent to that provider. Provider settings can be entered in the Settings UI, with environment variables available for explicit overrides.

Running Ollama on the host while the app runs in Docker needs the container to reach the host. The compose file handles it:

code
    extra_hosts:
      - "host.docker.internal:host-gateway"

That line makes host.docker.internal resolve on Linux; Docker Desktop on macOS and Windows already provides the name. Model calls go through LiteLLM, and its log level is set separately from the app's. LOG_LEVEL defaults to INFO and LOG_LLM defaults to WARNING, both accepting DEBUG, INFO, WARNING, or ERROR. Raise LOG_LLM to DEBUG when a provider call fails and the app log alone does not show why.

The ATS score is plain code and the check is pdfminer

The scoring side makes no LLM call. The ATS score comes from services/ats.py, and the ATS check lives in services/ats_parse/. The check runs your exported PDF through pdfminer to show what an applicant tracking system would extract, which is useful for catching a template whose columns or headings come out scrambled as text.

There are two consequences. The score is deterministic code, so the same resume and job description give the same number, and you can read the source to see what moves it. But the check is one extractor standing in for every tracking system an employer might run. A clean pdfminer result tells you the text layer of your PDF is readable; it does not tell you how a specific company's software ranks you. Treat the number as feedback on your own document, and look at the extracted text itself, especially after switching between single-column and two-column templates.

The tailoring prompts will not add experience you do not have

The tailoring prompts forbid adding skills, tools, employers, or metrics that are not in your master resume. That is a deliberate limit, and it shapes what the tool can do for you. If a job description asks for a framework you have never listed, Resume Matcher will not write it in. It can reorder, rephrase, and emphasize what is already there.

The practical effect is that the master resume carries all the weight. Anything you left out of it, a side project, a tool you used once, a measurable result, is invisible to every tailored version. Before running a batch of applications, spend the time on a complete master resume with real numbers you can defend in an interview, because the app will not supply them. Those who want a generator that fills gaps will find this frustrating; anyone worried about an AI inventing claims on their behalf gets a guardrail written into the prompts.

MCP mode lets Claude Code, Cursor or Codex write without an LLM key

There is a second way to use the app that skips configuring a provider entirely. Resume Matcher includes an MCP server, documented in SETUP.md under using it from Claude Code or Claude Desktop. In this mode Claude Code, Cursor, or Codex writes the tailored resume, while Resume Matcher stores it, checks it, and renders it. No LLM key is needed inside Resume Matcher for that path, because the writing happens in the coding agent you already run.

This split matters for who pays and where text goes. The model usage belongs to your agent's account, and Resume Matcher stays a local store, ATS checker, and PDF renderer. If you already work in one of those agents every day, this is the shortest route; if you do not, the Settings UI with an API key or Ollama is the path to take.

Building the image behind a slow or restricted network

The published image saves you a build, but compose can also build from the repository with four optional build arguments: DEBIAN_MIRROR, DEBIAN_SECURITY_MIRROR, PIP_INDEX_URL, and PLAYWRIGHT_DOWNLOAD_HOST. Each is empty by default, which means no change to the upstream sources. The compose file gives an example for slow networks:

code
DEBIAN_MIRROR=https://mirrors.edge.kernel.org/debian docker compose build

The Playwright download host is the one people overlook. Its presence in the list means the build fetches from a Playwright host as well, so pointing only Debian and pip at mirrors may not be enough on a restricted network. Set all four together if you are behind a corporate proxy or in a region with poor access to the default sources, and rebuild after changing them, since build arguments only take effect at build time.

Editorial conclusion

Resume Matcher fits job seekers who can run a terminal or a Docker container, want their resume kept in their own database, and are happy to pick their own model, local through Ollama or remote through an API key. It does not fit someone who wants a hosted website with no setup, or who expects the tool to fill gaps in experience. Before relying on it, check what the ATS check extracts from your exported PDF, and decide whether your resume may go to a remote provider or must stay on a local model.

Frequently asked questions

How do I install Resume Matcher?

Clone the repository or start one Docker container using the ghcr.io/srbhr/resume-matcher image from the project's docker-compose.yml. Step-by-step instructions are at resumematcher.fyi/docs/installation and in SETUP.md.

How do I use Resume Matcher?

Upload a master resume as PDF or DOCX, paste a job description, review the tailored content, optionally generate a cover letter and interview prep, adjust layout, and export a PDF.

Is 80% a good ATS score in Resume Matcher?

Resume Matcher computes its ATS score in plain code in services/ats.py with no LLM call. Pair the number with the ATS check, which shows the text pdfminer extracts from your PDF, rather than chasing a single percentage.

How does Resume Matcher help with resume scanners?

Its ATS check runs your PDF through pdfminer to show what an applicant tracking system would extract, so you can spot a layout that scrambles your text. Its tailoring will not add skills or employers missing from your master resume.

Is Resume Matcher a resume screening tool?

No. Resume Matcher is a resume builder for candidates that tailors a master resume to each job description; it is not built for employers screening applicants.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. srbhr/Resume-Matcher on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/srbhr-resume-matcher.svg)](https://hysenlabs.com/projects/srbhr-resume-matcher)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/srbhr-resume-matcher.svg)](https://hysenlabs.com/projects/srbhr-resume-matcher)

Was this useful?