cvlinter_

How the parse score is calculated

The parse score measures one thing: how well your CV survives being read by an applicant tracking system. It is not a judgment of your experience, your writing, or your fit for any role. A brilliant CV in a layout that parsers mangle scores low, and that's the point.

method version: parse-score/v2

The mechanics

We run your CV through the same commercial parsing engine that powers real ATSs, then inspect the result for likely mis-parses. Each finding becomes a visible signal in the preview, and each signal does a measured amount of damage to the section it belongs to. The score is nothing but a roll-up of the signals you can already see; there are no hidden factors. Three rules determine how much damage a signal does.

1 · Base damage by severity

severitybase damagemeaning
error55%the parser got this factually wrong (a misread skill, a swapped field)
warning22%worth double-checking (missing dates, a low-confidence read)
info5%a quiet note (minor normalization oddities)

Base damage is the share of a section's score a signal removes if it affects the whole section. These values are chosen judgment calls, not yet derived from data. We say so here, and we're calibrating them against a corpus of real engineering CVs.

2 · Coverage scaling

A problem on one item out of many hurts less than a problem across the whole section: one undated role out of five does one-fifth of the base damage, so fixing four of five undated roles visibly moves your score. The divisor is capped at 10 because keyword-search damage is absolute (a recruiter searching the one skill that was misread gets zero hits), so a long skills list can't dilute a real misread to nothing.

Signals that carry the parser's own confidence scale with it: a read the parser was only 40% sure of does about 1.35× the damage of one just under the 75% flag threshold.

3 · Diminishing returns

Damage compounds multiplicatively: each signal removes its share of what remains, so a section's score is 100 × ∏(1 − damage). Two whole-section errors leave ~20, three leave ~9. A section degrades toward a floor instead of slamming into zero, so the score keeps discriminating between bad and worse, and improvements always register.

Empty sections

If the parser extracts nothing for a core section, we check the raw extracted text for that section's heading. If the heading is there but the content didn't parse, that's the most serious failure we can detect and the section loses 95% of its score. If the CV genuinely doesn't have the section, like a new grad with no work history, it's excluded from the roll-up entirely and noted as an advisory instead. Projects are always optional.

Section weights

experience40
skills25
contact20
education15
projects10

The overall score is the weighted average of section scores, with weights rescaled over the sections your CV actually has. Experience weighs most because it's what recruiters search; contact matters because a mis-parsed email means no reply at all.

Grades (provisional)

A90–100
B75–89
C60–74
D40–59
F0–39

These bands are provisional round numbers. Once enough real CVs have been scored, we'll set them where they mean something ("B = parses cleanly enough that a recruiter sees the real CV") and bump the method version. We'd rather admit that than present arbitrary thresholds as science.

What the signals detect

Content lint: findings, never a grade

Alongside the parse signals, Cvlinter lints the CV's substance, and deliberately does not score it. Parseability is measurable, so it gets a number; writing quality is a judgment, and a standalone "content: 62/100" is exactly the fictional ATS number this tool exists to counter. Content lint therefore aggregates the way a code linter does: a tally of specific, itemized findings ("3 things to fix, 5 to consider"), each traceable to a specific bullet. to fix means a recruiter-visible weakness; to consider is a convention worth knowing about.

Three further rules are judgment calls no regex can make, so when enabled a small language model classifies each bullet against them: responsibility-phrasing (describes a duty, not an outcome, beyond just a weak opener), vague-claim (an achievement asserted with no number, scale, or specifics), and tense-inconsistent. The model classifies only: its output schema has no field for suggested text, so it structurally cannot rewrite anything you wrote. One batched call per CV, cached, and if it fails you simply get the deterministic findings alone.

Content findings never affect the parse score. That's enforced in code, not by policy. The wordlists behind these rules are early and under review by a working tech recruiter. The one place a content-adjacent number is honest is relative to a specific job description. That's the JD match, below.

JD match: the one honest number

Paste a job posting and we extract its concrete requirements (at most 12: technologies, experience, responsibilities; boilerplate ignored) and classify each one against your CV:

The headline, "you evidence 6 of 10 requirements", counts only evidenced. It's defensible precisely because it's anchored to one concrete posting; it is not a general quality score, and the same CV will legitimately score differently against different roles. A missing requirement is not an instruction to add keywords: the classifier's output schema has no field for suggested wording, so keyword advice structurally cannot come out of it. (Method version: jd-match/v2, same small language model as the lint rules, deterministic settings, cached.)

The fix flow: your words, tightened

Findings can be fixed without us writing your CV for you. For a flagged bullet we ask what you actually did; a language model then tightens your bullet using only the material in it and your answers. The guardrails are structural: the output schema is a single revised sentence, and a code-side fact guard rejects any suggestion containing a number that doesn't appear in your own words, before you ever see it. Nothing is applied without your explicit approval, and nothing you type is stored. (Method version: fix-flow/v2.)

The ATS-safe export: one template, forever

The export renders your parsed content, plus the fixes you approved and nothing else, into a single deliberately classical layout: one column, embedded real text, plain uppercase headings. This is not a resume builder: there is exactly one template and no design options, because its only job is to parse cleanly. Your skills section is reproduced from your CV's own text, never from the parser's normalized skill list (which can invent terms you never wrote). The PDF is generated in memory and streamed to you; we keep nothing.

What we deliberately don't do

Versioning

The score you see carries its method version (currently parse-score/v2). When weights or rules change, the version changes and this page is updated in the same release. A score is only meaningful if you can see the method that produced it.