The template
One class file owns the layout; a resume file holds only content. These are the real pages, built by CI from this commit: Duna's complete canonical resume, and the one-page variant tailored for a job.
What to notice, from the top of a page down:
-
Section tabs
Each section opens with a graphite tab and a rule to the margin. Sections always print in the same order (Summary, Experience, Projects, Education, Publications, Service, Honors & Awards), whatever the order in the source; leave one out to drop it.
-
A timeline spine
Roles and projects hang off one line, a ring for each entry, and the line keeps going across a page break.
-
Date pills
Dates are written once as
2023-04orpresent; the class prints them as Apr 2023 – Present.
-
Facts cited by key
A role's title, employer, place, and dates are defined once in
common/facts/and cited by key, so every variant prints them the same way.% common/facts/roles.tex \defrole{windowsill}{ title = {Head of Windowsill Operations}, org = {Sunbeam Estates}, location = {Living Room}, start = 2023-04, end = present, }% canonical/resume.tex \begin{role}{windowsill} \item Initiated and led ``Operation Red Dot'', … \end{role}
-
A typo fails the build
Cite
windowsilinstead ofwindowsilland the build stops with an error that names it. So do a missing field, a duplicate section, and a date like2024-13../canonical/resume.tex:60: Package resume Error: Unknown role key 'windowsil'. -
No stranded titles
Pages break between bullets, never between a role's title and its first bullet or between a heading and its first entry. A test moves the content through 51 page positions to check.
How it works
One complete resume, a tailored copy for each job, and git to remember what you sent.
-
Facts, written once
Roles, projects, degrees, publications, service, and honors are defined once in
common/facts/and cited by key. A wrong key, a missing field, or a bad date stops the build, so a title or a date can't drift between variants. -
/customize-resumetailors, with your approvalGive Claude Code a job posting. It saves a summary as
jd.mdin a new application folder, maps what the job asks for to evidence already in your resume, and stops for your approval before it edits. An ask with no evidence is marked as such, never invented. -
/update-resumeand tags keep historyNew experience goes into the facts and the canonical resume, and Claude asks for any date or title it doesn't have. Each application is a folder; tag it
submitted/…when you send it, and checking out the tag and building it gives back what you sent (with the same TeX Live).
Get started
Use the repo as a template and clone your copy. Then, on macOS with Homebrew:
brew bundle # BasicTeX, just, tex-fmt, prettier, poppler
just deps # + the extra TeX Live packages (asks for sudo once)
just build # canonical/resume.tex → canonical/resume.pdf
just check applications/2026-09-granary-senior-mouser # build + check it fits in 2 pages
just test # run the template tests
To make it yours, put your details in common/profile.tex and
common/facts/ (or run /update-resume in Claude Code and let it
ask for them), and rewrite canonical/resume.tex. For a job, run
/customize-resume with the posting.
- The repository on GitHub the source and the full README
- CLAUDE.md the rules Claude follows, starting with: never invent or inflate a claim
- The customize-resume skill tailors a variant to a job posting, and stops for your approval
- The update-resume skill adds new experience to the facts and the canonical resume