readwright
Render GitHub READMEs from Jinja2 templates with badge and screenshot helpers.
- Installation
- Quick start
- Template helpers
- Configuration
- pre-commit and GitHub Actions
- Contributing
- License
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e3bf7e18af2bec03d2f734f436472fa7f0cf35c5528ccc700dc82b8f9e639aa
|
|
| MD5 |
16f9c70a46ba095993176e4bec40305f
|
|
| BLAKE2b-256 |
4d1520a685710b301c41e05426737013cff845440d8323884e876973eb560a4b
|
Provenance
The following attestation bundles were made for readwright-0.3.0.tar.gz:
Publisher:
release.yml on Garulf/readwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
readwright-0.3.0.tar.gz -
Subject digest:
4e3bf7e18af2bec03d2f734f436472fa7f0cf35c5528ccc700dc82b8f9e639aa - Sigstore transparency entry: 2533476945
- Sigstore integration time:
-
Permalink:
Garulf/readwright@646352f70db3c8703e3da6f9f73c635848066e71 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Garulf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@646352f70db3c8703e3da6f9f73c635848066e71 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21027765d6c9780b3f8b6818b4505b2e4f73051fd695921977c58ab8951a0012
|
|
| MD5 |
c1fe9f8fc8904022a0fc9306988c136b
|
|
| BLAKE2b-256 |
d84ac7c97eafe4e3c685ede003996e6b0d767e375317e643334b7991e56a3150
|
Provenance
The following attestation bundles were made for readwright-0.3.0-py3-none-any.whl:
Publisher:
release.yml on Garulf/readwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
readwright-0.3.0-py3-none-any.whl -
Subject digest:
21027765d6c9780b3f8b6818b4505b2e4f73051fd695921977c58ab8951a0012 - Sigstore transparency entry: 2533477026
- Sigstore integration time:
-
Permalink:
Garulf/readwright@646352f70db3c8703e3da6f9f73c635848066e71 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Garulf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@646352f70db3c8703e3da6f9f73c635848066e71 -
Trigger Event:
push
-
Statement type: