Build CVMatchScore
KINDAreplaces $4.08/mosaves $48.96/yrback to the verdict
A comparison tool that maps a job description's stated requirements against evidence in a CV, quoting both sides, and refuses to produce an overall score because there is nothing real for a score to measure.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the local application.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree
Why Designed CV templates are two-column and a naive extractor produces interleaved text that every later step then operates on.
Get it A library exposing text with positions and block structure.
Verify
A two-column CV extracts in correct reading order - installfree, needs memory
Why A CV and the jobs someone is applying for are private in ways people underestimate, and this runs over both.
Get it Any local runner with a model that returns structured output reliably. open ↗
Verify
Ten extractions return valid structured output with positions - have readyfree
Why Requirement extraction quality is only assessable against real postings, which vary from precise lists to three paragraphs of aspiration.
Get it Collect postings you would actually apply for, including a vague one and one heavy with boilerplate.
Verify
Ten postings exist including one vague and one boilerplate-heavy - decidefree
Why The whole build refuses to predict, and the wording of that refusal is the most important text in the interface.
Get it Write the sentence the report leads with about what the comparison does and does not tell them.
Verify
A written sentence exists and appears where the reader will see it
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- documents(id, kind, text, filename, added_at) · kind is cv or posting - requirements(id, posting_id, quote, char_start, char_end, category, is_essential) · essential where the posting says so, never inferred - evidence(requirement_id, cv_id, quote, char_start, char_end, strength, note) - gaps(requirement_id, cv_id, kind, note) · kind is absent, weak or unclear - rewrites(id, cv_id, requirement_id, suggestion, accepted_at) · suggestions, never applied automatically - sessions(id, cv_id, posting_id, compared_at) - There is deliberately no score column anywhere, because a stored number would be displayed and it would be invented.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DB_PATH | required | ~/.local/share/cvmatch/data.db | Your CV and the jobs you are applying for. Personal in both directions. |
EXTRACTION_MODEL | required | local | Runs over your CV and your job search. Local is the sensible default. |
EMIT_SCORE | required | never | Present as a constant so the answer is visible. There is nothing real to score. |
GENERATE_CV_TEXT | required | never | Present as a constant. A pasted claim becomes a lie at interview. |
ALLOW_NETWORK | required | never | Present as a constant. Neither document needs to leave the machine. |
The build, in order
Reading both documents properly
A CV and a posting parse into text with positions preserved.
Designed CV templates are two-column and scramble under naive extraction.
Files
src/extract.tsEvery claim later has to quote, which needs positions.
Files
src/documents.tsPartial text produces a comparison that is confidently wrong.
Files
src/extract.ts
done when · tick each as it passeswatch out- A CV in two columns, which is common in designed templates, extracts as interleaved nonsense with a naive reader, and every comparison after that operates on scrambled text while looking entirely plausible. Reconstruct reading order and check the output is readable before doing anything with it.
Requirements as sentences, not keywords
The posting yields discrete requirements you could argue with.
A keyword loses what was actually being asked for.
Files
src/requirements.tsInferring which are essential is guessing at someone else's priorities.
Files
src/requirements.tsCulture paragraphs are not requirements and dilute the comparison.
Files
src/requirements.ts
done when · tick each as it passeswatch out- Reducing a posting to a keyword list turns a requirement like experience leading a small team through a migration into the word migration, and then matching becomes a word game rather than a comparison. Keep requirements as quoted sentences so the user can see what is actually being asked for.
Evidence, or its absence, stated plainly
Each requirement is matched to CV text or reported as unevidenced.
So the judgement belongs to the person rather than the tool.
Files
src/match.tsThey call for completely different responses.
Files
src/gaps.tsA percentage hides exactly the distinction that matters.
Files
tests/no-scores.test.ts
done when · tick each as it passeswatch out- Reporting a partial match as a percentage hides whether the CV said something adjacent or nothing at all, and those need completely different responses from the person. Say absent, weak or evidenced, and quote the text in every case so the judgement is theirs.
Suggestions that do not write your CV
You are told what is missing, not given sentences to paste in.
What did you actually do, rather than here is what they wanted.
Files
src/suggest.tsIts absence is the design. A pasted claim is a lie at interview.
Files
tests/no-generation.test.tsSome requirements genuinely do not apply to you.
Files
src/suggest.ts
done when · tick each as it passeswatch out- Generating a bullet point for a gap invites someone to paste in a claim about experience they do not have, which is a lie on a CV with their name on it and is discovered at interview. Ask what they actually did rather than supplying what the posting wanted to hear.
Saying what the tool cannot tell youproduct builder
The output is honest about the limits of what a comparison shows.
Not a footer. The reader is anxious and looking for a verdict.
Files
src/report.tsA CV and a job hunt are private in ways people underestimate.
Files
tests/offline.test.tsYour own patterns are real. A predicted outcome is not.
Files
src/applications.ts
done when · tick each as it passeswatch out- A report that ends with an implied verdict, even without a number, reads as a prediction, and the honest position is that the tool has no idea whether you will hear back because the dominant factor is how many other people applied. State that where the reader will see it rather than in a footer.
That is the whole plan for CVMatchScore. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Any overall score or match percentage.
- Predicting whether you will be contacted.
- Generating CV content.
- Optimising for a specific applicant tracking system.
- a calibrated rubric that scores the same resume the same way twice
- 50+ language support tested per parameter
- DOC, DOCX, and RTF parsing beyond PDF
- improvement plans and tailored cover letters built from the same analysis
- scores comparable across weeks of applications
- Comparing one CV against several postings to see which requirements recur
- Tracking which of your own claims get asked about at interview, which is real feedback
- A version history of your CV, since most people keep six files and lose track
Need the files? The project pack on the verdict page hands your agent the whole brief · more career.