Skip to main content

ResumeCraft

PyPI version Python versions License: MIT Downloads

Build professional Word (.docx) and PDF resumes from a simple JSON file.

ResumeCraft is a Python resume/CV generator that takes JSON input and produces a polished Word document or PDF. Use it as a library, a CLI tool, or drop it into a web app (FastAPI, Flask, Django).

See the generated PDF (built from sample_resume.json) to get a feel for the formatting. Set style.ats = true for ATS-friendly output.

Features

  • Resume content lives in a single JSON file, easy to version control
  • Auto-bolds keywords across all bullet points
  • Right-aligned dates using proper tab stops
  • Clickable hyperlinks for email, LinkedIn, GitHub, and projects
  • Keeps section headings from getting orphaned at page breaks
  • Pydantic-validated JSON input
  • Custom section ordering and headings
  • Sections: experience, projects (with multi-link support), skills, education, certifications, awards, languages
  • Style presets: 7 fonts, 6 color themes, 3 spacing options
  • Watch mode with PDF output for live preview
  • Optional PDF export via docx2pdf
  • JSON schema for editor autocomplete

Installation

pip install resumecraft              # library + CLI
pip install resumecraft[pdf]         # + PDF export
pip install resumecraft[pdf,watch]   # + PDF export + watch mode
pip install resumecraft[all]         # everything

# Install the CLI globally
pipx install resumecraft
uv tool install resumecraft

# Or run without installing
uvx resumecraft build my-resume.json
uvx "resumecraft[all]" build my-resume.json --open

Quick Start

# 1. Generate a template
resumecraft init -o my-resume.json

# 2. Edit my-resume.json with your details

# 3. Build your resume (docx)
resumecraft build my-resume.json

# 4. Build a PDF with the same filename (my-resume.pdf)
resumecraft build my-resume.json --pdf

# 5. Build and open immediately
resumecraft build my-resume.json --pdf --open

# 6. Validate without building
resumecraft validate my-resume.json

# 7. Watch for changes and rebuild automatically (defaults to PDF)
resumecraft watch my-resume.json --open

CLI Reference

resumecraft --help                                Show all commands
resumecraft --version                             Show version
resumecraft init -o FILE                          Generate a blank JSON template
resumecraft build FILE [-o FILE] [--pdf] [--open]  Build .docx or .pdf from JSON
resumecraft validate FILE                         Validate JSON without building
resumecraft watch FILE [-o FILE] [--open]         Watch and rebuild on file changes

When -o is omitted from build, the output is named after the input file with a timestamp, e.g., my-resume_2026-04-01_03-45pm.docx.

When -o is omitted from watch, the output defaults to <input-name>.pdf. PDF viewers don't lock files, so changes appear instantly.

Use as a Library

from resumecraft import ResumeCraft

# Load from anywhere
rc = ResumeCraft.from_jsonfile("my-resume.json")
rc = ResumeCraft.from_yamlfile("my-resume.yaml")      # needs: pip install resumecraft[yaml]
rc = ResumeCraft.from_json('{"name": "John", ...}')   # JSON string
rc = ResumeCraft.from_yaml("name: John\n...")         # YAML string
rc = ResumeCraft.from_bytes(uploaded_bytes)           # raw bytes (uploads, request body)
rc = ResumeCraft.from_dict({"name": "John", ...})     # dict

# Export
rc.to_docx("resume.docx")            # save .docx
rc.to_pdf("resume.pdf")              # save .pdf  (needs: pip install resumecraft[pdf])
rc.to_docx_bytes()                   # docx as bytes (for streaming)
rc.to_pdf_bytes()                    # pdf as bytes
rc.to_dict()                         # back to a dict

# Discover the schema
ResumeCraft.sample()                 # sample dict with all fields
ResumeCraft.json_schema()            # JSON schema (for editor autocomplete)

FastAPI example

import io
from fastapi import FastAPI, UploadFile
from fastapi.responses import Response, StreamingResponse

from resumecraft import ResumeCraft

app = FastAPI()


@app.post("/resume/docx")
def generate_docx(data: dict):
    rc = ResumeCraft.from_dict(data)
    return StreamingResponse(
        io.BytesIO(rc.to_docx_bytes()),
        media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        headers={"Content-Disposition": "attachment; filename=resume.docx"},
    )


@app.post("/resume/pdf")
def generate_pdf(data: dict):
    return Response(
        ResumeCraft.from_dict(data).to_pdf_bytes(),
        media_type="application/pdf",
    )


@app.post("/resume/upload")
async def from_upload(file: UploadFile):
    rc = ResumeCraft.from_bytes(await file.read())
    return Response(rc.to_pdf_bytes(), media_type="application/pdf")

Flask example

import io
from flask import Flask, request, send_file

from resumecraft import ResumeCraft

app = Flask(__name__)


@app.post("/resume/docx")
def generate_docx():
    rc = ResumeCraft.from_dict(request.json)
    return send_file(
        io.BytesIO(rc.to_docx_bytes()),
        mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        download_name="resume.docx",
    )


@app.post("/resume/pdf")
def generate_pdf():
    pdf = ResumeCraft.from_dict(request.json).to_pdf_bytes()
    return send_file(io.BytesIO(pdf), mimetype="application/pdf", download_name="resume.pdf")

See the examples/ folder for more complete examples including Django.

Advanced usage

The Pydantic model and the renderer are available for power users who need more control:

import json
from pathlib import Path
from resumecraft.models import Resume
from resumecraft.builder import DocxBuilder

data = json.loads(Path("my-resume.json").read_text())
resume = Resume.model_validate(data)
DocxBuilder(resume).save("resume.docx")

JSON Structure

Run resumecraft init to generate a full template. Here's the structure:

{
  "$schema": "https://raw.githubusercontent.com/mdfarhankc/resumecraft/main/schema.json",
  "name": "Your Name",
  "contact": {
    "location": "City, Country",
    "email": "your@email.com",
    "phone": "+1-234-567-8900",
    "links": [
      { "label": "LinkedIn", "url": "https://linkedin.com/in/you" },
      { "label": "GitHub", "url": "https://github.com/you" }
    ]
  },
  "summary": "A brief professional summary...",
  "bold_keywords": ["FastAPI", "React", "PostgreSQL"],
  "experience": [
    {
      "company": "Company Name",
      "location": "City, Country",
      "title": "Your Title",
      "duration": "JAN 2023 - PRESENT",
      "bullets": ["What you did and the impact it had."]
    }
  ],
  "projects": [
    {
      "name": "Project Name",
      "subtitle": "| Description",
      "tech_stack": "Python, FastAPI",
      "link": null,
      "bullets": ["What you built."]
    }
  ],
  "professional_projects": [
    {
      "name": "Project Name",
      "subtitle": "| Location | Type",
      "tech_stack": "FastAPI, React, PostgreSQL",
      "link": null,
      "bullets": ["What you built."]
    }
  ],
  "personal_projects": [
    {
      "name": "Side Project",
      "subtitle": "| Personal Project",
      "tech_stack": null,
      "links": [
        { "label": "GitHub", "url": "https://github.com/you/project" },
        { "label": "Live Demo", "url": "https://project.example.com" }
      ],
      "bullets": ["What you built and why."]
    }
  ],
  "skills": [
    { "category": "Backend", "items": "Python (FastAPI, Django), Node.js" },
    { "category": "Frontend", "items": "React, TypeScript" }
  ],
  "education": [
    {
      "institution": "University Name",
      "degree": "Bachelor of Computer Science",
      "duration": "2019 - 2023"
    }
  ],
  "certifications": [
    {
      "name": "AWS Certified Developer",
      "issuer": "Amazon Web Services",
      "date": "2024",
      "link": { "label": "Verify", "url": "https://aws.amazon.com/verify" }
    }
  ],
  "awards": [
    {
      "title": "Employee of the Year",
      "issuer": "Acme Corp",
      "date": "2024",
      "description": "Recognized for outstanding contributions."
    }
  ],
  "languages": "English - Native  |  Hindi - Professional",
  "style": {
    "font": "calibri",
    "color": "black",
    "spacing": "normal"
  },
  "section_order": [
    "summary",
    "experience",
    "professional_projects",
    "personal_projects",
    "skills",
    "education",
    "certifications",
    "awards",
    "languages"
  ]
}

Field Reference

Field Type Required Description
name string Yes Full name displayed at the top
contact object Yes Location, email, phone, and links
summary string Yes Professional summary paragraph
bold_keywords string[] No Words to auto-bold in all bullet points
experience object[] No Work experience entries
projects object[] No Single unified projects section
professional_projects object[] No Client/employer projects (use with personal_projects for split sections)
personal_projects object[] No Side projects and open source work
skills object[] No Categorized skill lists
education object[] No Degrees and institutions
certifications object[] No Professional certifications with issuer, date, and optional verification link
awards object[] No Awards and achievements with title, issuer, date, and optional description
languages string No Language proficiencies
section_order string[] No Custom order of sections (omit for default). Only listed sections are rendered.
headings object No Custom section headings (e.g., {"summary": "ABOUT ME"})
style object No Styling options (font, color, spacing)

Style Options

Add a style object to customize the look of your resume:

{
  "style": {
    "font": "garamond",
    "color": "navy",
    "spacing": "compact"
  }
}
Option Choices Default
font calibri, arial, times, garamond, georgia, helvetica, cambria calibri
color black, navy, forest, maroon, slate, royal black
spacing compact, normal, relaxed normal
ats true, false false

Set "ats": true to strip tab stops, colored tech lines, and heading borders for cleaner parsing by applicant tracking systems.

Available sections for section_order

summary, experience, projects, professional_projects, personal_projects, skills, education, certifications, awards, languages

Custom headings

Override any section's heading text:

{
  "headings": {
    "summary": "ABOUT ME",
    "experience": "CAREER",
    "awards": "HONORS"
  }
}

Editor autocomplete (JSON schema)

Reference the schema in your JSON for autocomplete and validation in VS Code, IntelliJ, etc.:

{
  "$schema": "https://raw.githubusercontent.com/mdfarhankc/resumecraft/main/schema.json",
  "name": "Your Name",
  ...
}

Note: Use either projects for a single section, or professional_projects + personal_projects for two separate sections. If you use projects, include it in section_order - it's not part of the default order.

Project Structure

resumecraft/
├── pyproject.toml
├── README.md
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── schema.json                 # JSON schema (regenerate with: make schema)
├── examples/
│   ├── library.py              # Library usage
│   ├── web.py                  # FastAPI/Flask/Django pattern
│   ├── sample_resume.json
│   └── output/sample_resume.pdf
├── src/resumecraft/
│   ├── __init__.py
│   ├── craft.py                # ResumeCraft (entry point)
│   ├── cli.py                  # CLI commands
│   ├── builder.py              # DocxBuilder (slim, drives the rendering)
│   ├── sections.py             # Section classes + SECTION_REGISTRY
│   ├── render.py               # RenderContext + paragraph helpers
│   ├── models.py               # Pydantic data models
│   ├── styles.py               # font/color/spacing maps
│   └── utils.py                # low-level docx helpers (hyperlinks, borders)
└── tests/
    ├── fixtures/sample.json
    ├── test_models.py
    ├── test_builder.py
    ├── test_craft.py
    ├── test_cli.py
    └── test_utils.py

Development

git clone https://github.com/mdfarhankc/resumecraft.git
cd resumecraft
uv sync --extra dev

Run tests

uv run pytest

Build

uv build

This creates dist/resumecraft-x.x.x.tar.gz and dist/resumecraft-x.x.x-py3-none-any.whl.

Publish to PyPI

Create a GitHub release (e.g., v0.2.0) and the CI workflow will publish to PyPI automatically via trusted publishing.

License

MIT

Metadata

Release files for resumecraft 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for resumecraft 0.6.0
File Size Uploaded
resumecraft-0.6.0.tar.gz 375.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for resumecraft 0.6.0
File Interpreter ABI Platform
resumecraft-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 397.0 kB

Release files / resumecraft-0.6.0.tar.gz

Download URL resumecraft-0.6.0.tar.gz
Size 375.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8ca2368eeb7bec1c92c80ee033d7862b4aa3815d8165999609b930b4a4e1b0e7
BLAKE2b-256 checksum
How to use checksums
b4bbc5d424b8c378ba84f30640e3f3b669e94823e3c477165127c4ef1fb59a8f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 25, 2026.

Transparency log

Release files / resumecraft-0.6.0-py3-none-any.whl

Download URL resumecraft-0.6.0-py3-none-any.whl
Size 21.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dc5719432d4511c250cb2a3299dc70309742c1a951137d6ada8e8273757b602e
BLAKE2b-256 checksum
How to use checksums
50033140be8c2d592b6d4ef38b488b41376d02ccb1593c0147ccbafc0892fdf5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page