Photo by Patrick Fore on Unsplash

Generating custom resumes for job applications using Terminal UIs

Brian Mathiyakom

--

I’m in the middle of job search. Like many in the technology industry, I was laid off in late 2023. I thought getting some extended time away from a job would be a nice change of pace. Refreshing even.

Not the case.

I had this nagging anxiety or worry about what my next role would be:

  • Do I continue doing more of the same (honing existing skills is a good thing)?
  • Do I try to jump up a level with a broader set of responsibilities?
  • Do I switch careers again since I’ve jumped between individual contributor and manager roles in the past?

Fortunately, I have some savings and an awesome and employed wife (thank you, Jesus) so I have space to think through these meta questions. Maybe I’ll write about how I approached them someday.

Writing resumes for each job application

Right now, I have a grand total of 94 job applications to companies in a variety of fields that drew my attention. I applied to roles as an software engineer, a manager/director, and to executive roles (at smaller startups). This means that the accomplishments in my submitted resumes have also been tailored for each application.

I presume that it’s wiser to highlight engineering accomplishments when applying for an engineer role. And vice versa for management roles. I don’t want my resume to be too long either; recruiters spend mere seconds reviewing a single resume. With tips from friends and easy-to-customize designs from Canva, I created separate resumes for each role. And each resume fit into one page. That’s not a bad result when trying to simplify a nearly two decade career in tech!

While Canva mostly worked, it is also a WYSIWYG app. That means that if I wanted to reposition, add, or remove content, I needed to then adjust the alignment and spacing for the surrounding content and export the result as a PDF. It’s a straight-forward but also tedious process.

How my previous resume was maintained 🛠

My previous resume before using Canva was written in Markdown (MD) and CSS. I would write the content in MD and style the layout with CSS. I used Pandoc to transform the MD+CSS into a PDF using weasyprint as the underlying PDF engine.

pandoc resume.md --pdf-engine=weasyprint -s --section-divs \
-c style.css -o resume.pdf

This setup was also OK.

Editing text files is better for my workflow. The CSS adjusted for spacing issues automatically as the content changed. And CSS properties like page-break-inside made for easy reading (i.e. keeping all accomplishments for a given job on the same page).

Except I’m not a great designer so the overall design wasn’t as “clean”. And as I would find out later: PDF engines don’t understand many CSS properties. And I would have had to keep separate MD files if I wanted to subset my resume into role buckets (engineer-focused, manager-focused).

Tinkering and Ideas 🤔

I’ve been interested in the Terminal User Interfaces (TUI) lately. A number of them have been featured in online forums that I visit. They reminded a lot of old bulletin board games (quite nostalgic).

So, I had the idea of making a resume generator using a TUI as the interface.

Writing a resume generator

The resume generator needed to combine the things I like from having a resume in Canva and in Markdown. Given my professional employment history and full list of accomplishments per job:

  • Allow me to easily pick which accomplishments to include in the generated resume via the command-line.
  • Support CSS for styling of the generated resume.
  • Support PDF as the final output format of the generated resume.
  • Keep the generated resume to one printed page¹.
  • Allow me to easily edit logistic info in the resume (skills, contact info, education, etc).

I decided to try out Charm as the TUI framework. Specifically, their huh library seemed like a good starting point for how I can do the “accomplishment picking”.

The first end-to-end iteration of the generator worked in the following way:

  1. Display the accomplishment multi-select form (the accomplishments were hard-coded into the app).
  2. I would select accomplishments I wanted.
  3. Perform variable substitution of the accomplishments into a HTML file. This was done with Go Templates since the app was written in Golang. Charm is a library for Go, so choosing Go as the base language was a choice made for me since I decided on Charm in the first place.
  4. Use Pandoc to transform the resulting HTML file into a PDF.

Fun with PDF engines, or not…

I recreated my favorite Canva resume template in HTML + CSS. I used Tailwind to help me style it. But the resulting PDF look at all like the HTML. Even when I pre-processed a static CSS file to include the Tailwind properties I used in the HTML (via tailwindcss), Pandoc and the PDF engine just didn’t properly interpret the CSS properties.

I could have spent more time trying to make Pandoc happy: like rewriting the CSS without Tailwind. That would have been more prudent. But I found having Tailwind available made making layout adjustments easier. So I considered the alternative of dropping Pandoc.

What is really good at rendering HTML/CSS and exporting to PDF?

Web browsers.

I got the idea to use a headless Chromium instance to render the resume HTML and then have it export the page to PDF. I used a Playwright library for Go to do this. Aside from being a more heavyweight process (launching a browser), it worked really well.

Open-sourcing

After showing this to my wife, she asked if she could do this with her resume too.

That began the journey of “refactoring so that someone else can generate custom resumes for themselves”.

You can find the code at GitHub.

A screenshot of selecting accomplishments in the resume generator

The current workflow is now:

  1. Read resume data from data.json.
  2. Display the accomplishment multi-select form with Charm/huh.
  3. Select accomplishments I wanted via keyboard.
  4. Perform variable substitution of the accomplishments into a HTML file via Go Templates.
  5. Export the template into HTML in /tmp.
  6. Launch Playwright and have it open the HTML file in /tmp.
  7. Ask Playwright to export a PDF of the HTML page into the current directory.

I can highlight relevant accomplishments in my resume on per job-application basis by generating a resume specific for the job application.

Screenshot of example resume PDF

I considered using some form of GenAI to take in the job description, my full list of accomplishments and write me a resume. But I didn’t want to work with the AI to adjust its writing style to mine nor did I want to figure out how to extract its output into my HTML layout². Maybe I’ll have the energy to play with this later, but now isn’t the time.

If you’re job hunting right now and are feeling overwhelmed, then I know the feeling. You’re not alone 💛.

¹: I didn’t end up implementing the keep-on-one-page feature. Didn’t need it in the end.

²: I would also want to do all of this locally and not send ChatGPT (or friends) too much of my information.

--

--

Brian Mathiyakom

Follower of Christ, makes a living through technology, pets all the cats 🐈