honest-cv 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- honest_cv-0.2.0/.gitignore +11 -0
- honest_cv-0.2.0/CHANGELOG.md +142 -0
- honest_cv-0.2.0/CONTRIBUTING.md +73 -0
- honest_cv-0.2.0/LICENSE +21 -0
- honest_cv-0.2.0/PKG-INFO +364 -0
- honest_cv-0.2.0/README.es.md +343 -0
- honest_cv-0.2.0/README.md +332 -0
- honest_cv-0.2.0/examples/ada/bullets.yaml +113 -0
- honest_cv-0.2.0/examples/ada/job-keywords.yaml +4 -0
- honest_cv-0.2.0/examples/ada/job-post.md +22 -0
- honest_cv-0.2.0/examples/ada/profile.yaml +49 -0
- honest_cv-0.2.0/examples/ada/skills.yaml +20 -0
- honest_cv-0.2.0/examples/ada/variants.yaml +73 -0
- honest_cv-0.2.0/examples/checklists/project-management.md +52 -0
- honest_cv-0.2.0/pyproject.toml +75 -0
- honest_cv-0.2.0/skills/honest-cv/SKILL.md +193 -0
- honest_cv-0.2.0/src/honest_cv/__init__.py +3 -0
- honest_cv-0.2.0/src/honest_cv/applications.py +136 -0
- honest_cv-0.2.0/src/honest_cv/build.py +51 -0
- honest_cv-0.2.0/src/honest_cv/checklist.py +570 -0
- honest_cv-0.2.0/src/honest_cv/checklists/backend-go.md +63 -0
- honest_cv-0.2.0/src/honest_cv/checklists/backend-jvm.md +90 -0
- honest_cv-0.2.0/src/honest_cv/checklists/backend-python.md +70 -0
- honest_cv-0.2.0/src/honest_cv/checklists/data.md +65 -0
- honest_cv-0.2.0/src/honest_cv/checklists/engineering-lead.md +51 -0
- honest_cv-0.2.0/src/honest_cv/checklists/frontend.md +62 -0
- honest_cv-0.2.0/src/honest_cv/checklists/platform-sre.md +81 -0
- honest_cv-0.2.0/src/honest_cv/checklists/software-architecture.md +62 -0
- honest_cv-0.2.0/src/honest_cv/cli.py +481 -0
- honest_cv-0.2.0/src/honest_cv/document.py +172 -0
- honest_cv-0.2.0/src/honest_cv/export.py +119 -0
- honest_cv-0.2.0/src/honest_cv/importer.py +384 -0
- honest_cv-0.2.0/src/honest_cv/letter.py +286 -0
- honest_cv-0.2.0/src/honest_cv/linkedin.py +142 -0
- honest_cv-0.2.0/src/honest_cv/model.py +390 -0
- honest_cv-0.2.0/src/honest_cv/prompts/cover_letter.md +40 -0
- honest_cv-0.2.0/src/honest_cv/prompts/import_linkedin_pdf.md +28 -0
- honest_cv-0.2.0/src/honest_cv/prompts/interview.md +100 -0
- honest_cv-0.2.0/src/honest_cv/prompts/linkedin_profile.md +30 -0
- honest_cv-0.2.0/src/honest_cv/prompts/tailor_for_job.md +61 -0
- honest_cv-0.2.0/src/honest_cv/render/__init__.py +0 -0
- honest_cv-0.2.0/src/honest_cv/render/docx.py +99 -0
- honest_cv-0.2.0/src/honest_cv/render/fonts/Carlito-Bold.ttf +0 -0
- honest_cv-0.2.0/src/honest_cv/render/fonts/Carlito-Regular.ttf +0 -0
- honest_cv-0.2.0/src/honest_cv/render/fonts/OFL.txt +94 -0
- honest_cv-0.2.0/src/honest_cv/render/pdf.py +84 -0
- honest_cv-0.2.0/src/honest_cv/render/templates/classic.typ +95 -0
- honest_cv-0.2.0/src/honest_cv/render/templates/letter.typ +46 -0
- honest_cv-0.2.0/src/honest_cv/score.py +283 -0
- honest_cv-0.2.0/src/honest_cv/server.py +974 -0
- honest_cv-0.2.0/src/honest_cv/store.py +365 -0
- honest_cv-0.2.0/src/honest_cv/templates/profile/bullets.yaml +10 -0
- honest_cv-0.2.0/src/honest_cv/templates/profile/profile.yaml +34 -0
- honest_cv-0.2.0/src/honest_cv/templates/profile/skills.yaml +8 -0
- honest_cv-0.2.0/src/honest_cv/templates/profile/variants.yaml +17 -0
- honest_cv-0.2.0/src/honest_cv/verify.py +177 -0
- honest_cv-0.2.0/tests/__init__.py +0 -0
- honest_cv-0.2.0/tests/conftest.py +32 -0
- honest_cv-0.2.0/tests/fixtures/resume.json +73 -0
- honest_cv-0.2.0/tests/test_applications.py +114 -0
- honest_cv-0.2.0/tests/test_checklist.py +320 -0
- honest_cv-0.2.0/tests/test_export.py +74 -0
- honest_cv-0.2.0/tests/test_honesty.py +70 -0
- honest_cv-0.2.0/tests/test_import.py +176 -0
- honest_cv-0.2.0/tests/test_letter.py +120 -0
- honest_cv-0.2.0/tests/test_linkedin.py +87 -0
- honest_cv-0.2.0/tests/test_model.py +91 -0
- honest_cv-0.2.0/tests/test_prompts.py +78 -0
- honest_cv-0.2.0/tests/test_release.py +26 -0
- honest_cv-0.2.0/tests/test_render_ats.py +180 -0
- honest_cv-0.2.0/tests/test_score.py +140 -0
- honest_cv-0.2.0/tests/test_server.py +386 -0
- honest_cv-0.2.0/tests/test_smoke.py +10 -0
- honest_cv-0.2.0/tests/test_store.py +206 -0
- honest_cv-0.2.0/tests/test_templates.py +80 -0
- honest_cv-0.2.0/tests/test_verify.py +74 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to honest-cv. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
|
+
and versions follow [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.2.0] — 2026-10-15
|
|
7
|
+
|
|
8
|
+
Closed on 2026-10-15 after a full test as a new user. The first release on PyPI.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `export_json_resume` and `honest-cv export`: a variant as JSON Resume, in one language. X skills
|
|
13
|
+
never appear and F skills keep their label; importing the file back gives the same profile.
|
|
14
|
+
- Your own checklist templates, for any profession: files in `<profile>/checklists/` show up in
|
|
15
|
+
`checklist_list` and combine with the built-in ones in `checklist_new`, which also takes a path.
|
|
16
|
+
- `checklist_apply` returns `skills_without_achievements`, the P and L skills no bullet shows, and
|
|
17
|
+
`key_skills_without_achievements`, the P ones in the ★ section or a variant. The assistant asks
|
|
18
|
+
first for the person's biggest achievements, then for the key skills still uncovered. The rest
|
|
19
|
+
wait for a job post: `gap_report` → `no_achievement` lists the ones it asks for.
|
|
20
|
+
- Templates can declare synonyms (`same: Work Breakdown Structure = WBS = EDT`). Those in
|
|
21
|
+
`<profile>/checklists/` count in the job score, the gaps, checklist merging and the letter check,
|
|
22
|
+
which also learns their skill names, so it works for any profession.
|
|
23
|
+
- An example template for another profession: `examples/checklists/project-management.md`.
|
|
24
|
+
- A built-in `software-architecture` checklist: styles and patterns, integration, quality
|
|
25
|
+
attributes, data architecture and the practice (ADRs, reviews, technical debt). New synonyms:
|
|
26
|
+
ADRs, ports and adapters, diseño de sistemas, CDC.
|
|
27
|
+
- Application tracking in `<profile>/applications.yaml`: `log_application`, `list_applications`
|
|
28
|
+
and `honest-cv apps log|list`. Each status change keeps its date; open applications with no
|
|
29
|
+
news for 14 days are listed as waiting.
|
|
30
|
+
Each application keeps the job post's text in `<profile>/posts/`, since links expire, and the
|
|
31
|
+
points to prepare for its interview (`prep`).
|
|
32
|
+
- LinkedIn texts from a variant, within LinkedIn's limits: `linkedin_profile` (tool and prompt) and
|
|
33
|
+
`honest-cv linkedin`. Headline, About, one description per position and the skills, P and L only.
|
|
34
|
+
An approved, polished headline and About go back through the tool, which checks them like a
|
|
35
|
+
letter and saves them in the file.
|
|
36
|
+
- The interview handles dictated answers: it reads names and numbers back before saving them, and
|
|
37
|
+
turns a long spoken answer into a bullet for the person to approve.
|
|
38
|
+
- A Courses section (`courses` in `profile.yaml`, set with `set_profile_details`) for training
|
|
39
|
+
without an exam, which is not a certification. JSON Resume has no field for it, so the export
|
|
40
|
+
leaves it out.
|
|
41
|
+
- The checklist header shows a marked example line.
|
|
42
|
+
- Publications: books, articles and papers the person wrote (`upsert_publication`,
|
|
43
|
+
`remove_publication`), in their own CV section. A variant shows all of them or the ones it lists.
|
|
44
|
+
The LinkedIn and JSON Resume imports read publications (and LinkedIn's courses), and the JSON
|
|
45
|
+
Resume export writes them.
|
|
46
|
+
- Spanish spellings of leadership and practice terms in job posts (liderazgo de equipos, revisión
|
|
47
|
+
de código, patrones de diseño, agentes de IA…) match the skill. In a letter, practices are not
|
|
48
|
+
claims to check.
|
|
49
|
+
- When every role has ended, summaries, letters and LinkedIn texts speak of that work in the
|
|
50
|
+
past tense.
|
|
51
|
+
- Evidence must say where and how: the assistant asks for each skill instead of taking a bare
|
|
52
|
+
"yes" to a list.
|
|
53
|
+
- The interview warns that it can take hours, proposes a first session that is enough for a CV,
|
|
54
|
+
and picks up where it stopped. The READMEs say so too.
|
|
55
|
+
- The interview asks once for certifications, courses and anything the person wrote, which people
|
|
56
|
+
rarely mention unasked.
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- The server's instructions cover checklists, dictated answers, applications, LinkedIn and export,
|
|
61
|
+
for clients that don't load the skill.
|
|
62
|
+
- `checklist list` shows "(yours)" next to the title of your own templates.
|
|
63
|
+
- Clearer error for an application date that isn't YYYY-MM-DD.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- Lowering a skill now lowers its mark in `<profile>/checklist.md` too. Before, the file kept
|
|
68
|
+
the old mark, and applying it again proposed the upgrade the person had undone. The
|
|
69
|
+
confirmation form also shows the person's own note on a skill first, since it may say why
|
|
70
|
+
they lowered it.
|
|
71
|
+
- A checklist mark typed with spaces, like `[ P]`, was skipped in silence; it now counts, and
|
|
72
|
+
any other text in the brackets is reported as a problem.
|
|
73
|
+
- A composed checklist's title said "imported skills" whenever the inventory had skills outside
|
|
74
|
+
the chosen lists.
|
|
75
|
+
|
|
76
|
+
## [0.1.0] — unreleased, frozen
|
|
77
|
+
|
|
78
|
+
Frozen on the `release/0.1` branch on 2026-10-14; it will be published from there.
|
|
79
|
+
|
|
80
|
+
The first release: an MCP server, a CLI and a Claude Code skill that turn one profile folder into
|
|
81
|
+
honest, ATS-safe CVs and cover letters.
|
|
82
|
+
|
|
83
|
+
### Profile and honesty
|
|
84
|
+
|
|
85
|
+
- A profile is four YAML files: contact and roles, a pool of achievement bullets, a skill inventory
|
|
86
|
+
and variants per type of role, with `extends:` inheritance. Texts can be per language (EN, ES).
|
|
87
|
+
- Skill levels: P (production), L (own project or lab), F (familiarity, always labeled as such)
|
|
88
|
+
and X (never shown, but kept so gap reports are honest).
|
|
89
|
+
- Raising a level needs written evidence and the person's own confirmation. In MCP clients that
|
|
90
|
+
support elicitation, a form asks "no / sí" for each upgrade, up to 10 at a time; elsewhere the
|
|
91
|
+
CLI asks in the terminal. The model cannot confirm for the person.
|
|
92
|
+
- Tools to edit every part of the profile, each validating the whole profile before writing, and
|
|
93
|
+
to remove a skill, bullet or role without leaving a broken reference.
|
|
94
|
+
|
|
95
|
+
### CVs
|
|
96
|
+
|
|
97
|
+
- PDF with Typst and the bundled Carlito font, the same on every machine with no system fonts;
|
|
98
|
+
DOCX with python-docx. `fit_pages` adjusts density to meet a variant's page limit.
|
|
99
|
+
- ATS guarantees checked on every build with pypdf and pdfminer.six: one column, no ligatures,
|
|
100
|
+
no kerning, no hyphenation, dates on their role's line, reading order, every bullet extracted,
|
|
101
|
+
and terms like "CI/CD", URLs and emails never split across lines.
|
|
102
|
+
- `verify` checks any PDF, including CVs made with other tools.
|
|
103
|
+
|
|
104
|
+
### Job posts
|
|
105
|
+
|
|
106
|
+
- Keyword coverage per variant, with synonyms in English and Spanish.
|
|
107
|
+
- Gaps classified against the person's own inventory: in the inventory but not on this CV,
|
|
108
|
+
familiarity only, or not held.
|
|
109
|
+
|
|
110
|
+
### Skill checklists
|
|
111
|
+
|
|
112
|
+
- Mark many skills at once in a Markdown file: one letter per line, evidence after " — ", an
|
|
113
|
+
optional evidence line per section, years and last year used.
|
|
114
|
+
- Seven built-in checklists (backend JVM, Python and Go, frontend, platform/SRE, data,
|
|
115
|
+
engineering leadership), merged without duplicates and prefilled from the inventory.
|
|
116
|
+
- Any checklist written by hand can be applied, in English or Spanish. Lines without evidence
|
|
117
|
+
come back as pending and are asked about in groups.
|
|
118
|
+
|
|
119
|
+
### Cover letters
|
|
120
|
+
|
|
121
|
+
- `check_claims` reads any text against the profile. It blocks an X skill, or an F skill
|
|
122
|
+
presented as experience, and warns about technologies and numbers the profile doesn't show.
|
|
123
|
+
- `build_letter` renders a one-page letter to PDF and DOCX with the CV's ATS checks, and refuses
|
|
124
|
+
while there are problems.
|
|
125
|
+
|
|
126
|
+
### Import
|
|
127
|
+
|
|
128
|
+
- JSON Resume and LinkedIn's data export (ZIP of CSVs): contact, roles, achievements,
|
|
129
|
+
education, certifications and languages. It only adds what is missing and never overwrites.
|
|
130
|
+
Skills arrive without a level, as a checklist to mark.
|
|
131
|
+
- LinkedIn's profile PDF: the server returns its text and the client proposes each section for
|
|
132
|
+
the person to approve.
|
|
133
|
+
- The export may be a ZIP or the folder a browser unzipped it into, and a profile may have no
|
|
134
|
+
email. The report names the files the export lacks: LinkedIn's basic export has only the
|
|
135
|
+
profile, without roles or email.
|
|
136
|
+
|
|
137
|
+
### Clients
|
|
138
|
+
|
|
139
|
+
- Tested in Claude Code (confirmation in the chat) and Claude Desktop (confirmation in a
|
|
140
|
+
terminal). The server needs no API key and makes no network calls.
|
|
141
|
+
|
|
142
|
+
[0.1.0]: https://github.com/JesusCabreraReveles/honest-cv/releases/tag/v0.1.0
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Contributing to honest-cv
|
|
2
|
+
|
|
3
|
+
Thanks for helping. Issues and pull requests are welcome, in English or Spanish.
|
|
4
|
+
|
|
5
|
+
## Ground rules
|
|
6
|
+
|
|
7
|
+
- **Never commit real personal data.** Tests, demos, screenshots and issues use only the fictional
|
|
8
|
+
profile in `examples/ada/`. Put real profiles in `profiles/`, which is ignored by git, or outside
|
|
9
|
+
the repository.
|
|
10
|
+
- **The code enforces honesty, not a prompt.**
|
|
11
|
+
- An `F` skill is always rendered under the "Familiarity" / "Familiaridad" label.
|
|
12
|
+
- An `X` skill is never rendered.
|
|
13
|
+
- Raising a level requires `evidence` and the person's confirmation.
|
|
14
|
+
|
|
15
|
+
A change that touches these rules must keep their tests passing, and a new rule needs a new test.
|
|
16
|
+
- **ATS guarantees are invariants.**
|
|
17
|
+
- One column; no layout tables, images, icons, headers or footers.
|
|
18
|
+
- Ligatures off; source order equals reading order.
|
|
19
|
+
- Text extractable by pypdf and pdfminer.six.
|
|
20
|
+
|
|
21
|
+
If a design idea breaks one of these, it doesn't go into the default template.
|
|
22
|
+
- **The server stays deterministic and keyless.** The MCP client's model does the language work;
|
|
23
|
+
the server validates, builds, verifies and measures.
|
|
24
|
+
- **Scope.** The v0.1 scope is in [`docs/PLAN.md`](docs/PLAN.md). Larger ideas (JSON Resume
|
|
25
|
+
import, LinkedIn import, cover letters, more templates) start as an issue.
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv sync
|
|
31
|
+
uv run pytest # the whole suite runs in a few seconds
|
|
32
|
+
uv run honest-cv build examples/ada -l en -l es # writes to out/
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Python 3.11 or newer. Code, names and comments are in English.
|
|
36
|
+
|
|
37
|
+
## Useful pieces
|
|
38
|
+
|
|
39
|
+
| Path | What lives there |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `src/honest_cv/model.py` | YAML schemas, `extends:` resolution and the skill-upgrade rule. |
|
|
42
|
+
| `src/honest_cv/document.py` | Turns a variant and a language into a document. The honesty rules apply here. |
|
|
43
|
+
| `src/honest_cv/render/` | The Typst template, the bundled fonts, the PDF renderer with `fit_pages`, and the DOCX renderer. |
|
|
44
|
+
| `src/honest_cv/verify.py` | ATS checks. |
|
|
45
|
+
| `src/honest_cv/score.py` | Keyword coverage, synonyms and gaps. |
|
|
46
|
+
| `src/honest_cv/server.py` | MCP tools and prompts. |
|
|
47
|
+
| `src/honest_cv/prompts/`, `skills/honest-cv/SKILL.md` | Conversation flows. A test keeps the tool names they mention in sync with the server. |
|
|
48
|
+
|
|
49
|
+
## Common contributions
|
|
50
|
+
|
|
51
|
+
- **Synonyms.** Add a group to `SYNONYMS` in `score.py`, with the canonical name first. Add a case
|
|
52
|
+
to `tests/test_score.py`. Terms of three characters or fewer match case-sensitively.
|
|
53
|
+
- **Checklists.** Add `src/honest_cv/checklists/<id>.md` for a kind of role that is missing: a
|
|
54
|
+
`# Title`, a one-line description, a `## ★ Main skills — years and last year used` section with
|
|
55
|
+
the skills that filter the most, then sections by topic. Leave every line unmarked (`- [ ] Name`)
|
|
56
|
+
and use the canonical names from `SYNONYMS`. `tests/test_checklist.py` checks all of this.
|
|
57
|
+
- **Checklists for other professions.** honest-cv is not only for software. A checklist for
|
|
58
|
+
another field (nursing, accounting, sales, teaching...) goes to `examples/checklists/<id>.md`,
|
|
59
|
+
in the same format, and may declare its synonyms with `same:` lines, the main name first:
|
|
60
|
+
`same: Work Breakdown Structure = WBS = EDT`. People copy it to `<profile>/checklists/`, where
|
|
61
|
+
`checklist_list` shows it and the job score, the gaps and the letter check use its names and
|
|
62
|
+
synonyms. `tests/test_templates.py` checks the format; see `project-management.md`.
|
|
63
|
+
- **Templates.** A new CV template must pass `verify_pdf` with the Ada profile in both languages.
|
|
64
|
+
Never put text in a box aligned to the right.
|
|
65
|
+
- **The demo GIF.** Regenerate it with `vhs docs/demo.tape` after the CLI output changes.
|
|
66
|
+
- **Packaging.** After `uv build`, `scripts/smoke.sh` checks the wheel on a clean Linux in
|
|
67
|
+
Docker; the command is at the top of the script.
|
|
68
|
+
|
|
69
|
+
## Pull requests
|
|
70
|
+
|
|
71
|
+
- Keep each pull request small and focused, with tests.
|
|
72
|
+
- CI must pass on Linux, macOS and Windows.
|
|
73
|
+
- Describe what changes for the person using the tool.
|
honest_cv-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jesus Cabrera
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
honest_cv-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: honest-cv
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Honest, ATS-safe, per-role CVs generated by your AI agent (MCP server + CLI + Claude Code skill).
|
|
5
|
+
Project-URL: Homepage, https://github.com/JesusCabreraReveles/honest-cv
|
|
6
|
+
Project-URL: Repository, https://github.com/JesusCabreraReveles/honest-cv
|
|
7
|
+
Project-URL: Issues, https://github.com/JesusCabreraReveles/honest-cv/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/JesusCabreraReveles/honest-cv/blob/master/CHANGELOG.md
|
|
9
|
+
Author: Jesus Cabrera
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ats,claude,cv,mcp,resume
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Office/Business
|
|
22
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: mcp<3,>=2.3
|
|
25
|
+
Requires-Dist: pdfminer-six>=20231228
|
|
26
|
+
Requires-Dist: pydantic>=2.6
|
|
27
|
+
Requires-Dist: pypdf>=4.0
|
|
28
|
+
Requires-Dist: python-docx>=1.1
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Requires-Dist: typst>=0.15
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# honest-cv
|
|
34
|
+
|
|
35
|
+
[](https://github.com/JesusCabreraReveles/honest-cv/actions/workflows/ci.yml)
|
|
36
|
+
[](https://github.com/JesusCabreraReveles/honest-cv/blob/master/LICENSE)
|
|
37
|
+
|
|
38
|
+
<!-- mcp-name: io.github.JesusCabreraReveles/honest-cv -->
|
|
39
|
+
|
|
40
|
+
**Honest, ATS-safe CVs tailored to each role, generated by your AI agent.** honest-cv is an MCP
|
|
41
|
+
server, a CLI and a Claude Code skill. It keeps one source of truth about your experience and
|
|
42
|
+
turns it into a PDF and DOCX for each type of role. It never claims a skill you don't have.
|
|
43
|
+
|
|
44
|
+
[Leer en español](https://github.com/JesusCabreraReveles/honest-cv/blob/master/README.es.md)
|
|
45
|
+
|
|
46
|
+

|
|
47
|
+
|
|
48
|
+
## Why
|
|
49
|
+
|
|
50
|
+
Many CVs that get no callbacks don't fail on design. They fail on targeting, and on details that
|
|
51
|
+
quietly break text extraction. AI makes the opposite problem easy: a model will happily stuff a CV
|
|
52
|
+
with keywords you can't defend in an interview. honest-cv is built around three ideas:
|
|
53
|
+
|
|
54
|
+
- **The code enforces honesty, not a prompt.** Every skill has a level. A skill at familiarity
|
|
55
|
+
level is always labeled as such, and a skill you don't have is never printed. Raising a level
|
|
56
|
+
takes written evidence and *your* confirmation, which the server asks you for directly. The
|
|
57
|
+
model can't confirm on your behalf.
|
|
58
|
+
- **Gaps are measured against your own inventory.** For each keyword a job post asks for,
|
|
59
|
+
honest-cv tells you which of three cases it is:
|
|
60
|
+
- you have it, but this CV doesn't show it;
|
|
61
|
+
- you only know it at familiarity level;
|
|
62
|
+
- you don't have it.
|
|
63
|
+
- **ATS safety is checked on every build.** Every PDF goes through two text extractors (pypdf and
|
|
64
|
+
pdfminer.six). The build checks that the text is one column, has no ligatures, keeps each date on
|
|
65
|
+
its role's line, follows the right reading order and includes every bullet.
|
|
66
|
+
|
|
67
|
+
The server is deterministic and needs no API key. Your MCP client's model runs the conversation;
|
|
68
|
+
honest-cv validates, builds, verifies and measures. It keeps your profile in a folder on your
|
|
69
|
+
machine and never sends it anywhere: see [Privacy](#privacy) for what your AI client does with it.
|
|
70
|
+
|
|
71
|
+
<p align="center"><img src="https://raw.githubusercontent.com/JesusCabreraReveles/honest-cv/master/docs/assets/ada-platform-en.png" width="560" alt="A generated one-page CV for the fictional Ada Example"></p>
|
|
72
|
+
|
|
73
|
+
## Quick start
|
|
74
|
+
|
|
75
|
+
honest-cv needs [uv](https://docs.astral.sh/uv/). Typst and the fonts ship inside the package,
|
|
76
|
+
so there is nothing else to install.
|
|
77
|
+
It runs on Linux (glibc) on x86_64 and ARM64, macOS on Intel and Apple
|
|
78
|
+
Silicon, and Windows on x64. Alpine Linux and Windows on ARM aren't supported, because the `typst`
|
|
79
|
+
package doesn't publish wheels for them.
|
|
80
|
+
|
|
81
|
+
### Claude Code
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
claude mcp add honest-cv -- uvx honest-cv serve --profile ~/cv-profile
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
To install the skill as well, which guides the interview and the tailoring:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
mkdir -p ~/.claude/skills/honest-cv
|
|
91
|
+
curl -fsSL https://raw.githubusercontent.com/JesusCabreraReveles/honest-cv/master/skills/honest-cv/SKILL.md \
|
|
92
|
+
-o ~/.claude/skills/honest-cv/SKILL.md
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Then start with *"interview me for my CV"*, or run `/mcp__honest-cv__interview`. You can answer
|
|
96
|
+
by voice with your system's dictation (on macOS: System Settings → Keyboard → Dictation): the
|
|
97
|
+
interview reads names and numbers back to you before saving them, since dictation mishears them.
|
|
98
|
+
|
|
99
|
+
> **The first interview is long.** With a long career and many skills it can take several hours.
|
|
100
|
+
> You don't have to do it in one sitting: everything is saved as you go, so stop whenever you like
|
|
101
|
+
> and say *"let's continue my CV interview"* later. A good first session covers your contact
|
|
102
|
+
> details, your two most recent roles and the skills checklist; with that you can already build a
|
|
103
|
+
> CV, and older roles can wait.
|
|
104
|
+
|
|
105
|
+
### Cursor
|
|
106
|
+
|
|
107
|
+
Add this to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` in a project:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"mcpServers": {
|
|
112
|
+
"honest-cv": {
|
|
113
|
+
"command": "uvx",
|
|
114
|
+
"args": ["honest-cv", "serve", "--profile", "/absolute/path/to/cv-profile"]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Claude Desktop
|
|
121
|
+
|
|
122
|
+
Edit `claude_desktop_config.json`:
|
|
123
|
+
- on macOS, `~/Library/Application Support/Claude/`;
|
|
124
|
+
- on Windows, `%APPDATA%\Claude\`.
|
|
125
|
+
|
|
126
|
+
Add the same `mcpServers` block as in the Cursor example and restart the app. If the app can't
|
|
127
|
+
find `uvx`, use its absolute path (`which uvx`).
|
|
128
|
+
|
|
129
|
+
### How each client confirms a skill upgrade
|
|
130
|
+
|
|
131
|
+
Raising a skill's level needs your own confirmation, which the server asks for through MCP
|
|
132
|
+
elicitation. Not every client supports it yet:
|
|
133
|
+
|
|
134
|
+
| Client | Where you confirm |
|
|
135
|
+
|---|---|
|
|
136
|
+
| 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. |
|
|
137
|
+
| 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 "..."`. |
|
|
138
|
+
| Other clients | In the chat if they support elicitation, otherwise in a terminal as above. |
|
|
139
|
+
|
|
140
|
+
## Your profile
|
|
141
|
+
|
|
142
|
+
A profile is a folder with four YAML files. Create one with `honest-cv init ~/cv-profile`, or let
|
|
143
|
+
the `interview` prompt fill it in with you. Keep it out of public repositories.
|
|
144
|
+
|
|
145
|
+
| File | What it holds |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `profile.yaml` | Contact details, roles, education, certifications, publications, courses and languages. |
|
|
148
|
+
| `bullets.yaml` | A pool of achievements, each with an `id`, a `role` and `tags`. |
|
|
149
|
+
| `skills.yaml` | Your skill inventory, with levels and evidence. |
|
|
150
|
+
| `variants.yaml` | One CV plan per type of role. A variant can inherit from another with `extends:`. |
|
|
151
|
+
|
|
152
|
+
Any text can be a single string or one string per language: `{en: ..., es: ...}`. CVs can be
|
|
153
|
+
built in English and in Spanish.
|
|
154
|
+
|
|
155
|
+
| Level | Meaning | On the CV |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `P` | Used in production at a job | Shown |
|
|
158
|
+
| `L` | Your own project or lab | Shown |
|
|
159
|
+
| `F` | Familiarity | Only on the line labeled "Familiarity" |
|
|
160
|
+
| `X` | You don't have it | Never shown, but recorded so gap reports are honest |
|
|
161
|
+
|
|
162
|
+
### Skill checklists
|
|
163
|
+
|
|
164
|
+
Recording dozens of skills one question at a time is slow. A checklist is a Markdown file you mark
|
|
165
|
+
in your editor, one letter per line:
|
|
166
|
+
|
|
167
|
+
```markdown
|
|
168
|
+
## Messaging and streaming
|
|
169
|
+
evidence: Payments platform at Acme, 2020–2026
|
|
170
|
+
- [P] Kafka — reconciliation flow, 2M events a day · years: 6 · last year: 2026
|
|
171
|
+
- [F] RabbitMQ — a workshop and the official tutorials
|
|
172
|
+
- [X] NATS
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Text after " — " is the evidence, and an `evidence:` line under a heading covers that section.
|
|
176
|
+
Lines without evidence are never saved: they come back as pending, and your assistant asks you
|
|
177
|
+
about them in groups. Upgrades are confirmed once for the whole file.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
honest-cv checklist list # backend-jvm, platform-sre, ...
|
|
181
|
+
honest-cv checklist new ~/cv-profile backend-jvm engineering-lead
|
|
182
|
+
honest-cv checklist apply ~/cv-profile ~/cv-profile/checklist.md
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Any profession works.** The built-in checklists are for software roles, but a template is just a
|
|
186
|
+
Markdown list in this format: save your own (or one someone shared) in `~/cv-profile/checklists/`
|
|
187
|
+
and it shows up in `checklist list` and combines with the others in `checklist new`, which also
|
|
188
|
+
takes a path. A template can declare synonyms, such as `same: Work Breakdown Structure = WBS`,
|
|
189
|
+
and the job score, the gaps and the letter check use them, along with its skill names. Start from
|
|
190
|
+
[`examples/checklists/project-management.md`](https://github.com/JesusCabreraReveles/honest-cv/blob/master/examples/checklists/project-management.md). You can also apply a file you marked yourself, in English or Spanish (`años`,
|
|
191
|
+
`último uso`). When you're done, honest-cv names the P and L skills that no achievement shows, and
|
|
192
|
+
your assistant asks you for one real example of each.
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
honest-cv checklist list ~/cv-profile # yours too, e.g. accounting
|
|
196
|
+
honest-cv checklist new ~/cv-profile accounting engineering-lead
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
New checklists for other kinds of roles are welcome: see [CONTRIBUTING.md](https://github.com/JesusCabreraReveles/honest-cv/blob/master/CONTRIBUTING.md).
|
|
200
|
+
|
|
201
|
+
See [`examples/ada/`](https://github.com/JesusCabreraReveles/honest-cv/tree/master/examples/ada) for a complete, fictional profile with three variants, a job
|
|
202
|
+
post and its keywords.
|
|
203
|
+
|
|
204
|
+
## Privacy
|
|
205
|
+
|
|
206
|
+
- **honest-cv itself makes no network calls.** No accounts, no telemetry, no API keys. Your
|
|
207
|
+
profile is a folder of YAML files on your machine, and the PDF engine and fonts run locally. You
|
|
208
|
+
can check it: every command works with the network turned off.
|
|
209
|
+
- **Your AI client is a different matter.** Whatever the client's model reads through the tools
|
|
210
|
+
goes to that model's provider, under the provider's terms, like anything else you share in a
|
|
211
|
+
chat. That includes your skills, bullets and the text of your CVs.
|
|
212
|
+
- **Some clients copy files to the cloud.** To edit files directly, Claude Desktop may ask for
|
|
213
|
+
access to the profile folder and say that the files leave your device. honest-cv's editing tools
|
|
214
|
+
make that unnecessary: decline the request and ask the assistant to use the tools.
|
|
215
|
+
- **If you want nothing to leave your machine,** use only the CLI (`build`, `verify`, `score`,
|
|
216
|
+
`skill`) and edit the YAML files yourself.
|
|
217
|
+
|
|
218
|
+
## Import what you already have
|
|
219
|
+
|
|
220
|
+
`honest-cv import` reads a [JSON Resume](https://jsonresume.org) file or LinkedIn's data export
|
|
221
|
+
(Settings → Data privacy → Download your data, a ZIP of CSVs, or its folder if your browser
|
|
222
|
+
unzipped it). Ask for the full archive: the basic one, offered when you pick files, has only your
|
|
223
|
+
headline and summary, without roles. Contact, roles, education,
|
|
224
|
+
certifications, languages and each role's achievements go into your profile; with a headline and
|
|
225
|
+
a summary it also creates a first variant, so `build` works right away.
|
|
226
|
+
|
|
227
|
+
- It only adds what your profile lacks and never overwrites. Try `--dry-run` first.
|
|
228
|
+
- Imported achievements are tagged `imported`: review their wording.
|
|
229
|
+
- **Skills arrive without a level**, because neither format says whether you used a skill in
|
|
230
|
+
production. They go to `imported-skills.md`, a checklist for you to mark.
|
|
231
|
+
|
|
232
|
+
LinkedIn's "Save to PDF" profile changes layout without notice, so it isn't parsed: with an MCP
|
|
233
|
+
client, the `import_linkedin_pdf` prompt reads its text and proposes each section for you to
|
|
234
|
+
approve.
|
|
235
|
+
|
|
236
|
+
## Track your applications
|
|
237
|
+
|
|
238
|
+
`honest-cv apps` keeps a log in `applications.yaml`, inside your profile folder: which variant and
|
|
239
|
+
files went to which company, and each status with its date (`draft`, `applied`, `interview`,
|
|
240
|
+
`offer`, `rejected`, `withdrawn`). Logging the same company and role again updates it. With an MCP
|
|
241
|
+
client, your assistant offers to log an application after building the CV or letter, and
|
|
242
|
+
`list_applications` points out the ones with no news for two weeks. It also keeps the job post's
|
|
243
|
+
text in `posts/`, since links expire, and what to prepare for the interview: ask your assistant
|
|
244
|
+
*"what did I need to prepare for Acme?"*.
|
|
245
|
+
|
|
246
|
+
## LinkedIn
|
|
247
|
+
|
|
248
|
+
`honest-cv linkedin` turns a variant into LinkedIn's texts, each within its limit: the headline
|
|
249
|
+
(your title and up to five production skills), About (the summary and impact bullets), one
|
|
250
|
+
description per position from its bullets, and the skills list. It writes them to a Markdown file
|
|
251
|
+
to copy from. The skills are P and L only: LinkedIn can't label familiarity, so F skills stay out,
|
|
252
|
+
and X skills never appear. With an MCP client, the `linkedin_profile` prompt polishes the wording
|
|
253
|
+
and checks it with `check_claims`.
|
|
254
|
+
|
|
255
|
+
## Export
|
|
256
|
+
|
|
257
|
+
To go the other way, `honest-cv export` writes a variant as JSON Resume for other CV tools and
|
|
258
|
+
sites, with the same rules as the CV: X skills never appear, and F skills only in a "Familiarity"
|
|
259
|
+
group with that level.
|
|
260
|
+
|
|
261
|
+
## Cover letters
|
|
262
|
+
|
|
263
|
+
The `cover_letter` prompt drafts a one-page letter for a job post from your own bullets. Before it
|
|
264
|
+
is built, `check_claims` reads the text against your profile:
|
|
265
|
+
|
|
266
|
+
- **Problems block the build:** a skill you marked X, or a familiarity skill presented as
|
|
267
|
+
experience ("I use Rust in production" when Rust is F; "I am familiar with Rust" is fine).
|
|
268
|
+
- **Warnings are for you to review:** a technology neither your inventory nor your bullets show,
|
|
269
|
+
or a number that appears nowhere in your profile. If it is true, record it first; if not, it
|
|
270
|
+
comes out of the letter.
|
|
271
|
+
|
|
272
|
+
The letter uses the CV's fonts and passes the same ATS checks. Without an AI client, write it in a
|
|
273
|
+
text file (paragraphs separated by blank lines) and use `honest-cv letter check` and `letter build`.
|
|
274
|
+
|
|
275
|
+
## CLI
|
|
276
|
+
|
|
277
|
+
Run any command with `uvx honest-cv ...`, or install it once with `uv tool install honest-cv` to
|
|
278
|
+
type just `honest-cv`.
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
honest-cv init ~/cv-profile # create the profile templates
|
|
282
|
+
honest-cv build ~/cv-profile -v backend -l en -l es # PDF + DOCX, verified on every build
|
|
283
|
+
honest-cv verify any-cv.pdf --text # check any PDF, even one made elsewhere
|
|
284
|
+
honest-cv score ~/cv-profile -k "Kubernetes,Go" -p "Rust" # coverage per variant, with gaps
|
|
285
|
+
honest-cv skill ~/cv-profile "Rust" L --evidence "CLI tool on GitHub" # asks you to confirm
|
|
286
|
+
honest-cv import ~/cv-profile linkedin-export.zip --dry-run # or resume.json
|
|
287
|
+
honest-cv export ~/cv-profile -v backend -l en # JSON Resume
|
|
288
|
+
honest-cv apps log ~/cv-profile --company Acme --role "SRE" -s applied -v platform
|
|
289
|
+
honest-cv apps list ~/cv-profile # latest first, with counts
|
|
290
|
+
honest-cv linkedin ~/cv-profile -v platform -l en # texts to paste into LinkedIn
|
|
291
|
+
honest-cv remove skill ~/cv-profile "Kafka" # asks you to confirm
|
|
292
|
+
honest-cv letter check ~/cv-profile letter.txt -k "Kubernetes,Go" # claims your profile doesn't support
|
|
293
|
+
honest-cv letter build ~/cv-profile letter.txt --company Acme --role "Platform Engineer" -l en
|
|
294
|
+
honest-cv serve --profile ~/cv-profile # the MCP server, over stdio
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`verify` works on any PDF. Use `--text` to see exactly what a parser extracts. Its
|
|
298
|
+
`single_column` check also catches a common defect: a date aligned to the right, which parsers
|
|
299
|
+
split away from its role.
|
|
300
|
+
|
|
301
|
+
## MCP tools and prompts
|
|
302
|
+
|
|
303
|
+
| Name | What it does |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `init_profile` | Creates a profile folder with commented templates. |
|
|
306
|
+
| `get_inventory` | Returns your skills, grouped by level, with years and evidence. |
|
|
307
|
+
| `set_skill` | Adds or changes a skill. To raise its level it needs evidence and asks you to confirm. |
|
|
308
|
+
| `set_skills` | Adds or changes several skills at once. Upgrades are confirmed with one question that lists each change. |
|
|
309
|
+
| `checklist_list` | Lists the built-in checklists. |
|
|
310
|
+
| `checklist_new` | Merges built-in checklists into one file, prefilled from your inventory. |
|
|
311
|
+
| `checklist_apply` | Saves the skills marked in a checklist and returns the lines that still need evidence. |
|
|
312
|
+
| `add_bullet` | Adds an achievement to the pool. |
|
|
313
|
+
| `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. |
|
|
314
|
+
| `set_contact` | Changes contact details: name, email, phone, location, links. |
|
|
315
|
+
| `set_profile_details` | Replaces the certifications list, the courses list and the spoken-languages line. |
|
|
316
|
+
| `upsert_role` | Adds a role in date order, or changes fields of an existing one. |
|
|
317
|
+
| `upsert_education` | Adds or changes an education entry. |
|
|
318
|
+
| `upsert_publication` | Adds or changes a book, article or paper the person wrote. Each variant shows all of them, or the ones it lists. |
|
|
319
|
+
| `save_variant` | Adds or replaces a variant. Every reference is checked before saving. |
|
|
320
|
+
| `list_variants` | Lists the variants after inheritance, with their bullet texts and the bullets no variant uses. |
|
|
321
|
+
| `build_cv` | Renders a PDF and/or DOCX and verifies it. |
|
|
322
|
+
| `verify_pdf` | Runs the ATS checks on any PDF and returns its extracted text. |
|
|
323
|
+
| `score_job` | Measures the keyword coverage of each variant. The client extracts the keywords. |
|
|
324
|
+
| `gap_report` | Groups missing keywords by what you can honestly do about each one. |
|
|
325
|
+
| prompt `interview` | Fills your inventory and bullet pool, one question at a time. |
|
|
326
|
+
| `check_claims` | Checks any text against your profile: blocks X skills and familiarity sold as experience, flags what the profile doesn't show. |
|
|
327
|
+
| `build_letter` | Renders a cover letter to PDF and DOCX, one page, with the CV's ATS checks. Refuses while `check_claims` finds problems. |
|
|
328
|
+
| prompt `tailor_for_job` | Scores the variants, explains the gaps, adapts a variant and rebuilds. |
|
|
329
|
+
| prompt `cover_letter` | Drafts a letter for a job post from your bullets, checks its claims and builds it. |
|
|
330
|
+
| `import_profile` | Imports JSON Resume or a LinkedIn data export, adding only what is missing. For a LinkedIn PDF it returns the text. |
|
|
331
|
+
| `export_json_resume` | Exports a variant as JSON Resume; X skills never appear and F skills keep their label. |
|
|
332
|
+
| `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. |
|
|
333
|
+
| `linkedin_profile` | LinkedIn headline, About, position descriptions and skills (P and L only) from a variant, within LinkedIn's limits. |
|
|
334
|
+
| `list_applications` | Lists applications, latest first, with a count per status and the ones with no news for 14+ days. |
|
|
335
|
+
| prompt `import_linkedin_pdf` | Turns the PDF from LinkedIn's "Save to PDF" into a profile, section by section, with your approval. |
|
|
336
|
+
| prompt `linkedin_profile` | Polishes the LinkedIn texts of a variant without adding claims, checked with `check_claims`. |
|
|
337
|
+
|
|
338
|
+
## ATS guarantees
|
|
339
|
+
|
|
340
|
+
The template enforces these. `verify` checks them on every build, and the test suite runs in CI on
|
|
341
|
+
Linux, macOS and Windows:
|
|
342
|
+
|
|
343
|
+
- One column. No layout tables, images, icons, headers or footers.
|
|
344
|
+
- Ligatures and kerning off, no hyphenation, and terms like "CI/CD", URLs and emails never split
|
|
345
|
+
across lines.
|
|
346
|
+
- Reading order equals source order. Dates sit on the same line as their role.
|
|
347
|
+
- Text is extractable by both pypdf and pdfminer.six, and the two agree.
|
|
348
|
+
- The fonts (Carlito, metric-compatible with Calibri) are embedded and identical on every machine.
|
|
349
|
+
|
|
350
|
+
## Development
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
uv sync
|
|
354
|
+
uv run pytest
|
|
355
|
+
uv run honest-cv build examples/ada -l en -l es
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The repository's `.mcp.json` registers `honest-cv-dev` with the fictional profile, so Claude Code
|
|
359
|
+
in this folder can use your working copy. See [CONTRIBUTING.md](https://github.com/JesusCabreraReveles/honest-cv/blob/master/CONTRIBUTING.md).
|
|
360
|
+
|
|
361
|
+
## License
|
|
362
|
+
|
|
363
|
+
MIT. The bundled Carlito font is under the SIL Open Font License; see
|
|
364
|
+
`src/honest_cv/render/fonts/OFL.txt`.
|