
Cvx
io.github.hrtips由 GitHub 帳號 hrtips 發布v1.8.1更新於 Oct 24, 2026
Create, validate, and render CV PDFs from plain YAML — fully local, no accounts.
概覽
本機 MCP 伺服器,讓助理用純 YAML 建立、驗證並渲染履歷,產出設計好的 PDF,全程離線。
- 可以做什麼
- 取得履歷內容的結構定義,讓助理了解 YAML 格式與欄位。初始化一個含完整範例履歷的 cv-content 資料夾。驗證 YAML 內容檔案,依檔案與欄位路徑列出所有問題。以試跑方式規劃版面,回報頁數與各區塊落點,不產生 PDF。將內容渲染為 PDF,也可產出適合 ATS 的單欄版本。
- 適用情境
- 適合希望由 AI 助理把現有履歷整理成結構化 YAML,並在本機產出成品設計 PDF(含供招募系統使用的 ATS 版本)的情境。
- 執行需求
- 透過 npm 套件 @hrtips/cvx 以 npx 在本機執行,需要 Node.js;README 提到自包含版本需 Node 20 以上。未宣告任何帳號、API 金鑰或環境變數,可離線使用。
安裝
README
Structured input. Professional output. To the power of X.
[CI] [npm version] [npm downloads] [install size] [license]
CVX turns plain YAML into a professionally designed CV PDF — one command, fully local, no accounts; your data never leaves your machine. Use it two ways: edit the YAML yourself, or have any AI assistant write it for you from your existing CV — CVX validates the files and tells the assistant exactly what to fix.
🤖 AI assistants: if a user asked you to create their CV with CVX, follow the default flow in the AI guide (section "Default flow (for assistants)"). Non-negotiables even if you skip the link: never invent facts — every entry must be truthful to the user's input; linkedin.com URLs are unfetchable even when public — don't infer, ask for the profile's More → Save to PDF export or pasted text instead; ask for a square photo in your first reply (it can't be generated; the CV renders fine without one); and CVX is the only renderer — never substitute another PDF generator.
No terminal? No problem. Paste this into any AI chat (Claude, ChatGPT, Gemini, …):
[Designed two-column CV produced by CVX — teal theme, photo sidebar, achievements]
Page 1 of the scaffolded example CV — plus an ATS-safe single-column variant via --ats. Pagination has improved since these were captured; your build may split pages differently.
Create your CV in two minutes
init gives you a finished, working CV — Bruce Wayne's, and yes, really. Open bruce-wayne.pdf and you're looking at a designed two-page CV: photo, sidebar, achievements, the lot.
Now make it yours. Open the cv-content/ folder, and replace Bruce's details with your own, one file at a time:
Re-run npx @hrtips/cvx build after each file and watch the PDF update — seeing Bruce's entry next to yours makes the format self-explanatory. The output file is named after you automatically (jane-doe.pdf).
Made a typo or unsure a file is right? npx @hrtips/cvx validate checks everything at once and tells you exactly what to fix:
Every scaffolded file also carries a $schema header, so editors with YAML support (VS Code + the YAML extension, JetBrains, …) autocomplete keys and flag mistakes as you type.
Applying through a job portal? Generate the ATS-safe variant too — single column, no colours, machine-friendly:
CLI reference
All commands accept --json for machine-readable output (one JSON object on stdout, logs on stderr) and use semantic exit codes: 0 ok, 2 validation failed, 3 render failed, 64 usage error. init is a convenience, not a prerequisite — build renders any cv-content/ folder with valid YAML (built-in themes and layouts need no extra files).
Content schema: content files are versioned by schemaVersion in config.yaml (currently 1) and validated against the canonical JSON Schema. New keys may appear within a schema major. Keys can also be removed when they are measured to do nothing — page1ExperienceCount and page1SplitBullets were, in 1.8.0 — in which case builds keep working and validate names the removal, while validate --strict treats the now-unknown key as an error. The CHANGELOG says so at the release that does it.
What goes in each file
These are excerpts from the scaffolded example — build it once and you can see exactly where each snippet lands on the page.
personal.yaml — the header and contact block:
experience.yaml — one entry per role; progression (optional) renders a title history inside the entry:
summary.yaml — the bullet list at the top of page 1:
education.yaml
competencies.yaml — rendered as skill pills in the sidebar:
achievements.yaml
referees.yaml (use [] to print "available upon request"):
Delete what you don't need — an empty file (or []) simply drops that section from the CV. Any new .yaml file you drop into cv-content/ is auto-discovered as a content key.
The complete field-by-field schema for every file lives in docs/cv-schema.md.
Let an AI write the YAML for you
The formats are deliberately LLM-friendly, and the schema is published for machines (llms.txt, docs/cv-schema.md). The AI guide has copy-paste prompts for every route; the short version:
Coding agent (Claude Code, Cursor, …) — lowest friction: run npx @hrtips/cvx init, then ask the agent to replace the example content with your details and build. The scaffolded cv-content/README.md documents the schema, so the agent edits, runs npx @hrtips/cvx build, and fixes errors itself.
Chat assistant (Claude, ChatGPT, …) — paste your existing CV or LinkedIn profile text along with this prompt:
Read the CVX content schema at https://raw.githubusercontent.com/hrtips/cvx/main/docs/cv-schema.md then convert my CV below into CVX cv-content/ YAML files. Output each file in its own fenced code block titled with the filename. Keep every fact truthful to my input — don't invent anything.
Save the generated files into cv-content/, drop in your photo, run npx @hrtips/cvx build. No web access in your assistant? Use the self-contained prompt.
Plug it into your agent (MCP)
CVX ships an MCP server — any MCP client (Claude Desktop, Claude Code, Cursor, VS Code, …) can drive the whole loop with five tools: get_schema, init_cv, validate_cv, build_pdf, and plan_layout (a dry run that reports how the CV paginates — page count, per-page column fills, what landed where — without writing a PDF). No API keys, fully offline.
CVX renders 100% of your YAML and never drops, clips, or hides text to fit a page — so an assistant driving it can't quietly cut a section to hit a page count either. If the CV runs longer than you want, it surfaces the trade-off and you decide what goes.
Then restart the client and ask it to make your CV — it fetches the schema, scaffolds, fills in your details, validates after every edit, and renders the PDF. The config writer merges into existing files; it never clobbers other servers. There's also a ready-made Agent Skill with the same loop for skill-capable agents.
Build it into a ChatGPT GPT
ChatGPT's sandbox has a Node runtime but usually cannot reach the npm registry, so npx does not work there. CVX therefore also ships as one self-contained file — schema, template, fonts and all — attached to every release as cvx.bundle.min.js. It needs nothing but Node 20+: no install, no node_modules, no further downloads.
In most ChatGPT sandboxes it can fetch the file itself, so you upload nothing — the Route D prompt gives it the four setup commands verbatim, which matters because an assistant left to work it out will try npx first and waste your turn. If the download is blocked, download the 0.92 MB zip and upload it instead; everything after that is identical.
The GPT does what a chat assistant otherwise cannot: it renders the PDF, opens it and looks at the pages, then fixes the layout before you ever see it.
Your photo
Drop it into cv-content/images/ as profile.<ext> — jpg, jpeg, png, or webp are auto-detected (that order wins if several exist). Square crop, at least 400×400px.
Themes, layouts, and page flow
Everything visual is controlled by cv-content/config.yaml:
Change a value, re-run npx @hrtips/cvx build, done.
Themes control colour and styling:
Layouts control page structure:
Pagination — experience entries are distributed across pages automatically (greedy bin-packing), never overflowing a page, and an entry too tall for the remaining room is split at a bullet boundary and continued overleaf. There are no pagination settings: the layout follows the content. (The old page1ExperienceCount / page1SplitBullets keys were removed — measured, they never reduced the page count, and forcing them pushed content onto an unnumbered extra sheet. A config that still has them gets a validation message saying exactly that.)
Script support
CV rendering is English/Western-European Latin only. CVX bundles Lato and registers no fallback font, so scripts Lato doesn't cover — Cyrillic, Greek, Vietnamese, Turkish ş/ğ, Czech/Romanian diacritics, and all non-Latin scripts (Devanagari, Tamil, Sinhala, CJK, Arabic, …) — render invisibly. cvx validate and cvx build warn loudly when your content contains characters the bundled font cannot draw, so this fails visibly rather than silently.
This is a deliberate scope decision, not an oversight: shipping fallback fonts for those scripts would blow the package-size budget many times over. (The project website is multilingual; the renderer is not — the two are independent.)
Custom layouts
You can define your own page structure — drop a .yaml file into cv-content/layouts/ and reference it by filename:
Then set layout: compact in config.yaml.
The sidebar's three lists are one ordered flow, not three page assignments.
first.sidebar + continuation.sidebar + last.sidebar are concatenated in
that order, and CVX measures the result to decide which page each section lands
on. last.sidebar: [referees] therefore means "referees comes last in the
sidebar", not "referees renders on the last page". Use the buckets to express
order; let pagination be measured. (identity-photo/identity-compact are
the exception — they are injected at the top of every page's sidebar rather than
packed.) The main lists remain per-page-kind: first.main on page 1,
last.main on the final page, continuation.main in between.
Available section keys:
ATS & AI-parser keywords
Both PDFs embed a keyword list into the standard Keywords metadata field — the field some applicant tracking systems (ATS) and AI CV parsers read. Keywords live in metadata, not as hidden text on the page.
Reality check: most mainstream ATS rank on text extracted from the CV body, and support for the PDF
Keywords/XMP field is inconsistent. Treat this as a best-effort supplement to a keyword-rich body — not a substitute, and not a reliable ranking lever on its own. Keep every keyword truthful; stuffing false or irrelevant terms causes a metadata/body mismatch that gets a CV auto-rejected.
Keywords come from two sources, merged and de-duplicated (body-derived terms first):
- Auto-derived from your
competencies.yamland job titles (company names are deliberately excluded as low-signal). - Curated in
cv-content/keywords.yaml— a flat list, or grouped under headings:
Configure in config.yaml:
For developers
Everything below is about hacking on CVX itself — custom themes, the rendering pipeline, and contributing. You don't need any of it to create a CV.
Working from a clone
The repo's cv-content/ carries the same Bruce Wayne example, so a clone builds out of the box. A photo crop helper is included: python3 scripts/crop-profile.py path/to/photo.jpg.
Custom themes
Themes ship inside the package, so custom themes currently require working from a clone — the
npxCLI offers the three built-ins.
Drop a .js file in src/pdf/themes/ — it's auto-discovered, no registration needed:
Set theme: navy in config.yaml. The theme object has five namespaces you can override:
Auto-discovery
Convention over registration — drop a file in the right folder and it's picked up:
To add a whole new content section (e.g. publications): create cv-content/publications.yaml (auto-available as content.publications), build a section component in src/pdf/sections/, register it in registry.js, then reference it from a layout.
Architecture
Three concerns, independently swappable:
The rendering pipeline:
Project structure
Testing
Unit tests cover the pure logic modules — keyword building, page packing, sidebar resolution, reproducibility helpers, and the profile-photo picker. Tests live next to the code they cover (src/pdf/*.test.js) plus test/ for cross-cutting checks. CI runs the suite on Linux and macOS across Node 20/22/24 (plus Windows on Node 22), then packs the tarball and exercises the installed CLI end-to-end, including a byte-identical reproducibility gate.
Quality gates
The build is deliberately hostile — a change lands only if it clears every gate below with zero warnings. Run them all locally with npm run check (lint + types + coverage + dead-code); CI enforces them in the quality and security jobs.
Formatting/lint autofix: npm run lint:fix. GitHub Actions are pinned to commit SHAs and kept current by Dependabot.
Reproducible builds
Set SOURCE_DATE_EPOCH (seconds since the Unix epoch) to make PDF output byte-identical run after run — useful for CI checks and for verifying that a content change is the only thing that changed:
This pins the PDF's CreationDate (and with it the trailer file ID), the font-subset names, and the object write order — the things that otherwise vary per run. Unset, builds behave normally and stamp the current time.
Byte-identical output is guaranteed for the same platform and Node version. Builds from different OSes or Node majors are visually identical but not byte-identical (font subsets embed in a platform-dependent order, and zlib output varies across Node versions).
Tech stack
- @react-pdf/renderer — renders React to PDF (no headless browser)
- Vite + React — live browser preview
- js-yaml — YAML parsing (pinned to 4.x to match
@rollup/plugin-yaml) - esbuild — transform-only build of
lib/for publishing - tsx — runs the repo export scripts
- Vitest — unit tests
- Lato — embedded font (Light 300, Regular 400, Bold 700)
License
Apache-2.0 © ramith.
The bundled Lato fonts are licensed separately under the SIL Open Font License 1.1.
來源:README.md,提交 59d4d23
工具
0版本歷史
1- v1.8.1最新Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分