When applying for jobs, it is important to ensure that your resume is well-structured and relevant to the positions you are applying for. But exactly what counts as “relevant” depends on the position, and without a good system you will find yourself editing several versions of your resume over and over again. This post arose out of my own desire to streamline this entire process, from adding new experiences to my resume to tailoring it to specific roles.
Naturally, a lot of people have already thought about this problem. There are many tools and services that are made for writing resumes, some of which require hefty usage fees. In this post, I suggest a solution that is so simple and obvious in hindsight that no one else has bothered to write about it.
The idea is to use a simple structured format, YAML, as the ground truth, and templates to turn the YAML resume into other formats like LaTeX, HTML, or whatever else you prefer. In more details, the benefits of this approach is that it allows you to:
- Maintain a single source of truth for your resume
- Easily create role-specific versions
- Generate documents in any format (PDF, HTML, Markdown, etc.), with complete control over the styling
- Keep everything under version control
- Optionally use AI to help tailor your resume
Let’s explore why this approach works better than traditional methods.
Why YAML?
Three common approaches and why I moved away from them:
The Word Document Approach
An approach I’ve been using over the last year is to maintain a single resume in Word document, as this is recommended by many sources.1 However, this has some drawbacks. Since docx
is a binary format, it is not friendly to version control, making it more cumbersome to maintain multiple versions for different roles. It also requires special software to view or edit, which makes it difficult to work with using programming tools.
1 A big part of why Word documents are recommended is that they tend to be friendly to Applicant Tracking Systems (ATS). But PDF generated with LaTeX can also be compatible with ATS, if careful attention is paid to the layout.
The Markdown / Asciidoc Approach
One idea I had was to maintain a single “master resume” in Markdown format, which is a text-based format that is easy to maintain and edit, and set up workflows for converting it to different formats. It’s easy to find several examples of this online, such as here and here.
The main disadvantage is losing control over formatting, often resulting in unattractive documents. While there are tools to help, they all follow the same basic strategy:
- Convert the Markdown document to a more structured format like JSON.
- Convert the structured format to the desired format.
More concretely, there are two main approaches. The first is to generate an HTML file from Markdown, controlling styling with a custom CSS file, and then convert the HTML file to the desired format, for example by printing it to a PDF. The HTML will look nice, but the PDF may not. The second approach is to rely on a powerful tool like pandoc, which can convert between different formats. Again, the final document may not look the way you want it to. This is not an insurmountable problem, but from what I can tell, it can be challenging to get the styling just right.
A similar approach to the Markdown approach is to use a richer text-based format like Asciidoc. Using Asciidoc has the advantage over Markdown that it may be somewhat easier to wrestle with the formatting. But just like with Markdown, it ultimately feels like trying to make a silk purse out of a sow’s ear.
The YAML Solution
It is easy to convert from a highly structured format to a less structured format, but not the other way around. This realization led me to structured file formats like JSON and YAML.
I’m not the first person to have this idea. In fact, there is a whole community of people advocating for a JSON-based standard for resumes, and various different tools for converting resumes from structured formats like YAML to other formats.
However, I’m advocating for a slightly different approach. Instead of providing a comprehensive package, my suggestion is to use a few lines of code to convert a YAML file into other formats using jinja2 templates. This doesn’t adhere to any strict standards, but it’s simple and flexible, and can be adapted to many different use cases.
I chose to use YAML over JSON because it’s more human-readable and doesn’t require quotes around strings or commas between items.
The YAML resume: A simple example
Here is an example of a YAML resume (click to expand):
Geppetto’s YAML resume
name: Geppetto
contact:
location: Villaggio Incantato, Italy
date_of_birth: March 12, 1820
citizenship: Italy
email: geppetto@woodmail.it
phone: +39 123 456 7890
github: https://github.com/geppetto-works
summary:
- text: |
Master woodcarver with a lifelong dedication to handcraft, toy design, and mechanical storytelling.
Combines traditional techniques with creative engineering to build expressive and enduring works.
Looking to contribute craftsmanship and care to meaningful creative projects.
education:
- institution: Guild of Master Carvers
degree: Journeyman Woodworker Certification
date: 1842
location: Florence, Italy
- institution: Independent Study
degree: Apprenticeship in Automata Construction and Puppet Mechanics
date: 1845
location: Venice, Italy
experience:
- organization: Geppetto's Workshop
location: Villaggio Incantato, Italy
role: Master Woodcarver and Toymaker
start: January 1850
end: Present
bullets:
- Designed and handcrafted over 300 wooden toys including animals, puppets, and musical automata.
- Created Pinocchio, an autonomous puppet capable of emotional response and ethical reasoning.
- Offered sliding-scale toy repairs and creations for families in the village.
- Built puppet theaters with hand-cranked scenery for school performances.
- Developed innovative joint mechanisms for enhanced puppet mobility and expression.
- Mentored 15 apprentices in traditional woodcarving techniques and mechanical design.
- Invented a self-playing musical box system using wooden gears and wind-up mechanisms.
- Established a community workshop program teaching basic woodworking to village children.
- Created custom mechanical toys for special needs children to aid in motor skill development.
- organization: Puppet Theater of Tuscany
location: Tuscany, Italy
role: Set Designer and Puppet Articulator
start: June 1848
end: December 1849
bullets:
- Designed stage mechanisms and built expressive puppets for traveling shows.
- Worked with performers to enhance articulation through mechanical design.
projects:
- title: Pinocchio
date: Ongoing
description: >
A fully articulated wooden puppet designed for emotional expressiveness and narrative-constrained learning.
Combines handcrafted form with emergent behavioral systems and ethical instruction frameworks. url: https://en.wikipedia.org/wiki/Pinocchio
- title: Whistle-toy Orchestra
date: March 1885
description: >
A set of carved whistle-operated instruments that harmonize through tuned airflow and puppet-assisted actuation.
Created to teach children musical structure through playful experimentation.
honors:
- title: Best Toymaker in Tuscany
description: Awarded by the Tuscany Chamber of Artisans for craftsmanship, community impact, and imaginative design.
date: December 1883
- title: Patron of the Children's Guild
description: Recognized for mentorship and generosity supporting village youth creative expression.
date: June 1886
publications:
- title: "The Heart Inside the Wood: Designing for Growth"
type: Preprint (submitted)
date: 1881
- title: "Whimsy and Will: Puppetry as a Medium for Ethical Development"
type: Symposium Proceedings
date: 1880
- title: "Toymaking for the Soul: A Handbook for Village Craft Educators"
type: Community Education Manual
date: 1876
coauthors:
- Silvino Boccadutti
- title: On the Practical Construction of Puppet Joints
type: Instructional Manual
date: 1874
This YAML resume can be converted to other formats using jinja2 templates and a few lines of code. I’ll get back to the templates later, but first, let’s look at the code for rendering the resume to a different format, for example tex
:
import yaml
from pathlib import Path
from jinja2 import Template
= "tex" # Change this to a different format if you want
FORMAT
# Load resume data
= yaml.safe_load(Path(f"resume.yaml").read_text())
resume_data
# Load and render template
with open(f"resume.{FORMAT}.j2") as f:
= Template(f.read())
template = template.render(**resume_data)
output
# Write output
f"resume.{FORMAT}").write_text(output)
Path(print(f"Resume rendered to resume.{FORMAT}")
Here is a simple example of a tex
template:
Jinja2 template for tex
\documentclass[10pt]{article}
\usepackage[margin=0.75in]{geometry}
\usepackage{enumitem}
\usepackage{titlesec}
\usepackage{hyperref}
\usepackage{xcolor}
% Customize hyperlink appearance
\definecolor{darkblue}{RGB}{0,0,120}
\hypersetup{
colorlinks=true,
linkcolor=darkblue,
filecolor=darkblue,
urlcolor=darkblue,
}
% No paragraph indentation
\setlength{\parindent}{0pt}
% \setlength{\parskip}{0.5em} % Optional: adds space between paragraphs
% Section formatting
\titleformat{\section}
{\normalsize\bfseries\uppercase}
{}{0em}{}[\titlerule]
\titlespacing*{\section}
{0pt}{1.5ex plus 1ex minus .2ex}{1ex plus .2ex}
% Custom commands for better spacing
\newcommand{\spaced}[1]{\vspace{0.3em}#1\vspace{0.3em}}
\begin{document}
% Header
\begin{center}
{\Large\bfseries{ {{- name -}} }}\\[0.2em]
{\normalsize
\href{mailto:{{ contact.email }}}{ {{- contact.email -}} } ~|~
\href{tel:{{ contact.phone }}}{ {{- contact.phone -}} } ~|~
\href{ {{- contact.github -}} }{GitHub}
}
\end{center}
\vspace{0.5em}
% Summary
{% if summary %}
\section*{Summary}
{% for s in summary %}
{{ s.text }}
{% endfor %}
{% endif %}
% Experience
\section*{Experience}
{% for job in experience %}
\textbf{ {{- job.organization -}} }, \hfill {{ job.location }} \\
\textit{ {{- job.role -}} }, \hfill {{ job.start }} -- {{ job.end }}
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
{% for b in job.bullets %}
\item {{ b }}
{% endfor %}
\end{itemize}
\vspace{0.3em}
{% endfor %}
% Projects
\section*{Projects}
{% for p in projects %}
\textbf{\href{ {{- p.url -}} }{ {{- p.title -}} }}, \hfill {{ p.date }} \\
{{ p.description }} \\
\vspace{0.3em}
{% endfor %}
% Education
\section*{Education}
{% for ed in education %}
\textbf{ {{- ed.institution -}}, } \hfill {{ ed.location }} \\
{{ ed.degree }}, \hfill {{ ed.date }}
\vspace{0.3em}
{% endfor %}
% Honors and Awards
\section*{Honors and Awards}
{% for award in honors %}
\textbf{ {{- award.title -}},} \hfill {{ award.date }} \\
{{ award.description }}
\vspace{0.3em}
{% endfor %}
% Publications
\section*{Publications}
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
{% for pub in publications %}
\item \textit{\href{ {{- pub.url -}} }{ {{- pub.title -}} }}{% if pub.coauthors %}, with {{ pub.coauthors | join(", ") }}{% endif %}. {{ pub.type }}.{% if pub.journal %} {{ pub.journal }} ({{ pub.date }}).{% endif %}
{% endfor %}
\end{itemize}
\end{document}
Running the code produces a tex
file like this:
Geppetto’s tex resume
\documentclass[10pt]{article}
\usepackage[margin=0.75in]{geometry}
\usepackage{enumitem}
\usepackage{titlesec}
\usepackage{hyperref}
\usepackage{xcolor}
% Customize hyperlink appearance
\definecolor{darkblue}{RGB}{0,0,120}
\hypersetup{
colorlinks=true,
linkcolor=darkblue,
filecolor=darkblue,
urlcolor=darkblue,
}
% No paragraph indentation
\setlength{\parindent}{0pt}
% \setlength{\parskip}{0.5em} % Optional: adds space between paragraphs
% Section formatting
\titleformat{\section}
\normalsize\bfseries\uppercase}
{\titlerule]
{}{0em}{}[\titlespacing*{\section}
{0pt}{1.5ex plus 1ex minus .2ex}{1ex plus .2ex}
% Custom commands for better spacing
\newcommand{\spaced}[1]{\vspace{0.3em}#1\vspace{0.3em}}
\begin{document}
% Header
\begin{center}
\Large\bfseries{Geppetto}}\\[0.2em]
{\normalsize
{\href{mailto:geppetto@woodmail.it}{geppetto@woodmail.it} ~|~
\href{tel:+39 123 456 7890}{+39 123 456 7890} ~|~
\href{https://github.com/geppetto-works}{GitHub}
}\end{center}
\vspace{0.5em}
% Summary
\section*{Summary}
Master woodcarver with a lifelong dedication to handcraft, toy design, and mechanical storytelling.
Combines traditional techniques with creative engineering to build expressive and enduring works.
Looking to contribute craftsmanship and care to meaningful creative projects.
% Experience
\section*{Experience}
\textbf{Geppetto's Workshop}, \hfill Villaggio Incantato, Italy \\
\textit{Master Woodcarver and Toymaker}, \hfill January 1850 -- Present
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
\item Designed and handcrafted over 300 wooden toys including animals, puppets, and musical automata.
\item Created Pinocchio, an autonomous puppet capable of emotional response and ethical reasoning.
\item Offered sliding-scale toy repairs and creations for families in the village.
\item Built puppet theaters with hand-cranked scenery for school performances.
\item Developed innovative joint mechanisms for enhanced puppet mobility and expression.
\item Mentored 15 apprentices in traditional woodcarving techniques and mechanical design.
\item Invented a self-playing musical box system using wooden gears and wind-up mechanisms.
\item Established a community workshop program teaching basic woodworking to village children.
\item Created custom mechanical toys for special needs children to aid in motor skill development.
\end{itemize}
\vspace{0.3em}
\textbf{Puppet Theater of Tuscany}, \hfill Tuscany, Italy \\
\textit{Set Designer and Puppet Articulator}, \hfill June 1848 -- December 1849
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
\item Designed stage mechanisms and built expressive puppets for traveling shows.
\item Worked with performers to enhance articulation through mechanical design.
\end{itemize}
\vspace{0.3em}
% Projects
\section*{Projects}
\textbf{\href{https://en.wikipedia.org/wiki/Pinocchio}{Pinocchio}}, \hfill Ongoing \\
A fully articulated wooden puppet designed for emotional expressiveness and narrative-constrained learning. Combines handcrafted form with emergent behavioral systems and ethical instruction frameworks.\\
\vspace{0.3em}
\textbf{\href{}{Whistle-toy Orchestra}}, \hfill March 1885 \\
A set of carved whistle-operated instruments that harmonize through tuned airflow and puppet-assisted actuation. Created to teach children musical structure through playful experimentation.\\
\vspace{0.3em}
% Education
\section*{Education}
\textbf{Guild of Master Carvers, } \hfill Florence, Italy \\
\hfill 1842
Journeyman Woodworker Certification, \vspace{0.3em}
\textbf{Independent Study, } \hfill Venice, Italy \\
\hfill 1845
Apprenticeship in Automata Construction and Puppet Mechanics, \vspace{0.3em}
% Honors and Awards
\section*{Honors and Awards}
\textbf{Best Toymaker in Tuscany,} \hfill December 1883 \\
Awarded by the Tuscany Chamber of Artisans for craftsmanship, community impact, and imaginative design.\vspace{0.3em}
\textbf{Patron of the Children's Guild,} \hfill June 1886 \\
Recognized for mentorship and generosity supporting village youth creative expression.\vspace{0.3em}
% Publications
\section*{Publications}
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
\item \textit{\href{}{The Heart Inside the Wood: Designing for Growth}}. Preprint (submitted).
\item \textit{\href{}{Whimsy and Will: Puppetry as a Medium for Ethical Development}}. Symposium Proceedings.
\item \textit{\href{}{Toymaking for the Soul: A Handbook for Village Craft Educators}}, with Silvino Boccadutti. Community Education Manual.
\item \textit{\href{}{On the Practical Construction of Puppet Joints}}. Instructional Manual.
\end{itemize}
\end{document}
Finally, compile the tex
to a pdf
:
The upshot is that it’s easy to maintain and edit the resume in YAML format, and to control the style of the final document with a jinja2 template. Of course, it’s also possible to make jinja2 templates for HTML, Markdown, or other formats.
One resume to rule them all
The above works for one resume in multiple formats. To target different roles, tag items in the YAML (e.g., all
, woodworking
, robotics
) and generate role‑specific resumes by filtering on tags. Optionally, use an LLM or other tools for light phrasing tweaks2.
2 In the end, I haven’t found the LLM suggestions to be helpful, but the feature is still in the accompanying repository. It can probably be improved by better prompting and fine-tuning.
This lets you keep one master resume while producing focused versions per role with minimal effort.
A practical implementation
The accompanying GitHub repository provides a simple CLI tool that enables the following workflow:
- Filtering:
resume generate --role <role>
to create a role‑specific YAML file from the master file. - Review: Optionally pass
--job <desc.txt>
to lightly refine phrasing with an LLM, or edit manually. - Rendering:
resume render --role <role-template>
to produce documents via your jinja2 templates.
If you go to the repository, you can also see an example of Geppetto’s resume with tags, and the resulting resume files for different roles.