Data-Driven CV with LaTeX, Lua & GitHub Actions
Bilingual CV and cover letter generated from a single JSON source using LaTeX and Lua. Automated compilation and deployment via GitHub Actions.
An automated system for generating a Curriculum Vitae and cover letter in both Italian and English. Built on LaTeX with the moderncv class, but rethought from the inside: content is fully separated from presentation and lives as a single source of truth under data/.
The Problem It Solves
Keeping a CV up to date in two languages across separate .tex files means updating every piece of data twice, in two different places - with the risk of them falling out of sync. Worse, this website’s own CV page used to be a third copy, maintained by hand and never quite in sync with the PDF. This project eliminates that redundancy entirely.
How It Works
Single Source of Truth
Everything - work experience, education, skills, projects, personal info - lives under data/, one JSON file per domain (numbered to match render order), with lightweight Markdown (**bold**/*italic*) for emphasis instead of raw LaTeX. Updating the CV, cover letter, and this website’s /cv/ page means editing those files only.
The Lua ↔ LaTeX Bridge
The file commons/lua_data_loader.tex contains a Lua script that, during compilation via LuaLaTeX, reads the JSON, converts the Markdown emphasis to LaTeX, and dynamically populates the document sections in the selected language. It’s not a static template - it’s code that runs at compile time.
The Python ↔ JSON Resume Bridge
scripts/generate_resume_json.py reads the same data/ source and produces a resume.json in JSON Resume format for this website’s /cv/ page, which renders it through a custom Research section (added on top of the standard schema) alongside the usual Education/Experience/Publications/Skills.
CI/CD Pipeline
A GitHub Actions workflow automatically compiles all four documents on every push and publishes them to the pdf-release branch. From there, further steps sync the CV PDFs and the generated resume.json directly to this website repository (eneamanzi.github.io), keeping the online version always current with no manual intervention.
data/*.json → lua_data_loader.tex → LuaLaTeX → PDF
│ ↓
│ GitHub Actions deploy
│ ↓
└── generate_resume_json.py → resume.json → eneamanzi.github.io (always up-to-date)
Generated Documents
| Document | Language |
|---|---|
| Curriculum Vitae | Italian |
| Curriculum Vitae | English |
| Cover Letter | Italian |
| Cover Letter | English |
Tech Stack
- Markup language: LaTeX (
moderncv) - Compilation engine: LuaLaTeX
- Scripting: Lua, Python
- Data format: JSON (custom domain schema + generated JSON Resume)
- Automation: GitHub Actions
- Build tool:
latexmk