# Cv Builder

> Use this skill to build a tailored, ATS-friendly CV as a 1-page or 2-page PDF using Pandoc and WeasyPrint. Trigger whenever someone wants to: create or update a CV/resume targeting a specific job or company, convert their work history into a polished PDF, customize their CV for a specific role, or generate a 1-pager or 2-pager from existing source materials. Also trigger when the user says 'apply for a job', 'tailor my resume', 'create my CV for [company]', or 'update my CV' — even if they don't mention PDF format explicitly.

- Skill: `berkaybuharali/cv-builder` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add berkaybuharali/cv-builder`
- Raw SKILL.md: https://api.skillmd.com/api/skills/berkaybuharali/cv-builder/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: berkaybuharali (https://skillmd.com/u/berkaybuharali)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/berkaybuharali/cv-builder

---


# CV Builder

Opinionated CV generation workflow: source materials → structured profile → job-tailored Markdown → PDF.

## Dependencies

- **Pandoc** — [pandoc.org/installing](https://pandoc.org/installing.html)
- **WeasyPrint** — `pip install weasyprint` (all platforms; see [weasyprint docs](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html) for system dependencies)

IBM Plex Sans font — download from Google Fonts, place `.ttf` files in `styles/fonts/`:
`IBMPlexSans-Regular.ttf`, `IBMPlexSans-Medium.ttf`, `IBMPlexSans-SemiBold.ttf`, `IBMPlexSans-Bold.ttf`, `IBMPlexSans-Italic.ttf`

---

## Project Structure

Scaffold once in the working directory:

```
sources/
  cv_or_resume.*        # existing CV (PDF, DOCX, or text)
  linkedin_profile.pdf  # LinkedIn export
  notes.md              # freeform notes — wins on any conflict
  job_description.md    # target JD, swapped per application
data/
  profile.json          # canonical profile (generated)
  jd_analysis.json      # per-application JD analysis (generated)
styles/
  cv-onepage.css
  cv-twopage.css
  fonts/
scripts/
  build_onepager.sh     # see scripts/ in this skill
  build_twopager.sh
```

---

## Workflow

**First: ask the user — 1-pager, 2-pager, or both?**

### Step 1 — Ingest & Profile

Read all files in `sources/`. `notes.md` overrides everything else on conflicts.

Extract `data/profile.json`:

```json
{
  "personal": { "name": "", "title": "", "email": "", "linkedin": "", "location": "" },
  "experience": [{
    "company": "", "company_context": "", "title": "",
    "period": { "start": "MMM YYYY", "end": "MMM YYYY or Present" },
    "location": "", "bullets": []
  }],
  "education": [{ "degree": "", "institution": "", "year": "" }],
  "certifications": [{ "name": "", "issuer": "", "year": "" }],
  "languages": []
}
```

Never invent data. Mark unknowns as `"MISSING"`. Ask one clarifying question at a time.

### Step 2 — JD Analysis

Read `sources/job_description.md`. Extract `data/jd_analysis.json`:

```json
{
  "company": "", "role_title": "",
  "hard_skill_keywords": [],
  "matching_candidate_strengths": [],
  "missing_or_weak_matches": [],
  "why_this_role_draft": ""
}
```

`why_this_role_draft`: ≤400 chars, no pronouns, ties 2–3 strengths to JD keywords.

### Step 3 — Generate `cv-{COMPANY}.md`

Only **Why This Role** changes per application. Everything else is constant.

**Sections in order:**
1. Name + title + contact
2. Value Proposition (5–6 bullets, no pronouns, include any notable awards/certifications)
3. Why This Role (≤400 chars, inside `.why-this-role` div)
4. Experience (reverse chronological)
5. Competency Matrix (EXPERT / PROFICIENT / FAMILIAR)
6. Education
7. Certifications
8. Languages

**Experience block format:**
```markdown
### [Title] | [Company] | [Period] | [Location]
*[One-line context: sector, team size, scale — no client-per-bullet attribution]*

- Action verb + what + metric/result

*[Sub-section italic label if grouping needed]:*

- ...
```

**Competency Matrix format:**
```markdown
::: {.competency-matrix}
::: {.matrix-row}
::: {.matrix-label}
EXPERT
:::
::: {.matrix-items}
GCP (...), Kubernetes, Terraform, ...
:::
:::
... repeat for PROFICIENT, FAMILIAR ...
:::
```

**Why This Role box:**
```markdown
::: {.why-this-role}
**WHY THIS ROLE**

[text, ≤400 chars]
:::
```

### Step 4 — Approval Gate ⛔

**Stop. Show the Markdown. Wait for explicit approval before building any PDF.**

Iterate on content until approved. Do not run the build scripts without approval.

### Step 5 — Build PDF

Generate CSS files (see `references/css.md`) and build scripts (see `scripts/`), then run:

```bash
bash scripts/build_onepager.sh {COMPANY}   # for 1-pager
bash scripts/build_twopager.sh {COMPANY}   # for 2-pager
```

Check page count:
```bash
# macOS
mdls -name kMDItemNumberOfPages cv-onepager-{COMPANY}-latest.pdf
# Linux / Windows (requires poppler-utils)
pdfinfo cv-onepager-{COMPANY}-latest.pdf | grep Pages
```

If page count is wrong, adjust CSS spacing — reduce `margin-top` on h2/h3 and `margin-bottom` on li first, before touching font size. Hard floor: 8.5pt for 1-pager, 9pt for 2-pager.

---

## Rules

- No personal pronouns (I, my, me, we, our)
- No banned phrases: *passionate, leveraged, spearheaded, dynamic, synergy, results-driven, detail-oriented, thought leader, cutting-edge, streamlined, robust, innovative, transformative, proactive*
- Why This Role ≤400 characters (count exactly)
- All bullets start with action verbs
- Company context line on every detailed role
- No photo, no date of birth, no nationality
- `notes.md` always wins on conflicts

## ATS Check (before PDF)

- ≥70% of top-10 JD hard skills in CV
- Why This Role ≤400 chars
- No banned phrases, no personal pronouns
- All bullets start with action verbs

## Per-application update

Only regenerate the Why This Role block. Re-run ATS check. Rebuild PDF.

---

## Reference Files

- `references/css.md` — Full CSS for both layouts with tuned values

