Skip to main content

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

Project description

ResumeCraft

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

Use it as a Python library, CLI tool, or integrate into your web app (FastAPI, Django, Flask, etc.).

Features

  • JSON-driven — All resume content lives in a single JSON file, easy to version control
  • Auto bold keywords — Define a list of keywords and they get bolded automatically in all bullet points
  • Right-aligned dates — Company locations and durations are properly right-aligned using tab stops
  • Clickable hyperlinks — Email, LinkedIn, GitHub, and project links are real clickable hyperlinks
  • Smart page breaks — Section headers never get orphaned at the bottom of a page
  • Separate project sections — Professional projects and personal/open source projects in distinct sections
  • Tech stack tags — Italic grey tech stack line under each project
  • Pydantic validation — JSON is validated against strict data models before building
  • Custom section ordering — Control which sections appear and in what order
  • Watch mode — Auto-rebuild on file save
  • PDF output — Optional PDF conversion via docx2pdf
  • Auto-open — Open the generated file after building with --open

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]"

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:

{
  "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,
      "link": { "label": "GitHub", "url": "https://github.com/you/project" },
      "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"
    }
  ],
  "languages": "English - Native  |  Hindi - Professional",
  "style": {
    "font": "calibri",
    "color": "black",
    "spacing": "normal"
  },
  "section_order": [
    "summary",
    "experience",
    "professional_projects",
    "personal_projects",
    "skills",
    "education",
    "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
languages string No Language proficiencies
section_order string[] No Custom order of sections (omit for default). Only listed sections are rendered.
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

Available sections for section_order

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

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.4.0.tar.gz (68.3 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.4.0-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for resumecraft-0.4.0.tar.gz
Algorithm Hash digest
SHA256 c70998a8c521755563a68adee2bc7e48cc610a082737dc224cc1ccde932f9931
MD5 7b096077708e957c916cf56e9290850c
BLAKE2b-256 86afdc5811b4bc21e811ec9e2cfd1023b5b89d3031ee186d5a30882237941cf6

See more details on using hashes here.

Provenance

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

File metadata

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

File hashes

Hashes for resumecraft-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 606493feb3193c5140d9cd4ab7960b1d0c3cae340d9a6be2d63245a7db692699
MD5 6a43f11af598b3a4f07ed73e830bf21d
BLAKE2b-256 39a298d24df470249113cffb5a072ace7a0a298877a750dc397bb4d841097bbb

See more details on using hashes here.

Provenance

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