ATS Resume Maker
Produce truthful, ATS-parseable resumes as canonical Markdown and a gated PDF delivery. Input is Markdown only — PDF extract is deferred (convert offline). Content rules run on Markdown; page count and layout truth come from the generated PDF and page images—not character estimates or vendor scores. Factual adds in a change manifest require evidence; never invent metrics or skills.
IRON LAWS
1. Never invent metrics, titles, employers, dates, credentials, or skills.
2. Never overwrite the user's source file; work only in run dirs / copies.
3. final/ is populated only when required gates pass (or visual is skipped).
4. Page count = actual PDF pages only. Never treat char/word count as page limit.
5. Do not claim visual pass without reviewing every previews/page-NN.png.
6. No DOCX. No runtime package installs during build. No silent renderer switch.
7. Spirit equals letter: "almost pass" is a fail until issues are fixed or waived.
When to use
- Create or rewrite a resume in the controlled Markdown dialect
- Tailor an existing resume with an approved change manifest
- Validate Markdown, PDF, or a full multi-gate build
- Inspect page previews and complete visual review
When not to use
- DOCX / Word-only deliverables
- Scraping or gaming online ATS scoring websites
- Designing multi-column creative portfolios as the ATS artifact
- PDF extraction from scanned/legacy PDFs (P0: not implemented—provide Markdown)
Quick start
pip install -e ".[dev]" # once per environment
ats-resume build path/to/resume.md -o outputs/
# With Gate B (source + evidenced changes required together):
ats-resume build path/to/updated.md -o outputs/ \
--source path/to/base.md --changes path/to/change_manifest.yaml
# CI without agent visual review:
ats-resume build path/to/resume.md -o outputs/ --skip-visual-review
Config: auto-loads resume.config.yaml from cwd / parents / package repo when
--config is omitted; or pass --config PATH. Run layout:
outputs/<slug>/<run-id>/
source/ work/ final/ previews/ reports/
Primary command path is ats-resume build. Prefer the CLI over re-implementing checks.
Gates (delivery blockers)
| Gate | Name | What | CLI |
|---|---|---|---|
| A | markdown | Structure + content (section-aware) | validate-markdown |
| B | semantic_diff | Unexpected changes vs source + manifest | diff |
| C | Pages, size, extractable text, links | validate-pdf |
|
| D | visual | Agent/human review of every page image | via build + visual_review.json |
Preflight (Python, templates, WeasyPrint) and render failures also block delivery.
Advisory issues may remain after a pass; critical (and important in strict) fail.
Agent checklist
- [ ] Canonical Markdown (see references/canonical_markdown.md + resume_template.md)
- [ ] Facts only from user/source; additions evidenced in change_manifest when using Gate B
- [ ] ats-resume build (or stepwise validate → render → validate-pdf → render-images)
- [ ] Read reports/validation.json + reports/validation_report.md
- [ ] Fix issues by code (references/validation_issue_codes.md); re-run build
- [ ] Open every previews/page-NN.png; write reports/visual_review.json with matching pdf_sha256
- [ ] Confirm final/ has *_Resume.md and *_Resume.pdf only after overall pass
- [ ] Deliver final artifacts + report summary; do not claim pass if final/ empty
Correction loop (agent-driven)
- Run
ats-resume build …(or isolated gate commands). - If exit ≠ 0: read
reports/validation.jsonissues (code,severity,gate). - Fix Markdown (or template/config)—never invent facts to silence DIFF_*.
- Re-run
buildafter each fix.workflow.max_attempts(default 3) is advisory for agents only — the package does not loop or retry internally. Escalate if stuck after that budget. - When PDF + previews exist: complete visual review → re-run build with
--visual-report path/to/visual_review.json(or place file underreports/). - Stop only when status is pass and
final/is populated (or visual legitimately skipped).
Source is always preserved under source/ (immutable base when --source is
set; otherwise a copy of the input).
Commands and exit codes
| Command | Role |
|---|---|
ats-resume build UPDATED.md -o DIR |
Full pipeline; --source required with --changes; optional --visual-report, --skip-visual-review, --config, --candidate |
ats-resume validate-markdown RESUME.md |
Gate A |
ats-resume diff SOURCE.md UPDATED.md -m MANIFEST.yaml |
Gate B (factual ops need evidence) |
ats-resume render RESUME.md -o out.pdf |
WeasyPrint render (**bold** → strong) |
ats-resume validate-pdf PDF --source RESUME.md |
Gate C (content inventory + links) |
ats-resume render-images PDF -o DIR |
PNG previews |
ats-resume report --run-dir RUN |
Summarize existing run |
ats-resume extract … |
Deferred — Markdown-only product; convert PDF offline (exit 2) |
| Code | Meaning |
|---|---|
| 0 | Success / pass |
| 1 | Validation failure |
| 2 | Invalid args / extract not implemented |
| 3 | Dependency or renderer failure |
| 4 | Visual incomplete/failed (other gates ok) |
| 5 | Internal error |
References
Load on demand (one level deep):
| File | Use |
|---|---|
references/ats_guidelines.md |
Severity model, MD vs PDF rules, style heuristics |
references/canonical_markdown.md |
Controlled Markdown dialect (parser contract) |
references/resume_template.md |
Copy-paste template matching the dialect |
references/visual_validation.md |
Gate D checklist + visual_review.json schema |
references/validation_issue_codes.md |
All MD_*/DIFF_*/PDF_*/VISUAL_*/PREFLIGHT_* codes |
references/troubleshooting.md |
WeasyPrint/Windows, install, empty final/ |
If you are editing this skill itself, also read references/skill_authoring_standards.md.
Red flags
- Skipping visual review then claiming delivery success
- Using char-count “page estimate” as a hard error
- Reintroducing DOCX or
generate_docx.js/ LibreOffice paths - Global word-repetition caps or treating em dashes as universal ATS blockers
- Inventing keywords/metrics to pass Gate B or impress a score site
- Installing packages mid-build or switching renderers without config change
Rationalizations
| Excuse | Reality |
|---|---|
| “Char count says ~2 pages” | Only PDF page count gates (PDF_PAGE_LIMIT) |
| “Em dash is fine / always fatal” | Configurable style (em_dash); default often ignore—not a universal ATS parse fail |
| “Bold everything for ATS” | Selective bold is advisory presentation, not a keyword signal |
| “Close enough on visual” | Incomplete review → exit 4; no final/ |
| “Need DOCX for ATS” | Text PDF is the delivery; DOCX is out of scope |
| “Add skills from the JD” | Only with evidence + manifest; never invent |
| “Title has I—pronoun fail” | Pronoun scan skips titles; Roman I in job titles is not first person |
| “Short certs look weak” | Short certification lines are valid; do not pad with filler |
Delivery artifacts
On pass, under outputs/<slug>/<run-id>/:
| Path | Content |
|---|---|
final/*_Resume.md |
Validated Markdown |
final/*_Resume.pdf |
Validated PDF |
previews/page-NN.png |
One image per PDF page |
reports/validation.json |
Gate results + issues |
reports/validation_report.md |
Human-readable summary |
reports/semantic_diff.json |
Gate B detail (when run) |
reports/visual_review.json |
Gate D (when required) |
source/source.md |
Preserved input |
work/ |
Intermediate HTML/PDF/updated.md |
Do not treat the run as delivered if final/ is empty.
Non-goals
- DOCX generation or round-trip
- Proprietary online ATS scores as ground truth
- Automated computer-vision visual pass (agent/human checklist only)
- PDF→Markdown extraction (
extractexits 2; convert PDF offline) - Character-count page limits as hard errors
- Inventing content to satisfy keyword density