Skip to main content

readwright

Render GitHub READMEs from Jinja2 templates with badge and screenshot helpers.

PyPI Python License CI pre-commit Ruff

Installation

pip install readwright

Or with uv:

uv tool install readwright

Quick start

cd my-repo
readwright init      # writes readme.yaml + README.md.j2 (autodetects owner/repo, name, license, ...)
readwright render    # writes README.md (--watch to re-render on change, -o - for stdout)
readwright check     # exit 1 with a diff if README.md is stale (use as a pre-commit hook / in CI)
readwright badges    # list badge presets
readwright blocks    # list overridable blocks and partials
readwright show partials/install.md.j2   # print a packaged template to copy and tweak

Already have a README? readwright init --from-readme moves its body into the template so nothing is lost, then takes over README.md. Prefer pyproject.toml? readwright init --pyproject writes the config to [tool.readme].

README.md.j2 extends the packaged base.md.j2 and overrides only what it needs:

{% extends "base.md.j2" %}

{% block usage %}
## Usage

{{ screenshot("main", width=600) }}

Run `{{ project.name }} --help`.
{% endblock %}

See examples/ for a kitchen-sink project using every helper, plus Minecraft mod, HACS card and Flow Launcher plugin examples.

Template helpers

Helper Result
badge("pypi"), badge("ci", workflow="test.yml") Preset badge built from repo metadata
shield("Discord", "chat", "5865F2", link=...) Custom shields.io static badge
badges() / donate_badges() All badges from badges: / donate: in config
screenshot("main", alt=..., width=...) Finds docs/screenshots/main.{png,jpg,gif,webp,svg}; main-dark.* + main-light.* become a theme-aware pair
screenshots(columns=2) Gallery table of every image in the screenshots dir
image("path/or/url", "alt", width=...) Explicit image, no discovery
screenshots(order=[...], captions={...}, subdir=...) Control gallery order/captions (or drop a captions.yaml in the folder)
toc(), toc(1, 2) Table of contents from the headings below it (min/max level)
changelog(n=1) Newest n entries of CHANGELOG.md
project.*, vars.* Repo metadata and free-form config values
cli_help("mytool --help") Runs the command and fences its output (needs allow_exec: true)
include_file(path), code_block(path), snippet(path, start, end) Pull a file, a fenced file, or a marked region into the README
config_table(path, section=...), env_table(".env.example"), entry_points_table() Markdown tables from YAML/TOML/JSON, env files, [project.scripts]
gh_link("issues", "Issues"), spdx_link(), my_ha_link("hacs_repository", owner=..., repository=...) Repo-relative GitHub links, SPDX license link, My Home Assistant buttons
callout("tip", text), details(summary, body), center(html), columns([...]) GitHub alerts, collapsibles, centered blocks, side-by-side cells
logo(width=120), video("demo"), contributors([...]) Theme-aware logo from docs/logo.*, video/gif embed, avatar grid
unsplash("photo-1518…", credit="Name", user="handle", width=1000, height=280) Hero image from Unsplash's CDN with the required attribution line; banner: in config puts one above the title
flow_install_cmd(), mc_versions(), mod_dependencies(), related_repos() Flow Launcher / Minecraft mod / related-repo tables
git_sha(), git_tag(), today() Build metadata (these change between renders, so check will flag them)

To add a badge to the top row without touching the config list, fill the badges_extra hook (there is a donate_extra too):

{% block badges_extra %} {{ shield("docs", "latest", "success", link=gh_link("wiki")) }}{% endblock %}

Badge presets: pypi, pypi-downloads, python, license, ci, codecov, npm, github-release, github-stars, pre-commit, ruff, version, modrinth, curseforge, hacs, ha-version, plus donation presets kofi, buymeacoffee, github-sponsors, patreon, paypal. Add your own under badges_custom; set badges_style: flat-square (or pass style= to any badge helper) to restyle them all.

Blocks in base.md.j2: header, badges, donate, toc, screenshots, install, usage, extra, contributing, license. Any packaged partial can be shadowed by a file of the same name under templates/partials/ in the repo (or ~/.config/readwright/templates/ for all your repos).

Image helpers emit plain markdown by default (dark/light pairs use GitHub's #gh-light-mode-only/#gh-dark-mode-only fragments instead of <picture>), and only fall back to HTML when you ask for something markdown can't do, like a width=. Set screenshots.style: html to always get <img>/<picture>/<table> output, or pass html=True to unsplash()/banner:.

Configuration

readme.yaml in the repo root (or [tool.readme] in pyproject.toml); see examples/config-only/readme.yaml for every key, annotated. Everything is optional; metadata is autodetected from the git remote, the LICENSE file and whichever manifest the project has: pyproject.toml, package.json, Cargo.toml, go.mod, *.csproj, Gradle (gradle.properties mod metadata for Minecraft mods), hacs.json or a Flow Launcher plugin.json. The install section adapts to the project type.

template: README.md.j2
templates: [../shared-readme-templates, "pkg:my_org_templates"]   # extra template search paths
output: README.md
strict: false                     # missing screenshot -> error instead of warning
allow_exec: false                 # let cli_help() run commands during render
badges_style: flat-square         # optional shields.io style for every badge
related: [{repo: other-tool, description: Sibling project}]   # for related_repos()
banner: {unsplash: photo-1518770660439-4636190af475, credit: Alexandre Debiève, user: alexkixa}
screenshots: {dir: docs/screenshots, width: 720, style: markdown}   # style: html for width/alignment
badges: [pypi, python, license, {preset: ci, workflow: test.yml}, {shield: {label: Docs, message: latest, color: success}}]
badges_custom:
  discord: {label: Discord, message: chat, color: 5865F2, link: https://discord.gg/xyz}
donate: [kofi, github-sponsors]
donate_handles: {kofi: yourname, github-sponsors: yourname}
project: {name: ..., owner: ..., repo: ..., tagline: ..., pypi: ..., npm: ..., license: ..., ci_workflow: ...}
vars: {anything: you like}

Put the values you repeat across repos (donation handles, owner, custom badges) in ~/.config/readwright/config.yaml; readwright init bakes them into each new readme.yaml so rendering stays reproducible in CI. readwright render --user-config merges them ad hoc.

pre-commit and GitHub Actions

# .pre-commit-config.yaml
- repo: https://github.com/Garulf/readwright
  rev: v0.3.0
  hooks:
    - id: readwright-check
# .github/workflows/ci.yml
- uses: Garulf/readwright@v0.3.0
  with:
    mode: check     # or render

Contributing

Issues and pull requests are welcome at Garulf/readwright.

License

MIT

Download files

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

Source Distribution

readwright-0.3.0.tar.gz (488.0 kB view details)

Uploaded Source

Built Distribution

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

readwright-0.3.0-py3-none-any.whl (34.3 kB view details)

Uploaded Python 3

File details

Details for the file readwright-0.3.0.tar.gz.

File metadata

  • Download URL: readwright-0.3.0.tar.gz
  • Upload date:
  • Size: 488.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for readwright-0.3.0.tar.gz
Algorithm Hash digest
SHA256 4e3bf7e18af2bec03d2f734f436472fa7f0cf35c5528ccc700dc82b8f9e639aa
MD5 16f9c70a46ba095993176e4bec40305f
BLAKE2b-256 4d1520a685710b301c41e05426737013cff845440d8323884e876973eb560a4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for readwright-0.3.0.tar.gz:

Publisher: release.yml on Garulf/readwright

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

File details

Details for the file readwright-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: readwright-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 34.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for readwright-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 21027765d6c9780b3f8b6818b4505b2e4f73051fd695921977c58ab8951a0012
MD5 c1fe9f8fc8904022a0fc9306988c136b
BLAKE2b-256 d84ac7c97eafe4e3c685ede003996e6b0d767e375317e643334b7991e56a3150

See more details on using hashes here.

Provenance

The following attestation bundles were made for readwright-0.3.0-py3-none-any.whl:

Publisher: release.yml on Garulf/readwright

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 Sentry Error logging StatusPage Status page