- Language
- Python
- Last commit
- 1h ago
- Forks
- 0
- Open issues
- 1
- Registry update
- Oct 15, 2026
Connect
pypi$claude mcp add honest-cv \ -e HONEST_CV_PROFILE=<honest-cv-profile> \ -- uvx honest-cv==0.2.0
Environment variables
HONEST_CV_PROFILEFolder that holds your profile, e.g. ~/cv-profile. Keep it out of public repositories. Tools also accept a profile argument.
Security review
Review passedReviewed 15m ago.
- metadata
- scanned
- packages
- 1 checked
No findings.
Tools
This server runs on your machine, so its tool list is not fetched before install — the README below describes what it offers.
honest-cv
Honest, ATS-safe CVs tailored to each role, generated by your AI agent. honest-cv is an MCP server, a CLI and a Claude Code skill. It keeps one source of truth about your experience and turns it into a PDF and DOCX for each type of role. It never claims a skill you don't have.

Why
Many CVs that get no callbacks don't fail on design. They fail on targeting, and on details that quietly break text extraction. AI makes the opposite problem easy: a model will happily stuff a CV with keywords you can't defend in an interview. honest-cv is built around three ideas:
- The code enforces honesty, not a prompt. Every skill has a level. A skill at familiarity level is always labeled as such, and a skill you don't have is never printed. Raising a level takes written evidence and your confirmation, which the server asks you for directly. The model can't confirm on your behalf.
- Gaps are measured against your own inventory. For each keyword a job post asks for,
honest-cv tells you which of three cases it is:
- you have it, but this CV doesn't show it;
- you only know it at familiarity level;
- you don't have it.
- ATS safety is checked on every build. Every PDF goes through two text extractors (pypdf and pdfminer.six). The build checks that the text is one column, has no ligatures, keeps each date on its role's line, follows the right reading order and includes every bullet.
The server is deterministic and needs no API key. Your MCP client's model runs the conversation; honest-cv validates, builds, verifies and measures. It keeps your profile in a folder on your machine and never sends it anywhere: see Privacy for what your AI client does with it.

Quick start
honest-cv needs uv. Typst and the fonts ship inside the package,
so there is nothing else to install.
It runs on Linux (glibc) on x86_64 and ARM64, macOS on Intel and Apple
Silicon, and Windows on x64. Alpine Linux and Windows on ARM aren't supported, because the typst
package doesn't publish wheels for them.
Claude Code
claude mcp add honest-cv -- uvx honest-cv serve --profile ~/cv-profile
To install the skill as well, which guides the interview and the tailoring:
mkdir -p ~/.claude/skills/honest-cv
curl -fsSL https://raw.githubusercontent.com/JesusCabreraReveles/honest-cv/master/skills/honest-cv/SKILL.md \
-o ~/.claude/skills/honest-cv/SKILL.md
Then start with "interview me for my CV", or run /mcp__honest-cv__interview. You can answer
by voice with your system's dictation (on macOS: System Settings → Keyboard → Dictation): the
interview reads names and numbers back to you before saving them, since dictation mishears them.
The first interview is long. With a long career and many skills it can take several hours. You don't have to do it in one sitting: everything is saved as you go, so stop whenever you like and say "let's continue my CV interview" later. A good first session covers your contact details, your two most recent roles and the skills checklist; with that you can already build a CV, and older roles can wait.
Cursor
Add this to ~/.cursor/mcp.json, or to .cursor/mcp.json in a project:
{
"mcpServers": {
"honest-cv": {
"command": "uvx",
"args": ["honest-cv", "serve", "--profile", "/absolute/path/to/cv-profile"]
}
}
}
Claude Desktop
Edit claude_desktop_config.json:
- on macOS,
~/Library/Application Support/Claude/; - on Windows,
%APPDATA%\Claude\.
Add the same mcpServers block as in the Cursor example and restart the app. If the app can't
find uvx, use its absolute path (which uvx).
How each client confirms a skill upgrade
Raising a skill's level needs your own confirmation, which the server asks for through MCP elicitation. Not every client supports it yet:
| Client | Where you confirm |
|---|---|
| Claude Code | In the chat: a form with one "no / sí" field per upgrade, up to 10 at a time. Only the ones you answer "sí" are saved; Decline saves nothing. |
| Claude Desktop | In a terminal. The server refuses the change and gives you the command to run: uvx honest-cv skill <profile> "<name>" <level> --evidence "...". |
| Other clients | In the chat if they support elicitation, otherwise in a terminal as above. |
Your profile
A profile is a folder with four YAML files. Create one with honest-cv init ~/cv-profile, or let
the interview prompt fill it in with you. Keep it out of public repositories.
| File | What it holds |
|---|---|
profile.yaml | Contact details, roles, education, certifications, publications, courses and languages. |
bullets.yaml | A pool of achievements, each with an id, a role and tags. |
skills.yaml | Your skill inventory, with levels and evidence. |
variants.yaml | One CV plan per type of role. A variant can inherit from another with extends:. |
Any text can be a single string or one string per language: {en: ..., es: ...}. CVs can be
built in English and in Spanish.
| Level | Meaning | On the CV |
|---|---|---|
P | Used in production at a job | Shown |
L | Your own project or lab | Shown |
F | Familiarity | Only on the line labeled "Familiarity" |
X | You don't have it | Never shown, but recorded so gap reports are honest |
Skill checklists
Recording dozens of skills one question at a time is slow. A checklist is a Markdown file you mark in your editor, one letter per line:
## Messaging and streaming
evidence: Payments platform at Acme, 2020–2026
- [P] Kafka — reconciliation flow, 2M events a day · years: 6 · last year: 2026
- [F] RabbitMQ — a workshop and the official tutorials
- [X] NATS
Text after " — " is the evidence, and an evidence: line under a heading covers that section.
Lines without evidence are never saved: they come back as pending, and your assistant asks you
about them in groups. Upgrades are confirmed once for the whole file.
honest-cv checklist list # backend-jvm, platform-sre, ...
honest-cv checklist new ~/cv-profile backend-jvm engineering-lead
honest-cv checklist apply ~/cv-profile ~/cv-profile/checklist.md
Any profession works. The built-in checklists are for software roles, but a template is just a
Markdown list in this format: save your own (or one someone shared) in ~/cv-profile/checklists/
and it shows up in checklist list and combines with the others in checklist new, which also
takes a path. A template can declare synonyms, such as same: Work Breakdown Structure = WBS,
and the job score, the gaps and the letter check use them, along with its skill names. Start from
examples/checklists/project-management.md. You can also apply a file you marked yourself, in English or Spanish (años,
último uso). When you're done, honest-cv names the P and L skills that no achievement shows, and
your assistant asks you for one real example of each.
honest-cv checklist list ~/cv-profile # yours too, e.g. accounting
honest-cv checklist new ~/cv-profile accounting engineering-lead
New checklists for other kinds of roles are welcome: see CONTRIBUTING.md.
See examples/ada/ for a complete, fictional profile with three variants, a job
post and its keywords.
Privacy
- honest-cv itself makes no network calls. No accounts, no telemetry, no API keys. Your profile is a folder of YAML files on your machine, and the PDF engine and fonts run locally. You can check it: every command works with the network turned off.
- Your AI client is a different matter. Whatever the client's model reads through the tools goes to that model's provider, under the provider's terms, like anything else you share in a chat. That includes your skills, bullets and the text of your CVs.
- Some clients copy files to the cloud. To edit files directly, Claude Desktop may ask for access to the profile folder and say that the files leave your device. honest-cv's editing tools make that unnecessary: decline the request and ask the assistant to use the tools.
- If you want nothing to leave your machine, use only the CLI (
build,verify,score,skill) and edit the YAML files yourself.
Import what you already have
honest-cv import reads a JSON Resume file or LinkedIn's data export
(Settings → Data privacy → Download your data, a ZIP of CSVs, or its folder if your browser
unzipped it). Ask for the full archive: the basic one, offered when you pick files, has only your
headline and summary, without roles. Contact, roles, education,
certifications, languages and each role's achievements go into your profile; with a headline and
a summary it also creates a first variant, so build works right away.
- It only adds what your profile lacks and never overwrites. Try
--dry-runfirst. - Imported achievements are tagged
imported: review their wording. - Skills arrive without a level, because neither format says whether you used a skill in
production. They go to
imported-skills.md, a checklist for you to mark.
LinkedIn's "Save to PDF" profile changes layout without notice, so it isn't parsed: with an MCP
client, the import_linkedin_pdf prompt reads its text and proposes each section for you to
approve.
Track your applications
honest-cv apps keeps a log in applications.yaml, inside your profile folder: which variant and
files went to which company, and each status with its date (draft, applied, interview,
offer, rejected, withdrawn). Logging the same company and role again updates it. With an MCP
client, your assistant offers to log an application after building the CV or letter, and
list_applications points out the ones with no news for two weeks. It also keeps the job post's
text in posts/, since links expire, and what to prepare for the interview: ask your assistant
"what did I need to prepare for Acme?".
honest-cv linkedin turns a variant into LinkedIn's texts, each within its limit: the headline
(your title and up to five production skills), About (the summary and impact bullets), one
description per position from its bullets, and the skills list. It writes them to a Markdown file
to copy from. The skills are P and L only: LinkedIn can't label familiarity, so F skills stay out,
and X skills never appear. With an MCP client, the linkedin_profile prompt polishes the wording
and checks it with check_claims.
Export
To go the other way, honest-cv export writes a variant as JSON Resume for other CV tools and
sites, with the same rules as the CV: X skills never appear, and F skills only in a "Familiarity"
group with that level.
Cover letters
The cover_letter prompt drafts a one-page letter for a job post from your own bullets. Before it
is built, check_claims reads the text against your profile:
- Problems block the build: a skill you marked X, or a familiarity skill presented as experience ("I use Rust in production" when Rust is F; "I am familiar with Rust" is fine).
- Warnings are for you to review: a technology neither your inventory nor your bullets show, or a number that appears nowhere in your profile. If it is true, record it first; if not, it comes out of the letter.
The letter uses the CV's fonts and passes the same ATS checks. Without an AI client, write it in a
text file (paragraphs separated by blank lines) and use honest-cv letter check and letter build.
CLI
Run any command with uvx honest-cv ..., or install it once with uv tool install honest-cv to
type just honest-cv.
honest-cv init ~/cv-profile # create the profile templates
honest-cv build ~/cv-profile -v backend -l en -l es # PDF + DOCX, verified on every build
honest-cv verify any-cv.pdf --text # check any PDF, even one made elsewhere
honest-cv score ~/cv-profile -k "Kubernetes,Go" -p "Rust" # coverage per variant, with gaps
honest-cv skill ~/cv-profile "Rust" L --evidence "CLI tool on GitHub" # asks you to confirm
honest-cv import ~/cv-profile linkedin-export.zip --dry-run # or resume.json
honest-cv export ~/cv-profile -v backend -l en # JSON Resume
honest-cv apps log ~/cv-profile --company Acme --role "SRE" -s applied -v platform
honest-cv apps list ~/cv-profile # latest first, with counts
honest-cv linkedin ~/cv-profile -v platform -l en # texts to paste into LinkedIn
honest-cv remove skill ~/cv-profile "Kafka" # asks you to confirm
honest-cv letter check ~/cv-profile letter.txt -k "Kubernetes,Go" # claims your profile doesn't support
honest-cv letter build ~/cv-profile letter.txt --company Acme --role "Platform Engineer" -l en
honest-cv serve --profile ~/cv-profile # the MCP server, over stdio
verify works on any PDF. Use --text to see exactly what a parser extracts. Its
single_column check also catches a common defect: a date aligned to the right, which parsers
split away from its role.
MCP tools and prompts
| Name | What it does |
|---|---|
init_profile | Creates a profile folder with commented templates. |
get_inventory | Returns your skills, grouped by level, with years and evidence. |
set_skill | Adds or changes a skill. To raise its level it needs evidence and asks you to confirm. |
set_skills | Adds or changes several skills at once. Upgrades are confirmed with one question that lists each change. |
checklist_list | Lists the built-in checklists. |
checklist_new | Merges built-in checklists into one file, prefilled from your inventory. |
checklist_apply | Saves the skills marked in a checklist and returns the lines that still need evidence. |
add_bullet | Adds an achievement to the pool. |
remove_skill, remove_bullet, remove_role, remove_publication | Delete for good, and remove every use in the variants. A role with bullets needs with_bullets. Clients ask before running them. |
set_contact | Changes contact details: name, email, phone, location, links. |
set_profile_details | Replaces the certifications list, the courses list and the spoken-languages line. |
upsert_role | Adds a role in date order, or changes fields of an existing one. |
upsert_education | Adds or changes an education entry. |
upsert_publication | Adds or changes a book, article or paper the person wrote. Each variant shows all of them, or the ones it lists. |
save_variant | Adds or replaces a variant. Every reference is checked before saving. |
list_variants | Lists the variants after inheritance, with their bullet texts and the bullets no variant uses. |
build_cv | Renders a PDF and/or DOCX and verifies it. |
verify_pdf | Runs the ATS checks on any PDF and returns its extracted text. |
score_job | Measures the keyword coverage of each variant. The client extracts the keywords. |
gap_report | Groups missing keywords by what you can honestly do about each one. |
prompt interview | Fills your inventory and bullet pool, one question at a time. |
check_claims | Checks any text against your profile: blocks X skills and familiarity sold as experience, flags what the profile doesn't show. |
build_letter | Renders a cover letter to PDF and DOCX, one page, with the CV's ATS checks. Refuses while check_claims finds problems. |
prompt tailor_for_job | Scores the variants, explains the gaps, adapts a variant and rebuilds. |
prompt cover_letter | Drafts a letter for a job post from your bullets, checks its claims and builds it. |
import_profile | Imports JSON Resume or a LinkedIn data export, adding only what is missing. For a LinkedIn PDF it returns the text. |
export_json_resume | Exports a variant as JSON Resume; X skills never appear and F skills keep their label. |
log_application | Records an application (company, role, CV variant, files sent, the post's text, what to prepare) or a new status, with its date. |
linkedin_profile | LinkedIn headline, About, position descriptions and skills (P and L only) from a variant, within LinkedIn's limits. |
list_applications | Lists applications, latest first, with a count per status and the ones with no news for 14+ days. |
prompt import_linkedin_pdf | Turns the PDF from LinkedIn's "Save to PDF" into a profile, section by section, with your approval. |
prompt linkedin_profile | Polishes the LinkedIn texts of a variant without adding claims, checked with check_claims. |
ATS guarantees
The template enforces these. verify checks them on every build, and the test suite runs in CI on
Linux, macOS and Windows:
- One column. No layout tables, images, icons, headers or footers.
- Ligatures and kerning off, no hyphenation, and terms like "CI/CD", URLs and emails never split across lines.
- Reading order equals source order. Dates sit on the same line as their role.
- Text is extractable by both pypdf and pdfminer.six, and the two agree.
- The fonts (Carlito, metric-compatible with Calibri) are embedded and identical on every machine.
Development
uv sync
uv run pytest
uv run honest-cv build examples/ada -l en -l es
The repository's .mcp.json registers honest-cv-dev with the fictional profile, so Claude Code
in this folder can use your working copy. See CONTRIBUTING.md.
License
MIT. The bundled Carlito font is under the SIL Open Font License; see
src/honest_cv/render/fonts/OFL.txt.
From the server's repository — third-party content, read it before running anything it suggests.
More in Marketing
Dynamoi
io.github.getDynamoi
Music marketing for AI agents: free Smart Links, promotion campaigns, analytics, and distribution.
Evascrape
com.evascrape
Find business leads with emails from Google Maps, Apollo.io and LinkedIn. Prepaid, API key.
ATS Engine
io.github.VeriWorkly
Read your own resume the way an ATS does and score it with a published, deterministic rubric.
OI AI Adoption
com.operative-intelligence
Advice on bringing AI into work processes, with sourced effects, risks and rules for SI, HR, DE, AT
EvidujZdarma – EET 2.0 (Czech sales registration)
cz.evidujzdarma
Czech EET 2.0 from 1 Jan 2027: check an IČO, classify payments, EET OFF cost, cited facts.
OpenSDR
io.github.arif-js
Open-source AI SDR: B2B prospecting, email enrichment, buying signals and safe outreach staging.
Listing from the official MCP Registry · repository facts from GitHub, 17m ago.