A fast, safe JSON Resume builder written in Rust. Generates professional PDF, HTML, and ATS-friendly text output from a single JSON Resume data file, with built-in validation and content quality checking.
- Multi-format output — LaTeX/PDF, HTML (4 themes), and plain-text ATS format from one source file
- Validation — schema compliance, date ordering, email format, action verb detection, weasel word and passive voice checks
- ATS optimisation — keyword extraction, quantification ratio analysis, plain-text output with ASCII-safe formatting
- Template engine — Tera (Jinja2-compatible) templates; bring your own or use the bundled ones
- LaTeX auto-detection — probes for Tectonic, XeLaTeX, and latexmk; uses the first one found
- Safe defaults —
-shell-escapeoff by default, aux file cleanup after PDF compilation - Nix-native — reproducible builds via Nix flakes
# With Nix
nix develop
cargo build --release
# Without Nix (requires Rust toolchain)
cargo build --release# Initialise a new project
./target/release/resume-builder init --name my-resume
# Edit my-resume/resume.json, then:
# Validate
./target/release/resume-builder validate --resume my-resume/resume.json
# Build all formats
./target/release/resume-builder build \
--resume my-resume/resume.json \
--format all \
--output my-resume/build/Check a resume for schema errors, content quality issues, and ATS warnings.
resume-builder validate --resume resume.jsonExits 0 if valid (warnings are non-fatal). Exits 1 if there are hard errors.
What it checks:
basics.name,basics.email(regex),basics.phone(digit count)- Work entry required fields, date ordering (month-granular), summary length, action verbs in highlights
- Education required fields and date ordering
- Duplicate skills, empty or very short keywords
- Project name and description length
- ATS keyword count and quantification ratio
- Weasel words (
highly,very,excellent, etc.) and passive voice across all text content
Generate resume output in one or more formats.
resume-builder build [OPTIONS]| Flag | Short | Default | Description |
|---|---|---|---|
--resume |
-r |
resume.json |
Path to JSON Resume file |
--format |
-f |
pdf |
Output format: latex, html, pdf, text, all |
--output |
-o |
build/ |
Output directory |
--template-dir |
templates/ |
Directory containing Tera templates | |
--theme |
-t |
modern |
HTML theme (see below) |
Examples:
# PDF only (auto-detects LaTeX engine)
resume-builder build --resume resume.json --format pdf
# HTML with a specific theme
resume-builder build --resume resume.json --format html --theme tech-timeline
# All formats to a custom output directory
resume-builder build --resume resume.json --format all --output dist/
# Use custom templates
resume-builder build --resume resume.json --template-dir /path/to/my-templates/Extract and analyse keywords from the resume for ATS optimisation.
resume-builder keywords --resume resume.jsonPrints a ranked list of all extracted keywords with occurrence counts.
Scaffold a new resume project directory.
resume-builder init --name my-resumeCreates my-resume/ with subdirectories templates/, build/, tests/ and a starter resume.json. Errors if the directory already exists.
Four themes are available via --theme:
| Theme | Flag value | Description |
|---|---|---|
| Modern (default) | modern |
Clean two-column layout with skill bars |
| Clean Minimal | clean-minimal |
Single-column editorial style |
| Modern Professional | modern-professional |
Bold header, card-based sections |
| Tech Timeline | tech-timeline |
Timeline-style work history |
resume-builder build --resume resume.json --format html --theme modern-professionalThis tool implements JSON Resume v1.0.0. All top-level sections are optional — only include what you have.
{
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
"basics": {
"name": "Your Name",
"label": "Professional Title",
"email": "you@example.com",
"phone": "+44 7700 000000",
"url": "https://yoursite.com",
"summary": "Brief professional summary.",
"location": {
"city": "London",
"countryCode": "GB"
},
"profiles": [
{ "network": "GitHub", "username": "yourhandle", "url": "https://github.com/yourhandle" },
{ "network": "LinkedIn", "username": "yourhandle", "url": "https://linkedin.com/in/yourhandle" }
]
},
"work": [
{
"name": "Company Name",
"position": "Your Role",
"url": "https://company.com",
"startDate": "2021-03",
"endDate": "Present",
"summary": "What you did.",
"highlights": [
"Reduced deployment time by 40% by introducing a CI/CD pipeline.",
"Led a team of 5 engineers across 3 time zones."
],
"location": "London, UK"
}
],
"education": [
{
"institution": "University Name",
"area": "Computer Science",
"studyType": "BSc",
"startDate": "2014",
"endDate": "2018"
}
],
"skills": [
{ "name": "Languages", "keywords": ["Rust", "Go", "Python", "TypeScript"] },
{ "name": "Infrastructure", "keywords": ["Kubernetes", "Terraform", "AWS"] }
],
"projects": [
{
"name": "my-oss-project",
"description": "A tool that does X.",
"url": "https://github.com/you/my-oss-project",
"highlights": ["500+ GitHub stars", "Used in production at 3 companies"],
"startDate": "2022"
}
],
"awards": [
{ "title": "Award Name", "date": "2023", "awarder": "Organisation", "summary": "Why." }
],
"certificates": [
{ "name": "Certified Kubernetes Administrator", "date": "2022", "issuer": "CNCF" }
],
"publications": [
{ "name": "Article Title", "publisher": "Blog Name", "releaseDate": "2023-06", "url": "https://..." }
],
"languages": [
{ "language": "English", "fluency": "Native" },
{ "language": "German", "fluency": "Professional" }
],
"volunteer": [
{
"organization": "Organisation Name",
"position": "Role",
"startDate": "2019",
"endDate": "2021",
"summary": "What you did."
}
],
"interests": [
{ "name": "Open Source", "keywords": ["Rust", "Nix", "Linux"] }
],
"references": [
{ "name": "Referee Name", "reference": "Available on request." }
]
}Date format: ISO 8601 — YYYY, YYYY-MM, or YYYY-MM-DD. Use "Present" for ongoing roles.
Templates use Tera syntax (Jinja2-compatible). Fields map to camelCase keys matching the JSON Resume spec.
templates/
├── latex/
│ └── moderncv.tex.j2 # ModernCV-based LaTeX
├── html/
│ ├── modern.html.j2 # Default HTML theme
│ └── themes/
│ ├── clean-minimal.html.j2
│ ├── modern-professional.html.j2
│ └── tech-timeline.html.j2
└── text/
└── ats-friendly.txt.j2 # ATS plain-text
Point --template-dir at any directory containing .j2 files with the same naming conventions. The root context variable is resume — the full deserialized JSON Resume object.
{{ resume.basics.name }}
{{ resume.basics.label }}
{% for job in resume.work %}
{{ job.position }} at {{ job.name }}
{{ job.startDate }} - {{ job.endDate | default(value="Present") }}
{% endfor %}The escape_latex filter is available in LaTeX templates to safely escape special characters:
{{ job.summary | escape_latex }}The pdf format requires a LaTeX engine. The builder probes for engines in this order:
- Tectonic — self-contained, no TeX installation needed (tectonic-typesetting.io)
- XeLaTeX — from a standard TeX Live or MiKTeX installation
- latexmk — wrapper around pdflatex/xelatex
If none are found, build --format pdf returns an error. Use --format latex to produce the .tex source without compiling.
Auxiliary files (.aux, .log, .fls, .fdb_latexmk, .out) are cleaned up automatically after a successful PDF build.
.
├── resume.json # Your resume data
├── Cargo.toml
├── flake.nix # Nix build
├── src/
│ ├── main.rs # CLI entry point and argument definitions
│ ├── lib.rs # Library exports
│ ├── cli/ # Subcommand handlers
│ │ ├── build.rs
│ │ ├── init.rs
│ │ ├── keywords.rs
│ │ └── validate.rs
│ ├── models/
│ │ └── resume.rs # JSON Resume data structures
│ ├── templates/
│ │ └── engine.rs # Tera engine wrapper and escape_latex filter
│ ├── utils/
│ │ └── latex.rs # LaTeX engine detection and compilation
│ └── validation/
│ └── resume_validator.rs # All validation and content quality logic
├── templates/ # Tera template files
├── tests/
│ ├── cli_scenarios.rs # End-to-end CLI tests (assert_cmd)
│ ├── template_snapshots.rs # Snapshot tests (insta)
│ └── fixtures/ # Test resume JSON files
└── build/ # Generated output (gitignored)
# Build
cargo build
# Run all tests (63 tests across 4 suites)
cargo test
# Lint
cargo clippy
# Update snapshot tests after intentional template changes
cargo insta accept
cargo test| Suite | Location | Count | What it covers |
|---|---|---|---|
| Unit — validator | src/validation/resume_validator.rs |
45 | All validation rules, property tests |
| Unit — templates | src/templates/engine.rs |
4 | escape_latex filter, property tests |
| CLI scenarios | tests/cli_scenarios.rs |
5 | End-to-end binary behaviour |
| Snapshot | tests/template_snapshots.rs |
5 | Template rendering regression |
MIT — see LICENSE for details.