Resume Pipeline
How I Automated My Resumes with Rust and Typst.
The Job Hunt Workflow
Automating the most soul-crushing part of the job search: resume‑pipeline.
How I Automated My Resumes with Rust and Typst
As a software engineer facing an incredibly competitive job market, I quickly realized that the spray-and-pray method of applying to jobs doesn't work. Recruiters look for specific technical stacks and experiences tailored to the very exact role they are hiring for. This means maintaining a single "master" Resume is a recipe for quick rejections. You need a dedicated tailored resume for every application.
Manually adjusting a Word Document or LaTeX file 20 times a day is soul-crushing. Thus, my Terminal UI Resume Pipeline was born.
Instead of dealing with visual editors, I built a pipeline that separates Data from Presentation. Here is a look at the internal architecture of how it fundamentally works.
1. The Data Layer (YAML)
My entire professional history—every job title I've held, every varied professional summary,
every project, and every isolated bullet point—is stored cleanly in multiple YAML files (experience.yaml, education.yaml, profile.yaml, etc.).
Using Rust and the serde crate, the application parses this vast repository of data
into strongly-typed internal Rust structs on application startup. This is the single source of
truth.
2. The Interactive Selection Engine (Ratatui)
Because not every application needs to showcase the same skills, I built an interactive Terminal
User Interface (TUI) using Ratatui. The application guides me through a
sequence of screens where I simply hit Space to toggle exactly what data I want to
include for the current job application.
I added granular controls allowing me to:
- Swap between different Job Titles and Professional Summaries to match the job description.
- Toggle entire roles or drill deep into an experience block to toggle individual bullet points on or off.
- Omit contact information (like my phone number or email) by pressing
eorp.
Once I traverse the wizard, the application creates a pruned instance of my data containing strictly what is visible.
3. The Pure Typst Compilation Boundary
Creating PDFs dynamically is historically painful (LaTeX is powerful but slow and complex to automate safely from Rust without full system dependencies). I turned to Typst—a modern, blazing-fast, Rust-based typesetting system.
However, Typst’s compiler is entirely pure. It does not blindly reach into the filesystem to
load fonts or check the system time. To integrate it securely into the pipeline, I implemented
the World trait for my application context (ResumeWorld). This
sandboxed environment acts as a tightly controlled bridge into the Typst compiler:
- Fonts: It permanently embeds the
LiberationSansfont bytes into memory so the resulting binary is completely self-contained. - Time: It injects a frozen timestamp so
#datetime.today()is completely deterministic. - Source Files: It intercepts any
#import/#includeattempts made by the template and explicitly returnsNotFoundunless it's requesting our exact layout file.
4. Bridging Rust and Typst Parameters
Instead of injecting my dynamically pruned data by generating temporary intermediate JSON files on the hard drive, I bypass the filesystem altogether.
Using derive_typst_intoval, I recursively serialize my filtered Rust structs into
Typst Dict objects. I bind this dictionary to the Typst compiler's internal Library setup.
Inside my Typst layout template, traversing this data is as simple as:
#import sys: inputs
#let resume_data = inputs
#for job in resume_data.experience [
#work_item(job.role, job.company, job.date)
#for point in job.bullets [ - #point ]
]
The template leverages advanced functional array manipulation to handle omitted fields cleanly
dynamically (preventing ugly hanging separators like Phone | | LinkedIn).
Core Capabilities
| Feature | Description |
|---|---|
| YAML‑based | Single source of truth for all professional history. |
| Interactive TUI | Ratatui-powered wizard for granular data selection. |
| Live Toggling | Toggle bullet points, profile summaries, and contact info. |
| Sandboxed Typst | Deterministic, fast compilation with embedded fonts. |
| Zero Dependencies | Everything compiled into a single, portable Rust binary. |
| Instant PDF | Meticulously typeset output in milliseconds. |
The Result
A robust, highly opinionated, incredibly fast resume generator. With zero dependencies other than
a single compiled Rust binary, I can traverse a 5-second CLI wizard and have a meticulously
typeset PDF waiting in my output/ folder, directly aligned with the specific job
description I am targeting.
No AI hallucinations, no broken formatting, and most importantly, no wasted time.
Ready to try it?
Download the latest release and the resume-data.zip, place them in the same directory, and fire it up.
Navigation & Control
| Key | Action |
|---|---|
| Enter | Continue / Generate PDF |
| Space | Toggle an item |
| J / K / Arrows | Move up/down |
| E / P | Toggle Email / Phone (screen specific) |
| E | to select bullets (screen specific) |
| Backspace | Go back |
| Q | Quit |
Once you generate a resume, it appears in output/resume.pdf instantly.
Feel free to fork the repo and make it your own.