cvx について
CVXは、YAML形式の履歴書データからデザイン版またはATS対応PDFを生成するローカルCLI・MCPサーバーです。履歴書の検証とローカルでのPDF出力を行いたい個人やコーディングエージェント向けです。
主な機能
- 01履歴書のYAMLファイルをひな形から作成
- 02内容を検証して修正点を提示
- 03デザイン版またはATS対応PDFを生成
- 04テーマとページレイアウトを選択
- 05PDFを生成せずページ構成を確認
- 06機械可読なCLI出力
活用シーン
- 01構造化した履歴書情報からPDFを作成
- 02出力前にYAMLの内容を確認
- 03ATS対応の単一カラム履歴書を準備
- 04エージェントにローカルで履歴書を編集・生成させる
MCP 対応
CVXはMCPクライアント向けにget_schema、init_cv、validate_cv、build_pdf、plan_layoutの5つのツールを提供します。サーバーは完全オフラインで動作し、APIキーは不要です。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
5掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| dir | string | いいえ | cv-content/を含むワークスペースフォルダーの絶対パス。デフォルトはサーバーの作業ディレクトリです。 |
| guides | array | いいえ | これらの同梱ガイドの全文を、`guides`配列にインラインで返します。省略すると(デフォルト)、一覧のみを返します。ai-guide.mdだけで約20 kBあるため、必要なときに要求し、毎回の呼び出しでは要求しないでください。 |
詳細
構造化された入力。プロフェッショナルな出力。Xの力をその手に。
CVXはプレーンなYAMLを、プロフェッショナルにデザインされたCVのPDFに変換します。コマンドひとつで、すべてローカルで実行でき、アカウントも不要です。データがマシンの外に出ることはありません。 使い方は2通りあります。YAMLを自分で編集するか、既存のCVをもとにAIアシスタントに作成してもらいます。CVXがファイルを検証し、修正箇所をアシスタントに正確に伝えます。
🤖 AIアシスタントの皆さまへ: ユーザーからCVXでCVを作成するよう依頼された場合は、AIガイドの「アシスタント向けのデフォルトフロー」に従ってください。リンクを開かない場合でも、次のルールは必ず守ってください。事実を決して捏造しないこと — すべての項目はユーザーの入力に基づいた真実でなければなりません。linkedin.comのURLは公開設定でも取得できません — 内容を推測せず、プロフィールの その他 → PDFとして保存 によるエクスポート、またはテキストの貼り付けを依頼してください。最初の返信で正方形の写真を依頼してください(生成できません。写真がなくてもCVは問題なく表示されます)。また、レンダラーとして使用するのはCVXのみです。別のPDF生成ツールで代用しないでください。
ターミナルがなくても大丈夫です。 これを任意のAIチャット(Claude、ChatGPT、Gemini、……)に貼り付けてください。
Create my CV with https://github.com/hrtips/cvx — open that page and follow its instructions for AI assistants.
Here is my LinkedIn profile: <your profile URL> (or attach your current CV and a photo instead).
ひな形から作成したサンプルCVの1ページ目 — --atsを使えばATS対応の1カラム版も作成できます。これらの画像を撮影してからページ分割が改善されているため、ビルド時には異なるページ分割になる場合があります。
2分でCVを作成
npx @hrtips/cvx init # scaffold cv-content/ with a complete example CV
npx @hrtips/cvx build # render it to a PDF
initを実行すると、完成済みですぐに使えるCVが作成されます。ブルース・ウェインのCVです。本当に。bruce-wayne.pdfを開けば、写真やサイドバー、実績などが揃った、デザイン済みの2ページのCVが表示されます。
さあ、自分用に編集しましょう。cv-content/フォルダーを開き、ファイルを1つずつ、自分の情報に置き換えてください。
cv-content/
personal.yaml ← start here: your name, title, contact details
summary.yaml ← the bullet points at the top of page 1
experience.yaml ← your work history (the bulk of the CV)
education.yaml ← degrees, institutions, years
competencies.yaml ← skill pills in the sidebar
achievements.yaml ← awards and recognitions
referees.yaml ← referees, or [] for "available upon request"
images/profile.jpg ← your photo (square, 400×400px or larger)
各ファイルを編集するたびにnpx @hrtips/cvx buildを再実行し、PDFが更新される様子を確認してください。ブルースの項目と自分の項目を並べて見ると、形式がわかりやすくなります。出力ファイルには自動的にあなたの名前が付きます(jane-doe.pdf)。
入力ミスがあったり、ファイルが正しいか不安だったりしますか? npx @hrtips/cvx validateを実行すると、すべてを一度に確認し、修正箇所を正確に教えてくれます。
cv-content/personal.yaml
⚠ unknown key "linkdin"
↳ did you mean "linkedin"?
ひな形から作成されるすべてのファイルには$schemaヘッダーも含まれているため、YAMLに対応したエディター(VS CodeとYAML拡張機能、JetBrainsなど)では、入力中にキーが自動補完され、間違いがあれば指摘されます。
求人ポータルから応募しますか? ATS対応版も生成できます。1カラム、色なしで、機械が読み取りやすい形式です。
npx @hrtips/cvx build --ats
CLI リファレンス
| コマンド | 内容 |
|---|---|
npx @hrtips/cvx init | サンプル CV を含む cv-content/ を生成します(既存のものは上書きしません) |
npx @hrtips/cvx validate | cv-content/ を検証します。すべての問題を一度に、ファイルとフィールドのパス、および修正方法とともに表示します |
npx @hrtips/cvx validate --strict | 警告(不明なキー)でも失敗します。エージェント/CI での使用を推奨します |
npx @hrtips/cvx build | cv-content/ を <your-name>.pdf にレンダリングします |
npx @hrtips/cvx build --ats | ATS 対応の単一列レイアウトにレンダリングします |
npx @hrtips/cvx list | 利用可能なテーマとレイアウトを表示します |
npx @hrtips/cvx --help / --version | ヘルプ/バージョン |
すべてのコマンドは、機械可読な出力(標準出力に 1 つの JSON オブジェクト、ログは標準エラー出力)を行う --json を受け付け、セマンティックな終了コードを使用します。0 は成功、2 は検証失敗、3 はレンダリング失敗、64 は使用方法のエラーです。init は便利な機能であり、必須ではありません。build は有効な YAML を含む任意の cv-content/ フォルダーをレンダリングします(組み込みのテーマとレイアウトには追加ファイルは不要です)。
コンテンツスキーマ: コンテンツファイルのバージョンは config.yaml の schemaVersion(現在は 1)で管理され、正式な JSON Schema に照らして検証されます。スキーマのメジャーバージョン内で新しいキーが追加されることがあります。また、効果がないと判明したキーは削除されることもあります。1.8.0 では page1ExperienceCount と page1SplitBullets が削除されました。この場合、ビルドは引き続き動作し、validate は削除されたキーを示します。一方、validate --strict は、現在は不明なキーとなったものをエラーとして扱います。削除を行ったリリースには、CHANGELOG にその旨が記載されます。
各ファイルに記述する内容
以下は、生成されたサンプルからの抜粋です。一度ビルドすれば、それぞれの内容がページのどこに配置されるかを正確に確認できます。
personal.yaml — ヘッダーと連絡先ブロック:
name: Bruce Wayne
title: Founder & Field Commander – Gotham Operations
company: Wayne Enterprises
phone: "+1 (201) 555-2283"
phoneHref: "tel:+12015552283"
email: [email protected]
linkedin: linkedin.com/in/brucewayne
linkedinHref: "https://www.linkedin.com/in/brucewayne"
experience.yaml — 職務ごとに 1 件を記述します。progression(任意)を指定すると、その職務項目内に役職の変遷が表示されます:
- role: Founder & Field Commander – Gotham Operations
company: The Batman
period: 2005 – Present
description: Self-directed vigilante operation safeguarding Gotham City through deterrence, investigation, and crisis response.
progression:
- title: Commander, Batman Incorporated
period: 2011 – Present
- title: Solo Operative, The Dark Knight
period: 2005 – 2008
bullets:
- Established and scaled a citywide security operation from a solo initiative to a franchised network (Batman Incorporated).
- Recruited, trained, and led a high-performing field team including Robin, Nightwing, and Batgirl.
- Reduced organised-crime activity in Gotham by an estimated 60% through data-driven surveillance and rapid incident response.
summary.yaml — 1 ページ目上部の箇条書きリスト:
- "Strategic operations leader with 20+ years' experience, progressing from solo field operative to Field Commander of a citywide security network."
- "Co-founded the Justice League as a global response coalition, serving as chief strategist and contingency planner for existential-scale threats."
education.yaml
- degree: "Applied Sciences & Criminology (self-directed)"
institution: League of Shadows
period: 1998 – 2004
- degree: BSc, Criminology & Chemistry
institution: Gotham University
period: 1994 – 1998
competencies.yaml — サイドバーにスキルのピルとして表示されます:
- Strategic Planning
- Criminal Investigation
- Crisis Response
- Surveillance & Intelligence
achievements.yaml
- year: Gotham's Most Influential Citizen
text: "— 2024, Gotham Gazette"
- year: Key to the City
text: "— Office of the Mayor, Gotham City"
referees.yaml(「ご要望に応じて提供可能」と表示するには [] を使用します):
- name: Diana Prince
title: Founding Member, Justice League
company: Themysciran Embassy
email: [email protected]
phone: "+1 (202) 555-0177"
不要なものは削除してください。空のファイル(または [])にすると、そのセクションは CV から削除されます。cv-content/ に追加した新しい .yaml ファイルは、コンテンツキーとして自動的に検出されます。
すべてのファイルのフィールドごとの完全なスキーマは、docs/cv-schema.md にあります。
AI に YAML を作成してもらう
形式は LLM で扱いやすいよう意図的に設計されており、スキーマは機械向けに公開されています(llms.txt、docs/cv-schema.md)。**AI ガイド**には、あらゆる方法で使えるコピー&ペースト用のプロンプトがあります。要点は次のとおりです。
コーディングエージェント(Claude Code、Cursor など)— 最も手軽な方法です。npx @hrtips/cvx init を実行し、サンプルの内容を自分の情報に置き換えてビルドするようエージェントに依頼します。生成された cv-content/README.md にスキーマが記載されているため、エージェントが編集し、npx @hrtips/cvx build を実行して、自分でエラーを修正します。
チャットアシスタント(Claude、ChatGPT など)— 既存の CV または LinkedIn プロフィールのテキストと、以下のプロンプトを貼り付けます。
https://raw.githubusercontent.com/hrtips/cvx/main/docs/cv-schema.md にある CVX コンテンツスキーマを読み、以下の私の CV を CVX の cv-content/ YAML ファイルに変換してください。各ファイルは、ファイル名をタイトルにした個別のフェンス付きコードブロックで出力してください。入力にある事実をすべて忠実に保ち、何も作り出さないでください。
生成されたファイルを cv-content/ に保存し、写真を追加して、npx @hrtips/cvx build を実行します。アシスタントがウェブにアクセスできない場合は、自己完結型プロンプトを使用してください。
エージェントに組み込む(MCP)
CVX には MCP サーバーが付属しており、あらゆる MCP クライアント(Claude Desktop、Claude Code、Cursor、VS Code、…)から、get_schema、init_cv、validate_cv、build_pdf、plan_layout の 5 つのツールを使って、作成から出力までの一連の処理を実行できます。plan_layout は、PDF を書き出さずに履歴書のページ割りを報告するドライランです。ページ数、ページごとのカラムの埋まり具合、各項目がどこに配置されたかを確認できます。API キーは不要で、完全にオフラインで動作します。
CVX は YAML の内容を 100% 描画し、ページに収めるためにテキストを省略したり、切り取ったり、隠したりすることはありません。そのため、CVX を操作するアシスタントが、ページ数に合わせるためにセクションをこっそり削ることもできません。履歴書が希望より長くなる場合は、トレードオフを提示するので、何を含めるかは自分で決められます。
npx @hrtips/cvx mcp init --client claude # Claude Code (.mcp.json, project)
npx @hrtips/cvx mcp init --client claude-desktop # Claude Desktop (global config)
npx @hrtips/cvx mcp init --client cursor # Cursor (.cursor/mcp.json)
npx @hrtips/cvx mcp init --client vscode # VS Code (.vscode/mcp.json)
次にクライアントを再起動して、履歴書の作成を依頼してください。クライアントはスキーマを取得し、ひな形を作成して詳細を入力し、編集のたびに検証してから PDF を出力します。設定ファイルの書き込みでは既存の内容にマージするため、ほかのサーバーを上書きすることはありません。同じ手順をスキル対応エージェントで使える、すぐに利用可能な Agent Skill もあります。
ChatGPT GPT に組み込む
ChatGPT のサンドボックスには Node のランタイムがありますが、通常 npm レジストリには接続できないため、npx は動作しません。そのため CVX には、スキーマ、テンプレート、フォントなどすべてを含む 自己完結型の単一ファイル も用意されています。各リリースに cvx.bundle.min.js として添付されており、Node 20+ 以外は何も必要ありません。インストールも、node_modules も、追加のダウンロードも不要です。
ほとんどの ChatGPT サンドボックスではファイルを自動で取得できるため、アップロードは不要です。Route D のプロンプトには 4 つのセットアップコマンドがそのまま記載されています。これは重要です。アシスタントに任せると、まず npx を試してしまい、やり取りを無駄にするからです。ダウンロードがブロックされる場合は、0.92 MB の zip をダウンロードしてアップロードしてください。それ以降の手順は同じです。
GPT は、チャットアシスタントには通常できないことを実行します。PDF を出力し、開いてページを確認してから、実際に表示される前にレイアウトを修正します。
写真
写真を cv-content/images/ に profile.<ext> として配置してください。jpg、jpeg、png、webp は自動検出されます(複数ある場合はこの順番で優先されます)。正方形にトリミングし、サイズは 400×400px 以上にしてください。
テーマ、レイアウト、ページの流れ
見た目に関する設定はすべて cv-content/config.yaml で管理します。
theme: teal # teal | coral | mono
layout: two-column # two-column | single-column
値を変更して npx @hrtips/cvx build を再実行すれば完了です。
テーマでは色とスタイルを設定します。
| テーマ | アクセントカラー | 説明 |
|---|---|---|
teal | #1a6070 | プロフェッショナルなティール(デフォルト) |
coral | #c0534a | 温かみのあるコーラルレッド |
mono | #000000 | ATS に最適化された白黒 |
レイアウトではページ構成を設定します。
| レイアウト | 構成 | 説明 |
|---|---|---|
two-column | サイドバー+メインカラム | 写真、プロフィール欄、実績を含むデザイン重視の履歴書 |
single-column | 全幅 | ATS に適しており、サイドバーや装飾要素はありません |
ページ割り — 職歴の項目はページからはみ出さないよう、自動的にページ間へ振り分けられます(貪欲法によるビンパッキング)。残りのスペースに収まりきらない項目は、箇条書きの区切りで分割され、次のページに続きます。ページ割りの設定項目はありません。レイアウトは内容に応じて決まります。(以前の page1ExperienceCount / page1SplitBullets キーは削除されました。測定した結果、ページ数を減らす効果はなく、強制すると番号のない余分なページに内容が押し出されていました。これらのキーが残っている設定には、そのことを明記した検証メッセージが表示されます。)
スクリプトのサポート
CV のレンダリングは英語/西ヨーロッパ言語のラテン文字のみ対応しています。 CVX には Lato が含まれており、フォールバックフォントは登録されていません。そのため、Lato がカバーしていない文字体系、つまりキリル文字、ギリシャ文字、ベトナム語、トルコ語の ş/ğ、チェコ語/ルーマニア語のダイアクリティカルマーク付き文字、そしてラテン文字以外のすべての文字体系(デーヴァナーガリー文字、タミル文字、シンハラ文字、CJK、アラビア文字など)は、表示されません。コンテンツに同梱フォントで描画できない文字が含まれている場合、cvx validate と cvx build は目立つ警告を表示するため、問題が見過ごされずに分かります。
これは見落としではなく、意図的な対応範囲の決定です。これらの文字体系用のフォールバックフォントを同梱すると、パッケージサイズの予算を何倍も超えてしまいます。(プロジェクトのウェブサイトは多言語対応ですが、レンダラーはそうではありません。両者は独立しています。)
カスタムレイアウト
独自のページ構成を定義できます。.yaml ファイルを cv-content/layouts/ に配置し、ファイル名で参照します。
# cv-content/layouts/compact.yaml
template: two-column
pages:
first:
sidebar:
- identity-photo
- contact
main:
- summary
- spacer: 27
- experience
continuation:
sidebar:
- identity-compact
- education
- competencies
- achievements
main:
- experience:continued
last:
sidebar:
- identity-compact
- referees
main:
- experience:continued
次に、config.yaml で layout: compact を設定します。
サイドバーの 3 つのリストは、ページごとの割り当てではなく、ひと続きの順序付きフローです。
first.sidebar + continuation.sidebar + last.sidebar はこの順序で連結され、CVX はその結果を測定して、各セクションがどのページに配置されるかを決定します。したがって、last.sidebar: [referees] は「推薦者情報がサイドバーの最後に来る」という意味であり、「推薦者情報が最終ページに表示される」という意味ではありません。各項目の順序を表すためにバケットを使い、ページ割りは測定に任せてください。(identity-photo/identity-compact は例外で、サイドバーに詰め込まれるのではなく、各ページのサイドバーの先頭に挿入されます。)メインのリストは引き続きページ種別ごとです。first.main は 1 ページ目、last.main は最終ページ、continuation.main はその間のページに配置されます。
使用できるセクションキー:
| キー | 表示内容 |
|---|---|
identity-photo | 氏名、肩書き、会社名+プロフィール写真(サイドバー) |
identity-compact | 氏名、肩書き、会社名(写真なし、サイドバー) |
contact | アイコン付きの電話番号、メールアドレス、LinkedIn、所在地(サイドバー) |
achievements | 年+説明のリスト(サイドバー) |
education | 学位、教育機関、期間(サイドバー) |
competencies | ピル形式のスキルタグ(サイドバー) |
referees | 推薦者の連絡先(サイドバー) |
summary | 箇条書きリスト(メイン列) |
experience | 1 ページ目の職務経験項目(メイン列) |
experience:continued | 続きの職務経験項目(メイン列) |
header-ats | 全幅の氏名/肩書き/連絡先ヘッダー(単一列) |
spacer: N | N ポイントの垂直スペーサー |
ATS と AI パーサー向けキーワード
両方の PDF には、標準の Keywords メタデータフィールドにキーワードリストが埋め込まれています。これは、一部の応募者追跡システム(ATS)や AI CV パーサーが読み取るフィールドです。キーワードはメタデータに保存され、ページ上の隠しテキストとしては配置されません。
現実的な注意点: 主流の ATS の多くは、CV の本文から抽出したテキストに基づいて順位付けしており、PDF の
Keywords/XMP フィールドへの対応は一貫していません。キーワードを充実させた本文を補う、可能な範囲での追加策として扱ってください。代替策ではなく、それだけで確実に順位を上げられる方法でもありません。すべてのキーワードを事実に即したものにしてください。誤った用語や無関係な用語を詰め込むと、メタデータと本文の不一致が生じ、CV が自動的に却下される原因になります。
キーワードは 2 つのソースから取得され、統合・重複排除されます(本文から抽出した用語が先になります)。
competencies.yamlと職務名から自動抽出されます(会社名はシグナルが弱いため、意図的に除外されています)。cv-content/keywords.yamlで選定します。フラットなリスト、または見出しの下にグループ化した形式を使用できます。
# cv-content/keywords.yaml
- Operations Management
- Risk Management
# …or grouped:
Leadership: [Executive Leadership, Team Building]
config.yaml で設定します。
atsKeywords:
enabled: true # master switch (default: true)
autoDerive: true # also derive from competencies + job titles (default: true)
max: 40 # optional cap; body-derived terms are kept first (default: all)
開発者向け
以下はすべて、CVX 自体の開発(カスタムテーマ、レンダリングパイプライン、コントリビューション)に関する内容です。CV を作成するだけなら必要ありません。
クローンから作業する
git clone [email protected]:hrtips/cvx.git
cd cvx
npm install
npm run dev # live browser preview at http://localhost:5173
npm run pdf # generate PDF (same pipeline as `cvx build`)
npm run pdf:ats # generate the ATS variant
npm test # unit tests
npm run build:lib # build the publishable lib/ (what the CLI runs)
リポジトリの cv-content/ には同じ Bruce Wayne のサンプルが含まれているため、クローンした状態ですぐにビルドできます。写真の切り抜きを補助するツールも付属しています。python3 scripts/crop-profile.py path/to/photo.jpg。
カスタムテーマ
テーマはパッケージに同梱されるため、現時点でカスタムテーマを使用するには、リポジトリをクローンして作業する必要があります。
npxCLI で利用できるのは、組み込みの 3 つのテーマです。
src/pdf/themes/ に .js ファイルを追加すると、自動検出されます。登録は不要です。
// src/pdf/themes/navy.js
import { tealTheme } from './teal.js'
export const navyTheme = {
...tealTheme,
name: 'navy',
palette: {
...tealTheme.palette,
accent: '#1e3a5f',
sidebarBg: '#eef1f5',
tagBg: '#d0d8e8',
tagText: '#1e3a5f',
divider: '#b8c4d4',
},
}
config.yaml で theme: navy を設定します。テーマオブジェクトには、上書きできる名前空間が 5 つあります。
| 名前空間 | 制御対象 |
|---|---|
palette | アクセント、背景、テキスト、タグ、区切り線、セマンティックな不透明度カラーなど、すべての色 |
typography | 各要素のフォントサイズ、太さ、文字間隔、行の高さ |
spacing | すべてのコンポーネントで使用する間隔、マージン、パディングの値 |
chrome | 装飾の寸法 — 角丸、区切り線の幅、写真のサイズ、コーナーバッジ |
geometry | ページ寸法、列の比率、パディングオブジェクト |
自動検出
登録ではなく規約に従います。所定のフォルダーにファイルを追加すると、自動的に読み込まれます。
| 対象 | 追加先 | 検出方法 |
|---|---|---|
| コンテンツ | cv-content/*.yaml | config.yaml 以外の .yaml ファイルはすべて、ファイル名と一致するコンテンツキーになります |
| テーマ | src/pdf/themes/*.js | name プロパティを持つオブジェクトをエクスポートする .js ファイルがすべて対象です |
| レイアウト | cv-content/layouts/*.yaml | template と pages の構造を持つ .yaml ファイルがすべて対象です |
| プロフィール写真 | cv-content/images/profile.* | .jpg、.jpeg、.png、.webp の最初の一致 |
新しいコンテンツセクション全体(例:出版物)を追加するには、cv-content/publications.yaml を作成し(content.publications として自動的に利用可能になります)、src/pdf/sections/ にセクションコンポーネントを作成して、registry.js に登録し、レイアウトから参照します。
アーキテクチャ
個別に差し替え可能な 3 つの関心事:
Content (YAML) × Theme (JS) × Layout (YAML)
↓ ↓ ↓
what to say how it looks where it goes
レンダリングパイプライン:
config.yaml → resolves theme + layout
↓
cv-content/*.yaml → auto-loaded into data bag
↓
layout.js → packs experience entries across pages (using theme metrics)
↓
CVDocument → picks template (TwoColumn or SingleColumn)
↓
template → renders slots from layout config via section registry
↓
sections → read theme from React context, render content
↓
@react-pdf/renderer → PDF buffer → file
プロジェクト構成
cv-content/ ← content (the repo carries the example CV)
*.yaml ← auto-discovered content files
config.yaml ← theme, layout, pagination
layouts/ ← auto-discovered layout definitions
images/profile.<ext> ← photo (jpg/jpeg/png/webp)
src/pdf/ ← framework
CVDocument.jsx ← unified config-driven document
ATSDocument.jsx ← standalone ATS document
ThemeContext.jsx ← React context + useStyles hook
render.js ← shared render pipeline (CLI + scripts)
layout.js ← theme-aware page-packing + sidebar resolution
keywords.js ← ATS/AI-parser keyword metadata
reproducible.js ← SOURCE_DATE_EPOCH support (see below)
profilePhoto.js ← shared profile-image extension precedence
loadContent.js ← auto-discovers cv-content/*.yaml
loadLayout.js ← normalizes layout YAML → slot config
fonts.js ← Lato font registration
*.test.js ← Vitest unit tests (co-located)
themes/ ← auto-discovered themes (teal, coral, mono)
templates/ ← page shells (TwoColumn, SingleColumn)
sections/ ← content sections + registry
components/ ← shared leaf components
scripts/
export-pdf.js ← npm run pdf
export-pdf-ats.js ← npm run pdf:ats
build-lib.js ← npm run build:lib (publishing build)
crop-profile.py ← photo crop helper
bin/cvx.js ← npx CLI (init / build)
template/cv-content/ ← starter content scaffolded by `cvx init`
lib/ ← generated: published transform of src/pdf (gitignored)
テスト
npm test
ユニットテストでは、キーワードの構築、ページの割り当て、サイドバーの解決、再現性ヘルパー、プロフィール写真の選択処理といった、純粋なロジックモジュールを対象とします。テストは対象コードの隣(src/pdf/*.test.js)と、横断的なチェック用の test/ にあります。CI では、Linux と macOS で Node 20/22/24(さらに Windows では Node 22)を使ってテストスイートを実行した後、tarball を作成し、インストール済み CLI のエンドツーエンドテストを実施します。これには、バイト単位で同一であることを確認する再現性ゲートも含まれます。
品質ゲート
このビルドは意図的に厳格です。以下のすべてのゲートを警告 ゼロ件 で通過しない限り、変更は反映されません。npm run check(lint + 型チェック + カバレッジ + デッドコード)ですべてをローカルで実行できます。CI では quality ジョブと security ジョブでこれらを強制します。
| ゲート | コマンド | 検証内容 |
|---|---|---|
| Lint + フォーマット | npm run lint | Oxlint(高速な正確性チェック/suspicious。rules-of-hooks、no-focused-tests を含む)と Biome(フォーマット、インポート、より詳細な lint)— 警告ゼロ |
| 型 | npm run typecheck | JS/JSX ソース全体に対して、checkJs と完全な strict を有効にした tsc --noEmit(型は JSDoc と JSON スキーマから生成された src/pdf/types.d.ts で指定) |
| カバレッジ | npm run test:cov | Vitest v8。ファイルごとに行/関数/ステートメントのカバレッジ ≥ 90%、分岐カバレッジ ≥ 85% — 全体平均なし、ファイルごとの免除なし |
| デッドコード | npm run knip | 未使用のファイル、エクスポート、依存関係がないこと |
| パッケージ | npm run publint · npm run attw | publint によるパッケージ検証 + arethetypeswrong による解決検証 |
| サプライチェーン | security CI job | actionlint · zizmor(SHA で固定したアクション、最小権限)· gitleaks · osv-scanner |
フォーマット/lint の自動修正:npm run lint:fix。GitHub Actions はコミット SHA で固定され、Dependabot によって最新の状態に保たれます。
再現可能なビルド
SOURCE_DATE_EPOCH(Unix エポックからの秒数)を設定すると、PDF の出力が実行ごとにバイト単位で同一になります。CI チェックや、コンテンツの変更だけが差分であることの検証に便利です。
SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) npx @hrtips/cvx build # or npm run pdf
これにより、PDF の CreationDate(およびそれに伴うトレーラーファイル ID)、フォントサブセット名、オブジェクトの書き込み順序が固定されます。これらは、設定しない場合は実行ごとに変わります。設定を解除すると、ビルドは通常どおりに動作し、現在の時刻が記録されます。
バイト単位で同一の出力が保証されるのは、同じプラットフォームと Node バージョンを使用する場合です。異なる OS または Node のメジャーバージョンでビルドした場合、見た目は同じですが、バイト単位では同一になりません(フォントサブセットの埋め込み順序はプラットフォームによって異なり、zlib の出力は Node のバージョンによって変わります)。
技術スタック
- @react-pdf/renderer — React を PDF にレンダリングします(ヘッドレスブラウザーは不要)
- Vite + React — ブラウザーでのライブプレビュー
- js-yaml — YAML の解析(
@rollup/plugin-yamlに合わせて 4.x に固定) - esbuild — 公開用に
lib/を変換のみでビルドします - tsx — リポジトリのエクスポートスクリプトを実行します
- Vitest — 単体テスト
- Lato — 埋め込みフォント(Light 300、Regular 400、Bold 700)
ライセンス
Apache-2.0 © ramith.
同梱の Lato フォントは、SIL Open Font License 1.1 に基づき、別途ライセンスされています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。