Resume Builder is an HTML and PDF resume builder made in Ruby with Middleman. It lets you keep resume content in YAML files and render it as HTML for the web and as PDF-ready HTML for download/printing.
It has the following features:
- YAML-based resume content with layouts and styles kept separately.
- Thirteen resume section types and six complete screen/print themes.
- Multiple selectable resume definitions, with explicit supported and archived lists.
- Optional brief versions, Gravatar photos, and Markdown/HTML descriptions.
- Schema validation before rendering, including referenced jobs, skills, links, summaries, layouts, templates, and PDF sources.
- Static HTML and PDF-ready HTML generation, plus a downloadable PDF copied from each resume's configured source.
- Unit, shell, full build-matrix, rendered-content, PDF-conversion, and visual regression coverage.
- Automated GitHub Pages deployment to resume.timothyfisher.com.
The tracked example deployment is johndoe/resume_sample, selected in
data/active_resume.yml, with brief generation disabled. Supported resumes are
exercised across all six themes with brief generation both enabled and
disabled.
Every build writes Middleman's intermediate files to build/ and packages the
selected deployable resume under dist/<user>/<resume-name>/. The packaged
artifact contains the screen and PDF HTML entrypoints, stylesheets, optional
brief entrypoints, and the configured downloadable PDF.
If you forked to your own repo:
git clone https://github.com/<yourusername>/resume-builder.git
cd resume-builder
Otherwise:
git clone https://github.com/timothyf/resume-builder.git
cd resume-builder
Install Ruby 3.4.9 with RVM and use the project gemset:
rvm install 3.4.9
rvm use 3.4.9@resume --create
Install Ruby dependencies:
bundle install
Node.js 22, Python 3.12, and Poppler are also required to run the complete visual regression suite. Install the project-managed Node and Python packages with:
npm ci
pip install -r requirements-visual.txt
Install poppler-utils with your operating system package manager so
pdftoppm is available.
See the deployed resume at resume.timothyfisher.com.
Build the static version of your resume
bundle exec middleman build
Or use the helper script:
./build_resume.bash
Optional profile override:
./build_resume.bash --resume-user johndoe --resume-name resume_sample
Optional theme override:
./build_resume.bash --theme theme-fern
You can also use environment variables:
ACTIVE_RESUME_USER=johndoe ACTIVE_RESUME_NAME=resume_sample ./build_resume.bash
ACTIVE_RESUME_THEME=theme-orange ./build_resume.bash
Optional brief-generation override:
ACTIVE_RESUME_GENERATE_BRIEF=true ./build_resume.bash
View current configured and effective active resume selection:
./show_active_resume.bash
With override preview:
ACTIVE_RESUME_USER=johndoe ACTIVE_RESUME_NAME=resume_sample ./show_active_resume.bash
Available themes:
theme-default, theme-fern, theme-grey, theme-orange, theme-tapestry, theme-tradewind
data/johndoe/layouts/layout_ats.yml provides a text-first,
single-column layout modeled on a conventional ATS resume. It renders a
centered identity and contact header followed by summary, skills, experience,
and education. The layout uses semantic HTML, standard fonts, black text,
simple headings, and no sidebar, icon dependency, tables, or decorative content
that could interfere with resume parsers.
Select it in a resume definition with:
layout: layout_ats
pdf:
useicons: falseThe ATS layout is independent of the selected color theme and has dedicated responsive and Letter-print rules. It is also available in the Local YAML Editor layout selector. The active deployed resume is not switched to this layout automatically.
Theme bundles are now full layout/style sets (not color-only overlays). Each theme has separate screen and PDF stylesheet bundles:
source/stylesheets/themes/_theme-default.screen.scss
source/stylesheets/themes/_theme-default.pdf.scss
...
To create a new complete layout theme:
- Duplicate one theme pair in
source/stylesheets/themes/. - Rename both files to
_theme-yourname.screen.scssand_theme-yourname.pdf.scss. - Update layout structure/styles in those files.
- Add
theme-yournametoAVAILABLE_THEMESinlib/resume_selection.rb. - Build with
./build_resume.bash --theme theme-yourname.
The packaged result is written to dist/<user>/<resume-name>/. Its primary
entrypoints are index.html for the screen resume and pdf.html for the print
layout. If brief generation is enabled, corresponding named screen and PDF
brief files are included as well.
The primary deployment path is the GitHub Pages workflow in
.github/workflows/static.yml. A push to main validates all supported resume
definitions, runs the integration matrix, runs visual regression
coverage, builds johndoe/resume_sample, and deploys its packaged
artifact.
For a manual deployment using the Middleman Git deploy configuration:
./deploy_resume.bash
Optional profile override:
./deploy_resume.bash --resume-user johndoe --resume-name resume_sample
Optional theme override:
./deploy_resume.bash --theme theme-fern
The workflow sets RESUME_DEPLOYED_AT to the UTC deployment time. The screen
resume converts it to America/Detroit local time and displays the correct
EST or EDT abbreviation below the resume. The timestamp is intentionally
omitted from the PDF entrypoint.
bundle exec middleman
You can preview your resume at http://localhost:4567/
When using RVM, entering the project directory can pick up .ruby-version
and .ruby-gemset and use ruby-3.4.9@resume.
The helper scripts resolve bundle from your PATH by default. If needed,
override with:
BUNDLE_BIN=/absolute/path/to/bundle ./build_resume.bash
Install test dependencies:
bundle install
Run unit tests:
bundle exec rspec spec/lib
Validate the configured active resume without running a build:
./validate_resume.bash
Validate a selected resume with overrides:
./validate_resume.bash --resume-user johndoe --resume-name resume_sample
Validate the complete supported-resume matrix:
./validate_supported_resumes.bash
The matrix in data/resume_support.yml explicitly classifies every stored
data/<user>/resume*.yml definition as either supported or archived. Supported
definitions must pass the current schema validator. Archived definitions are
not buildable under the current schema and must include a reason. A new resume
definition must be added to one of these lists or matrix validation will fail.
The tracked matrix contains the supported John Doe example.
Run shell script tests:
./spec/shell/run_shell_tests.bash
Run all tests (integration test is skipped by default):
bundle exec rspec
Run integration smoke test:
RUN_INTEGRATION=1 bundle exec rspec spec/integration/build_smoke_spec.rb
The integration suite runs the full Cartesian build matrix: every resume listed
as supported in data/resume_support.yml, every theme in
ResumeSelection::AVAILABLE_THEMES, and brief generation both enabled and
disabled. Each build verifies the screen and PDF entrypoints, theme CSS, and
brief artifact behavior. This matrix also runs in the GitHub Pages workflow
before the deployed resume is built.
Run visual regression coverage after installing the Node and Python test
dependencies (npm ci and pip install -r requirements-visual.txt):
RUN_VISUAL=1 bundle exec rspec spec/visual/visual_regression_spec.rb
Visual coverage compares desktop screenshots for every supported theme, a
mobile-width screenshot, and the first rendered print/PDF page against the PNG
baselines in spec/visual/baselines/. It also renders every generated PDF page
under tmp/pdfs/visual-regression/ and checks the expected page count, text
bounds, rendered content, and unexpected blank pages.
The screenshots currently render the active resume rather than a fixed test-only content fixture. Normal resume edits can therefore change wrapping, document height, or PDF pagination and cause an intentional visual failure. Review the generated images before updating baselines; do not update them automatically merely to make the test pass.
After intentionally changing layout, styles, or resume content, inspect the current images and update the committed baselines with:
RUN_VISUAL=1 UPDATE_VISUAL=1 bundle exec rspec spec/visual/visual_regression_spec.rb
Set VISUAL_CHROME_BIN, VISUAL_NODE_BIN, or VISUAL_PYTHON_BIN when those
executables are not discoverable from their standard locations. Failed CI runs
upload current screenshots and rendered PDF pages as diagnostic artifacts.
You can run a local-only editor UI for YAML data files (jobs, summaries, resume definitions, and the active-resume selection) without exposing data to any external service.
Install Node dependencies:
npm ci
Start the local editor:
npm run editor:start
Open in browser:
http://127.0.0.1:4310
The editor only reads/writes files inside data/ and currently lists:
jobs*.ymlfiles under each user folder- files under each user's
summaries/folder
Editor modes:
Structured: form-based editing for jobs, summaries, resumes, and active selectionRaw YAML: direct text editing for full control
The structured resume editor uses the selected user's real catalogs to populate layouts, themes, summaries, job files and IDs, links, and skills. It edits PDF settings, contact information, ordered job references, link references, skill groups, and education entries. The active-resume form selects a valid user and resume definition and controls brief generation. Sections not represented by a form are retained unchanged during structured saves.
The structured job editor supports searching by job ID, title, or company;
editing all job fields currently used by the repository (id, include,
brief, title, company, location, dates, and description); duplicating jobs
with a generated unique ID; reordering jobs; and guarded deletion. Optional
include and brief values can be explicitly unset, blank locations are stored
as null, and unrecognized job fields are retained during structured saves.
Validation rejects missing required job fields and duplicate job IDs.
Before either mode saves, the editor parses the candidate YAML and validates a
temporary copy against the complete supported-resume matrix. Invalid content is
reported without changing the source file. A successful save first copies the
previous version to .local-editor-backups/<timestamp>/ and then replaces the
source atomically. Backups are local and gitignored.
The editor marks unsaved changes in the browser title and warns before file, category, or mode changes, reloads, and browser navigation. Use Validate to check without saving and Revert to reload the version currently on disk.
Run the editor API and headless-browser tests with:
npm run editor:test
To create/update your resume, edit data/active_resume.yml and the selected
resume file under data/<user>/ (for example data/johndoe/resume_sample.yml).
All keys with a desc: | header can be Markdown formatted.
Every Middleman build and preview validates the effective active resume before
rendering. Validation checks required nested fields, referenced jobs, skills,
links and summaries, duplicate catalog IDs, and layout template files. All
problems are reported together with their source paths. Use
./validate_resume.bash for a faster validation-only check, or
./validate_supported_resumes.bash to validate every supported definition.
The GitHub Pages workflow runs the full supported-resume validation before it
builds the deployed resume.
Here is what it looks like:
contact_info:
name: Jonathan Doe
shortdesc: Web Designer, Director
email: example@example.com
phone: (313) - 867-5309
address:
- 123 Fake Street
- City, Country
desc: |
You can put Markdown in here [like this](http://daringfireball.net/projects/markdown/).Here is a description of each of the currently supported sections of a resume. A section is a content component that can be included in the resume YAML data file.
The following section types are currently supported:
- Headers
- Contact Info
- Links
- Summary
- Skills
- Jobs
- Education
- Certifications
- Projects
- Volunteering
- Languages
- Interests
This project uses generatePdf.rb to generate a PDF via the FreeConvert API.
Run it with:
ruby generatePdf.rb
No API key is required for the current FreeConvert endpoint. If an API key is needed for an account or endpoint later, it can be supplied without changing the script:
export FREECONVERT_API_KEY=your_api_key
By default, the command resolves the active resume, builds its PDF HTML, sends
that HTML to FreeConvert, saves the result to the resume's configured
pdf.source, and runs the build again so dist/ contains the new PDF. On
completion it prints the directory containing the saved source PDF.
Common environment overrides supported by the script:
FREECONVERT_SOURCE_PATH=build/pdf.html
FREECONVERT_SOURCE_URL=https://resume.timothyfisher.com/pdf.html # optional override
FREECONVERT_BUILD_BEFORE_CONVERT=true
FREECONVERT_PACKAGE_AFTER_CONVERT=true
FREECONVERT_OUTPUT_PATH=/tmp/converted-resume.pdf # optional intermediate path
FREECONVERT_POLL_INTERVAL_SECONDS=5
FREECONVERT_MAX_POLLS=120
FREECONVERT_OUTPUT_PATH is optional. When provided, the downloaded file is
copied back to pdf.source before packaging. When FREECONVERT_API_KEY is set,
it is sent as a bearer token; otherwise the authorization header is omitted.
GitHub Pages deployments use the committed pdf.source and do not call
FreeConvert on every push. If automated conversion is added later, store the
key as a GitHub Actions secret named FREECONVERT_API_KEY.
The PDF section is used to describe details of the resume PDF that will be generated.
pdf:
filename: TimothyFisher-Resume
source: TimothyFisher-Resume.pdf
useicons: true
role: developerfilename is the public path without the .pdf extension. source is resolved
relative to the project root and copied into the built resume artifact at that
public path. A configured source that does not exist causes validation/building
to fail so a broken PDF link is not deployed. All currently supported resume
definitions provide a PDF source.
The headers section allows you to specify the names of sections that will be used within the resume. For example, given the headers section shown below, the profile section will be labeled as 'Summary' and the jobs section will be labeled as "Experience".
headers:
profile: Summary
jobs: Experience
education: Education
skills: Skills
download: Download PDFThis section is used to provide basic contact info for the resume user.
contact_info:
name: Timothy Fisher
photo: false
email: timothyf@gmail.com
phone: (555) 555-1234
address:
street: 555 Springwells
city: Detroit
state: MI
postal_code: 48134links:
github: https://github.com/timothyf
linkedin: https://linkedin.com/in/timothyfisher/
twitter: http://twitter.com/tfishersummary:
developer:
I am a passionate developer and leader with nearly 30 years of industry experience in roles that include
both hands-on and leadership positions across organizations that range from small startups to large enterprises.
...
leader:
I am a passionate developer and leader with 29 years of software development experience in roles
including Chief Technology Officer, VP of Engineering, Chief Architect, and Director of Mobile Development,
along with many years of hands-on development experience.
...skills:
- Team Leadership & Management
- Microservices Architecture
- Amazon Web Services (AWS), Heroku, EngineYard
- Ruby, Rails, JavaScript, Node.js, React, ReactNative, Java, Swift, HTML, CSS- title: Senior Java Architect
company: LogicaCMG
brief: false
include: brief
location:
city: Southfield
state: MI
dates:
start: 2003, February
end: 2006, May
desc: |
Worked on a Web-based single login project for Ford Motor Company. Responsibilities include assisting with
architecture, analysis, design, coding, and testing. Environment consisted of Websphere Application Server
...
- title: Development Team Lead
company: MedCharge
brief: false
location:
city: Ann Arbor
state: MI
dates:
start: 2002, February
end: 2003, January
desc: |
Led the J2EE development team at MedCharge, a startup whose product was a health care application
used within the University of Michigan Medical Center. The product allows hospital staff to capture all
...education:
- name: University of Michigan
degree: B.S. Electrical Engineering
dates:
start: Sept 1986
end: May 1991
- name: Capella University
degree: M.S. Education
dates:
start: Sept 2001
end: May 2003