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 samples to get a feel for the formatting:

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

As a library

pip install resumecraft                # Core library only
pip install resumecraft[pdf]           # + PDF output support

As a CLI tool

pip install resumecraft[cli]           # Core + CLI
pip install resumecraft[cli,pdf,watch] # Everything
pip install resumecraft[all]           # Same as above

# Or install globally
pipx install "resumecraft[cli]"
uv tool install "resumecraft[cli]"

Run without installing

Use uvx to run the CLI in an ephemeral environment:

uvx "resumecraft[cli]" 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
resumecraft build my-resume.json

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

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

# 6. 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] [--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 file is automatically named with a timestamp, e.g., 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

# From a JSON file
rc = ResumeCraft.from_json("my-resume.json")
rc.to_docx("resume.docx")

# From a dict
rc = ResumeCraft({"name": "John Doe", "contact": {...}, "summary": "..."})
rc.to_docx("resume.docx")

# From a JSON string
rc = ResumeCraft('{"name": "John Doe", ...}')

# Get bytes (for web frameworks)
content = rc.to_bytes()

# Export as PDF (requires: pip install resumecraft[pdf])
rc.to_pdf("resume.pdf")

# Export back to dict
data = rc.to_dict()

# Get a sample template to see all fields
sample = ResumeCraft.sample()

# Get JSON schema for editor validation
schema = ResumeCraft.json_schema()

FastAPI example

import io
import tempfile
from fastapi import FastAPI
from fastapi.responses import FileResponse, StreamingResponse
from resumecraft import ResumeCraft

app = FastAPI()

@app.post("/resume/docx")
def generate_docx(data: dict):
    rc = ResumeCraft(data)
    return StreamingResponse(
        io.BytesIO(rc.to_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):
    rc = ResumeCraft(data)
    tmp = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
    rc.to_pdf(tmp.name)
    return FileResponse(tmp.name, filename="resume.pdf", media_type="application/pdf")

Flask example

import io
import tempfile
from flask import Flask, request, send_file
from resumecraft import ResumeCraft

app = Flask(__name__)

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

@app.post("/resume/pdf")
def generate_pdf():
    rc = ResumeCraft(request.json)
    tmp = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False)
    rc.to_pdf(tmp.name)
    return send_file(tmp.name, mimetype="application/pdf", download_name="resume.pdf")

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

Advanced usage

You can also use the lower-level Resume and DocxBuilder classes directly:

from resumecraft import Resume, DocxBuilder

resume = Resume.from_json("my-resume.json")
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/resumecraft-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/resumecraft-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
├── LICENSE
├── examples/
│   ├── basic.py            # Simple usage
│   ├── from_json.py        # Build from JSON file
│   ├── styled.py           # Custom fonts, colors, spacing
│   ├── fastapi_app.py      # FastAPI REST API
│   ├── flask_app.py        # Flask REST API
│   └── django_view.py      # Django views
├── src/resumecraft/
│   ├── __init__.py        # Public API (ResumeCraft, Resume, DocxBuilder)
│   ├── craft.py           # ResumeCraft facade (simple high-level API)
│   ├── cli.py             # Typer CLI commands (build, validate, init, watch)
│   ├── models.py          # Pydantic data models
│   ├── builder.py         # DocxBuilder - converts models to .docx
│   ├── styles.py          # Styling constants (fonts, sizes, colors, margins)
│   └── utils.py           # Helpers (hyperlinks, keep_with_next, bold patterns)
└── tests/
    ├── fixtures/
    │   └── sample.json    # Sample resume for tests
    ├── 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.5.0.tar.gz (568.5 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.5.0-py3-none-any.whl (19.9 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for resumecraft-0.5.0.tar.gz
Algorithm Hash digest
SHA256 f6b6b00727b4b798274eb0e3d14bd4fad58e4c50dd8164be2195ac552219dc53
MD5 7576b93de2971d10072dc18b4c8cd236
BLAKE2b-256 ac4fba4b4ed676863aa0aa68555b34c3454ccd365282dbe219499a2057fc96f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumecraft-0.5.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.5.0-py3-none-any.whl.

File metadata

  • Download URL: resumecraft-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 19.9 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.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 247f253195d3406e5dac75b43ef2e5a9844a7fa94abbfc6c765204b45d56c093
MD5 b51c28498e3817c3b7a2da0aa54d8c57
BLAKE2b-256 3a3c893da83c39a302114351cd94ceeb1b08cbf6f803a23d712df0db35070036

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumecraft-0.5.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