This document is self-contained: with only this file and a person's CV facts, you can generate a complete, valid cv-content/ folder for CVX. It is written for both humans and AI assistants.
npx @hrtips/cvx initscaffoldscv-content/with a complete example CV (Bruce Wayne's).npx @hrtips/cvx validatechecks every file at once and reports exact errors with suggested fixes (--strictalso fails on unknown keys,--jsonfor machine-readable output; exit0ok /2problems found). Run it after every edit.npx @hrtips/cvx buildrenderscv-content/to a PDF in the current directory.npx @hrtips/cvx build --atsrenders an ATS-safe single-column variant instead.- Every content file is validated against the canonical JSON Schema; the scaffolded files carry
$schemaheaders for editor autocomplete. - The output PDF is named from
personal.yaml'sname: lowercased, spaces → hyphens (Bruce Wayne→bruce-wayne.pdf; the ATS variant appends-ats). - Every
.yamlfile incv-content/is auto-discovered by filename. A missing file, an empty file, or[]simply drops that section from the CV — no error. (Required in practice:personal.yaml,summary.yaml,experience.yaml—validatechecks this.) initis a convenience, not a prerequisite —buildrenders anycv-content/folder with valid YAML; built-in themes and layouts need no extra files. A missing photo renders fine (the sidebar simply omits it).- All rendering is local; no network calls, no accounts.
- Quote any string containing a colon (
"Director: Operations") or starting with a special character. - Periods/date ranges are free text — the convention in the example content is an en-dash:
2005 – Present,Jan 2022 – Dec 2023. - Do not invent facts. Every entry must be truthful to the source CV; this especially matters for
keywords.yaml(ATS parsers cross-check keywords against body text).
Identity header + contact block. Only the keys listed here render — arbitrary extra keys are ignored.
| Key | Type | Required | Renders |
|---|---|---|---|
name |
string | yes | Header name; also derives the output filename |
title |
string | recommended | Job title line under the name |
company |
string | optional | Company line under the title |
phone |
string | optional | Contact row (phone icon) |
phoneHref |
string | optional | Makes the phone row clickable, e.g. "tel:+12015552283" |
email |
string | optional | Contact row (envelope icon); clickable automatically via mailto: |
linkedin |
string | optional | Contact row (LinkedIn icon), display text e.g. linkedin.com/in/brucewayne |
linkedinHref |
string | optional | Makes the LinkedIn row clickable (full URL) |
facebook |
string | optional | Contact row (Facebook icon) |
facebookHref |
string | optional | Makes the Facebook row clickable |
location |
string | optional | Contact row (pin icon), e.g. "Gotham City, USA" |
links |
list of {label, href} |
optional | Extra contact rows — blog, portfolio, GitHub, personal site. label is optional and falls back to the URL. Keeps working alongside the built-in linkedin/facebook rows |
Contact rows appear only for keys that are present, with any links last. The ATS layout's header uses phone, email, linkedin, location (not facebook) and appends any links.
name: Bruce Wayne
title: Founder & Field Commander – Gotham Operations
company: Wayne Enterprises
phone: "+1 (201) 555-2283"
phoneHref: "tel:+12015552283"
email: bruce.wayne@wayne-enterprises.com
linkedin: linkedin.com/in/brucewayne
linkedinHref: "https://www.linkedin.com/in/brucewayne"
links:
- label: Wayne Foundation
href: "https://www.wayne-foundation.org"The professional-summary bullets at the top of page 1. Aim for 3–6 bullets, each a single sentence focused on scope, specialisation, or headline achievements.
- "Strategic operations leader with 20+ years' experience, progressing from solo field operative to Field Commander of a citywide security network."
- "Specialised in recruiting and developing elite field talent."A bullet is usually a plain string, but any bullet (here or in experience[].bullets) may instead be an object embedding a clickable link: text (before the link), link — an object of href + label (the clickable part) — and optional suffix (after it):
- text: "Published the "
link: { href: "https://example.com/report", label: "annual security report" }
suffix: " read by 40k+ practitioners."Work history, most recent first. Keep each role its own entry — ATS keywords are auto-derived from role and progression titles, so roles merged into one "earlier roles" entry (or mentioned only in bullet text) drop out of the keyword metadata. Older roles can simply carry fewer bullets. Per entry:
| Key | Type | Required | Renders |
|---|---|---|---|
role |
string | yes | Bold role headline |
company |
string | recommended | Left side of the meta line |
period |
string | recommended | Right side of the meta line, free text |
location |
string | optional | Muted line under the meta line |
description |
string | optional | One-line italic company/role description |
progression |
list of {title, period} |
optional | Indented title-history block (promotions within the role) |
bullets |
list of bullets | optional | Impact bullets — start with a verb, quantify where truthful; 3–6 per recent role, fewer for older ones. Plain strings, or the {text, link, suffix} object form (see summary.yaml) |
- role: Founder & Field Commander – Gotham Operations
company: The Batman
period: 2005 – Present
description: Self-directed vigilante operation safeguarding Gotham City.
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.
- Reduced organised-crime activity in Gotham by an estimated 60% through data-driven surveillance.Most recent first. Per entry: degree (string), institution (string), period (string).
- degree: BSc, Criminology & Chemistry
institution: Gotham University
period: 1994 – 1998Professional certifications, most recent first — kept separate from achievements.yaml (awards). Per entry: name (required), issuer (string), year (string). Omit the file if there are none.
- name: "LFD259: Kubernetes for Developers"
issuer: The Linux Foundation
year: "2023"Publications and written work, most recent first. Per entry: title (required), venue (string), year (string). Omit the file if there are none.
- title: "Applied Deterrence: Non-Lethal Intervention at Scale"
venue: Gotham Journal of Criminology
year: "2021"Languages spoken. Per entry: language (required), proficiency (string, free text — e.g. Native, Professional, Conversational). Omit the file if there are none.
- language: English
proficiency: Native
- language: Japanese
proficiency: ProfessionalSkill tags rendered as pills in the sidebar. Keep each 1–3 words; 6–12 items reads best.
- Strategic Planning
- Criminal Investigation
- Crisis ResponseAwards and recognitions. Field names are historical: year is the bold headline (usually the award name, not a year), text is the muted attribution line, conventionally "— Year, Awarding Organisation".
- year: Key to the City
text: "— Office of the Mayor, Gotham City"Per entry: name, title, company, email, phone (all strings). An explicit empty list [] prints "available upon request".
- name: Diana Prince
title: Founding Member, Justice League
company: Themysciran Embassy
email: d.prince@justiceleague.org
phone: "+1 (202) 555-0177"Extra ATS/AI-parser keywords embedded in the PDF's Keywords metadata field (never printed on the page). Competencies and job titles are auto-derived already, so list only what those don't cover. Groups are flattened; headings are not printed. Keep every keyword truthful to the CV body.
- Operations Management
- Risk Management
# or grouped:
Leadership: [Executive Leadership, Team Building]| Key | Type | Default | Meaning |
|---|---|---|---|
schemaVersion |
integer | 1 |
Content schema major version — content files never break within a major |
theme |
teal | coral | mono |
teal |
Colour scheme (mono is black-and-white, ATS-optimised) |
layout |
two-column | single-column | custom layout filename |
two-column |
Page structure |
page1ExperienceCount |
integer | auto | Experience entries on page 1 — entry N+1 starts page 2. If the count doesn't fit, validate/build warn and the overflow is clipped; automatic packing (omit the key) never overflows |
page1SplitBullets |
integer | off | Show only N bullets of page 1's last entry; the rest continue on page 2 |
atsKeywords.enabled |
boolean | true |
Master switch for keyword metadata |
atsKeywords.autoDerive |
boolean | true |
Also derive keywords from competencies + job titles |
atsKeywords.max |
integer | all | Cap on embedded keywords (body-derived terms kept first) |
Square photo, 400×400px or larger. Extensions auto-detected in precedence order: jpg, jpeg, png, webp (case-insensitive). Used by the two-column layout; the ATS variant has no photo.
A .yaml file here becomes selectable as layout: <filename>. Structure:
template: two-column # or single-column — the page shell to use
pages:
first: # page 1
sidebar: [identity-photo, contact, achievements]
main: [summary, spacer: 27, experience]
continuation: # middle pages (repeat as needed)
sidebar: [identity-compact, education, certifications, competencies, languages, publications]
main: [experience:continued]
last: # final page
sidebar: [identity-compact, referees]
main: [experience:continued]Valid section keys: identity-photo, identity-compact, contact, achievements, education, certifications, publications, languages, competencies, referees (sidebar); summary, experience, experience:continued, header-ats (main); spacer: N (N points of vertical space, either slot).
personal.yaml— name (required), title, contact details with*Hreflinks where known.summary.yaml— 3–6 single-sentence bullets.experience.yaml— every role, most recent first, with quantified truthful bullets.education.yaml,certifications.yaml,publications.yaml,languages.yaml,competencies.yaml,achievements.yaml,referees.yaml— or[]/ omit to drop.keywords.yaml— only truthful terms not already covered by competencies/titles.config.yaml— usually justtheme+layout; add pagination keys only if page 1 overflows.- Ask for the photo in your first message to the user (it can't be generated) — but never block on it; the CV renders cleanly without one. If you ran
init, replace or delete the scaffolded example photo atimages/profile.jpg(it's Bruce Wayne's) before building. Then runnpx @hrtips/cvx build.