Ergograph
Ergograph (Greek ἔργον "work, deed" + γράφειν "to write": "the one that writes down your work") is a YAML-driven CV and dossier generator. From plain content files it produces ready-to-send PDFs: a CV, a project history, a skills matrix and a complete dossier, in any number of languages and variants (e.g. with/without an hourly rate).
The generator contains no personal data. All content and all build steering come from the outside via YAML files; the code only provides rendering, the theme and the PDF export.
How it works
config.yaml + content/<lang>.yaml -> HTML (theme "modern") -> PDF (Chrome headless)
config.yamlsteers the build: person, languages, variants, documents, output paths.- One content file per language (
content/de.yaml,content/en.yaml, …) with all texts, including section labels and document file names. - Chrome (headless) renders the HTML intermediate step to A4 PDFs, which then get page numbers and title/author metadata stamped in.
Installation
Requirements: Python ≥ 3.10 and Google Chrome or Chromium. Chrome is only needed for
the PDF step (ergograph build --html-only works without it) and is not installed by
pip — Ergograph looks for an existing installation (see chrome: below).
# as an isolated tool (recommended)
uv tool install ergograph
# or into the current environment
pip install ergograph
There are no extras to pick: page numbers and the ATS check are always included. Both dependencies (PyYAML and pypdf) are pure Python and together under 1 MB.
Quick start
cd examples/minimal/
ergograph validate # check config + content files
ergograph build # build everything (HTML + PDF)
ergograph build --html-only # HTML only, no Chrome
ergograph build --variant mit-stundensatz --lang de
The PDFs end up under pdf/<variant>/<language>/YYYY-MM-DD_<Name>_<document>_<language>.pdf. Older builds are kept side by side thanks to the date prefix (disable it with output.date_prefix: false).
Example output
The rendered example PDFs are committed per persona under examples/<name>/pdf/, e.g. the German CV or the comprehensive architect dossier.
ATS readability
The documents are built to be fully readable by applicant tracking systems: a real text layer (no text in images), reading order equal to content order, skill levels as numbers next to the bars, and PDF title/author metadata. Ergograph verifies this instead of assuming it — after every build it extracts the PDF text layer (pypdf, the same way ATS parsers read PDFs) and asserts that every content string from your YAML appears in it. Findings are reported as warnings; ergograph build --strict turns them into a build failure. Details in docs/SPEC.md (R15/D13).
The steering file config.yaml
person:
name: Alexandra Argyriou # appears in the header and in the PDF file names
# file_slug: Alexandra-Argyriou # optional, default: name with hyphens
theme: modern # bundled theme, or path to your own .css
level_max: 6 # maximum of the skill-bar scale
languages: [de, en]
variants: [mit-stundensatz, ohne-stundensatz]
documents: # list (for all languages) or mapping per language
de: [cv, projects, full]
en: [full]
content:
de: content/de.yaml
en: content/en.yaml
output:
html_dir: html
pdf_dir: pdf
date_prefix: true # date-stamped file names; false = stable names
# chrome: /path/to/chrome # optional; otherwise auto-detected
The content files
One YAML file per language with the sections title, tagline, labels, doc_names, contact, facts, languages, certs, top_skills, education, experience, publications, projects and skills. Empty lists hide the corresponding section. The format is specified in docs/SPEC.md.
Examples
Every example under examples/ is a fictional persona and ships with its rendered PDFs:
| Example | Shows |
|---|---|
minimal |
Small bilingual dossier with rate variants — also the test fixture |
software-architect |
Comprehensive bilingual freelance dossier: structured bullets, project period/org metadata, publications with summaries |
handwerker |
Master carpenter — trade CV with certificates and reference projects, no publications |
reporter |
Journalist — publications with summaries, investigative projects |
arzt |
Physician — clinical-academic CV with board certifications and studies |
buerokauffrau |
Office administrator — commercial CV with internal projects |
Variants are steered declaratively: an entry in facts with variants: [mit-stundensatz] only appears in that variant, all other facts appear everywhere.
facts:
- label: Availability
value: from October 2026
- label: Hourly rate
value: €110-150/h depending on task
variants: [mit-stundensatz]
Content values are trusted HTML fragments: write UTF-8 directly (ü, €, "…"), and use <a href="...">…</a> for inline links where needed.
Development
uv run pytest # test suite, no Chrome and no network needed
uvx pip-audit -r <(uv export --format requirements-txt --all-extras --no-dev --no-emit-project)
trivy fs --scanners vuln,secret,misconfig .
Every push runs the suite on Python 3.10–3.14, renders all examples, and scans
dependencies and sources (pip-audit, Trivy, CodeQL). Releases go to PyPI from a v*
tag via trusted publishing. Version history: CHANGELOG.md.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ergograph-1.0.0.tar.gz.
File metadata
- Download URL: ergograph-1.0.0.tar.gz
- Upload date:
- Size: 56.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5b2181d0f255470afdde9aea66b41b85dc3fee335c2b333ed3c33310c1e691e
|
|
| MD5 |
04e8bc37efdf8586b831a6a91587c620
|
|
| BLAKE2b-256 |
0b321210f0ad38c424683ec6f8bfd1e7dff1bfec70a4ec17c4e5df841c333f5b
|
Provenance
The following attestation bundles were made for ergograph-1.0.0.tar.gz:
Publisher:
release.yml on Supportlik/Ergograph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ergograph-1.0.0.tar.gz -
Subject digest:
f5b2181d0f255470afdde9aea66b41b85dc3fee335c2b333ed3c33310c1e691e - Sigstore transparency entry: 2533208154
- Sigstore integration time:
-
Permalink:
Supportlik/Ergograph@3bf981d860b8fcc5b3c7a02c0a7b38d587470c64 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/Supportlik
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3bf981d860b8fcc5b3c7a02c0a7b38d587470c64 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ergograph-1.0.0-py3-none-any.whl.
File metadata
- Download URL: ergograph-1.0.0-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9234fff4b2a7c242809abea75640f4b91412a4992bb43ad1449e2fe3e3da52d7
|
|
| MD5 |
d442245681ee48806d70694b7277b660
|
|
| BLAKE2b-256 |
17da72b21fe48f51a76cfc4eb91bb3d69cfb61c2466ccdd656246c50e46288cd
|
Provenance
The following attestation bundles were made for ergograph-1.0.0-py3-none-any.whl:
Publisher:
release.yml on Supportlik/Ergograph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ergograph-1.0.0-py3-none-any.whl -
Subject digest:
9234fff4b2a7c242809abea75640f4b91412a4992bb43ad1449e2fe3e3da52d7 - Sigstore transparency entry: 2533208805
- Sigstore integration time:
-
Permalink:
Supportlik/Ergograph@3bf981d860b8fcc5b3c7a02c0a7b38d587470c64 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/Supportlik
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3bf981d860b8fcc5b3c7a02c0a7b38d587470c64 -
Trigger Event:
push
-
Statement type: