Skip to main content

Generate professional resumes from JSON with DOCX/PDF export, custom styling, and web framework support.

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

resumecraft-0.6.0.tar.gz (375.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

resumecraft-0.6.0-py3-none-any.whl (21.2 kB view details)

Uploaded Python 3

File details

Details for the file resumecraft-0.6.0.tar.gz.

File metadata

  • Download URL: resumecraft-0.6.0.tar.gz
  • Upload date:
  • Size: 375.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for resumecraft-0.6.0.tar.gz
Algorithm Hash digest
SHA256 8ca2368eeb7bec1c92c80ee033d7862b4aa3815d8165999609b930b4a4e1b0e7
MD5 b0a7887fccf001f586da9ffaccba3e89
BLAKE2b-256 b4bbc5d424b8c378ba84f30640e3f3b669e94823e3c477165127c4ef1fb59a8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumecraft-0.6.0.tar.gz:

Publisher: publish.yml on mdfarhankc/resumecraft

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file resumecraft-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: resumecraft-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 21.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for resumecraft-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dc5719432d4511c250cb2a3299dc70309742c1a951137d6ada8e8273757b602e
MD5 e7f6ab4a81db26caf4b0ea92359f0702
BLAKE2b-256 50033140be8c2d592b6d4ef38b488b41376d02ccb1593c0147ccbafc0892fdf5

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumecraft-0.6.0-py3-none-any.whl:

Publisher: publish.yml on mdfarhankc/resumecraft

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page