154 lines
6.7 KiB
Markdown
154 lines
6.7 KiB
Markdown
# Mode: latex — LaTeX/Overleaf CV Export
|
|
|
|
Export a tailored, ATS-optimized CV as a `.tex` file and compile it to PDF via `tectonic` or `pdflatex`.
|
|
|
|
## Pipeline
|
|
|
|
1. Read `cv.md` as source of truth
|
|
2. Read `config/profile.yml` for candidate identity and contact info
|
|
3. Ask the user for the JD if not already in context (text or URL)
|
|
4. Extract 15-20 keywords from the JD
|
|
5. Detect JD language → CV language (EN default)
|
|
6. Detect role archetype → adapt framing
|
|
7. Rewrite Professional Summary injecting JD keywords (same rules as `pdf` mode — NEVER invent skills)
|
|
8. Select top 3-4 most relevant projects for the offer
|
|
9. Reorder experience bullets by JD relevance
|
|
10. Inject keywords naturally into existing achievements
|
|
11. Build a JSON payload (see schema below) and write to `/tmp/cv-{candidate}-{company}.json`
|
|
12. Run: `node build-cv-latex.mjs /tmp/cv-{candidate}-{company}.json output/cv-{candidate}-{company}-{YYYY-MM-DD}.tex`
|
|
13. Run: `node generate-latex.mjs output/cv-{candidate}-{company}-{YYYY-MM-DD}.tex output/cv-{candidate}-{company}-{YYYY-MM-DD}.pdf`
|
|
*(Replace `{candidate}`, `{company}`, `{YYYY-MM-DD}` with actual values.)*
|
|
14. Report: .tex path, .pdf path, file sizes, section count, keyword coverage %
|
|
|
|
**Requires:** `tectonic` (preferred — `brew install tectonic`, auto-downloads packages) or `pdflatex` (MiKTeX / TeX Live) on PATH.
|
|
|
|
## Language support
|
|
|
|
- **Localized section titles are fine.** The validator counts `\section{}` blocks instead of matching English titles, so a Spanish/French/German CV (e.g. `\section{Educación}`) validates normally.
|
|
- **CJK (Japanese / Chinese / Korean) is NOT supported on this path yet.** The template is a pdfLaTeX / Computer-Modern setup with no CJK font, so kana/kanji/hangul cannot render. `generate-latex.mjs` detects CJK characters and stops with guidance. For a Japanese CV, use `pdf` mode (HTML → PDF), which renders CJK via a `lang="ja"` font fallback.
|
|
|
|
## JSON Input Schema
|
|
|
|
Write a JSON file with this structure. `build-cv-latex.mjs` handles template merge and LaTeX escaping — no need to escape special characters yourself.
|
|
|
|
```json
|
|
{
|
|
"name": "Jane Smith",
|
|
"contact_line": "San Francisco, CA | +1 415 555 0100",
|
|
"email": { "url": "jane@example.com", "display": "jane@example.com" },
|
|
"linkedin": { "url": "https://linkedin.com/in/janesmith", "display": "linkedin.com/in/janesmith" },
|
|
"github": { "url": "https://github.com/janesmith", "display": "github.com/janesmith" },
|
|
"education": [
|
|
{
|
|
"institution": "University Name",
|
|
"location": "City, State",
|
|
"degree": "Bachelor of Science in Computer Science",
|
|
"dates": "2018 - 2022",
|
|
"coursework": ["Data Structures", "Algorithms", "Machine Learning"]
|
|
}
|
|
],
|
|
"experience": [
|
|
{
|
|
"company": "Company Name",
|
|
"role": "Job Title",
|
|
"location": "Remote",
|
|
"dates": "June 2022 - Present",
|
|
"bullets": [
|
|
"Achievement bullet with JD keywords injected",
|
|
"Another bullet with quantified impact"
|
|
]
|
|
}
|
|
],
|
|
"projects": [
|
|
{
|
|
"name": "Project Name",
|
|
"context": "Tech stack summary for the project line",
|
|
"dates": "",
|
|
"bullets": [
|
|
"What you built and what it does"
|
|
]
|
|
}
|
|
],
|
|
"skills": [
|
|
{ "category": "Languages", "items": "Python, JavaScript, C++" },
|
|
{ "category": "Frameworks", "items": "FastAPI, React, PyTorch" }
|
|
]
|
|
}
|
|
```
|
|
|
|
### Field reference
|
|
|
|
| Field | Type | Source |
|
|
|-------|------|--------|
|
|
| `name` | string | `profile.yml → candidate.full_name` |
|
|
| `contact_line` | string | Phone / City, State / Visa — built from profile.yml |
|
|
| `email.url` | string | Email for `\href{mailto:...}` (sanitized via sanitizeUrl, not LaTeX-escaped) |
|
|
| `email.display` | string | Display text for the email link |
|
|
| `linkedin.url` | string | Full URL with scheme for `\href{}` (sanitized via sanitizeUrl, not LaTeX-escaped) |
|
|
| `linkedin.display` | string | Display text only (no scheme) |
|
|
| `github.url` | string | Full URL with scheme for `\href{}` (sanitized via sanitizeUrl, not LaTeX-escaped) |
|
|
| `github.display` | string | Display text only (no scheme) |
|
|
| `education[].institution` | string | From cv.md Education |
|
|
| `education[].location` | string | Institution location |
|
|
| `education[].degree` | string | Degree name |
|
|
| `education[].dates` | string | Date range |
|
|
| `education[].coursework` | string[] | Optional — generates a coursework line if present |
|
|
| `experience[].company` | string | From cv.md Experience |
|
|
| `experience[].role` | string | Job title |
|
|
| `experience[].location` | string | Work location |
|
|
| `experience[].dates` | string | Date range |
|
|
| `experience[].bullets` | string[] | Reordered and keyword-injected achievement bullets |
|
|
| `projects[].name` | string | From cv.md Projects |
|
|
| `projects[].context` | string | Tech stack — appears next to project name |
|
|
| `projects[].dates` | string | Date range (or empty) |
|
|
| `projects[].bullets` | string[] | Selected project achievements |
|
|
| `skills[].category` | string | Skill category name (e.g. "Languages", "Frameworks") |
|
|
| `skills[].items` | string | Comma-separated skills in that category |
|
|
|
|
## LaTeX Escaping (handled by the script)
|
|
|
|
`build-cv-latex.mjs` automatically escapes all user-supplied text before insertion:
|
|
|
|
| Character | Escape |
|
|
|-----------|--------|
|
|
| `&` | `\&` |
|
|
| `%` | `\%` |
|
|
| `$` | `\$` |
|
|
| `#` | `\#` |
|
|
| `_` | `\_` |
|
|
| `{` | `\{` |
|
|
| `}` | `\}` |
|
|
| `~` | `\textasciitilde{}` |
|
|
| `^` | `\textasciicircum{}` |
|
|
| `\` | `\textbackslash{}` |
|
|
| `±` | `$\pm$` |
|
|
| `→` | `$\rightarrow$` |
|
|
|
|
**Exception:** URLs inside `\href{}` are NOT escaped by the LaTeX escaper, but `sanitizeUrl()` still validates the scheme (mailto/http/https) and removes dangerous characters to prevent injection.
|
|
|
|
## ATS Rules (same as pdf mode)
|
|
|
|
- Single-column layout (enforced by template)
|
|
- Standard section headers: Education, Work Experience, Personal Projects, Technical Skills
|
|
- UTF-8, machine-readable via `\pdfgentounicode=1`
|
|
- Keywords distributed: first bullet of each role, skills section
|
|
- No images, no graphics, no color in body text
|
|
|
|
## Keyword Injection Strategy
|
|
|
|
Same ethical rules as `modes/pdf.md`:
|
|
- NEVER add skills the candidate doesn't have
|
|
- Only reformulate existing experience using JD vocabulary
|
|
- Examples:
|
|
- JD says "RAG pipelines" → reword "LLM workflows with retrieval" to "RAG pipeline design"
|
|
- JD says "MLOps" → reword "observability, evals" to "MLOps and observability"
|
|
|
|
## Overleaf Compatibility
|
|
|
|
The generated `.tex` file uses only standard CTAN packages (no custom or bundled dependencies):
|
|
|
|
- `latexsym`, `fullpage`, `titlesec`, `marvosym`, `color`, `verbatim`, `enumitem`
|
|
- `hyperref`, `fancyhdr`, `babel`, `tabularx`, `fontawesome5`, `multicol`, `glyphtounicode`
|
|
|
|
Upload the `.tex` file directly to Overleaf — compiles with no extra configuration.
|