readwright 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. readwright-0.4.0/.agents/skills/readwright/SKILL.md +165 -0
  2. readwright-0.4.0/.agents/skills/readwright/helpers.md +130 -0
  3. readwright-0.4.0/AGENTS.md +85 -0
  4. readwright-0.4.0/CLAUDE.md +18 -0
  5. {readwright-0.3.0 → readwright-0.4.0}/PKG-INFO +20 -4
  6. {readwright-0.3.0 → readwright-0.4.0}/README.md +19 -3
  7. {readwright-0.3.0 → readwright-0.4.0}/README.md.j2 +16 -1
  8. {readwright-0.3.0 → readwright-0.4.0}/examples/README.md +7 -5
  9. readwright-0.4.0/examples/dotnet-tool/DotTool.csproj +10 -0
  10. readwright-0.4.0/examples/dotnet-tool/README.md +20 -0
  11. readwright-0.4.0/examples/dotnet-tool/readme.yaml +7 -0
  12. readwright-0.4.0/examples/go-cli/README.md +20 -0
  13. readwright-0.4.0/examples/go-cli/go.mod +3 -0
  14. readwright-0.4.0/examples/go-cli/readme.yaml +6 -0
  15. readwright-0.4.0/examples/node-cli/README.md +20 -0
  16. readwright-0.4.0/examples/node-cli/package.json +7 -0
  17. readwright-0.4.0/examples/node-cli/readme.yaml +2 -0
  18. readwright-0.4.0/examples/rust-cli/Cargo.toml +6 -0
  19. readwright-0.4.0/examples/rust-cli/README.md +20 -0
  20. readwright-0.4.0/examples/rust-cli/readme.yaml +7 -0
  21. {readwright-0.3.0 → readwright-0.4.0}/pyproject.toml +4 -1
  22. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/changelog.py +3 -1
  23. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/cli.py +57 -10
  24. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/config.py +2 -2
  25. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/helpers.py +22 -8
  26. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/images.py +1 -1
  27. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/metadata.py +10 -9
  28. {readwright-0.3.0 → readwright-0.4.0}/tests/test_cli.py +29 -0
  29. {readwright-0.3.0 → readwright-0.4.0}/tests/test_examples.py +21 -14
  30. {readwright-0.3.0 → readwright-0.4.0}/uv.lock +1 -1
  31. readwright-0.3.0/examples/flow-plugin/README.md +0 -26
  32. readwright-0.3.0/examples/flow-plugin/README.md.j2 +0 -7
  33. readwright-0.3.0/examples/flow-plugin/plugin.json +0 -1
  34. readwright-0.3.0/examples/flow-plugin/readme.yaml +0 -2
  35. readwright-0.3.0/examples/ha-card/README.md +0 -34
  36. readwright-0.3.0/examples/ha-card/README.md.j2 +0 -23
  37. readwright-0.3.0/examples/ha-card/docs/example.yaml +0 -2
  38. readwright-0.3.0/examples/ha-card/hacs.json +0 -1
  39. readwright-0.3.0/examples/ha-card/package.json +0 -1
  40. readwright-0.3.0/examples/ha-card/readme.yaml +0 -2
  41. readwright-0.3.0/examples/minecraft-mod/README.md +0 -32
  42. readwright-0.3.0/examples/minecraft-mod/README.md.j2 +0 -9
  43. readwright-0.3.0/examples/minecraft-mod/build.gradle +0 -1
  44. readwright-0.3.0/examples/minecraft-mod/gradle.properties +0 -6
  45. readwright-0.3.0/examples/minecraft-mod/readme.yaml +0 -10
  46. readwright-0.3.0/examples/minecraft-mod/src/main/resources/META-INF/neoforge.mods.toml +0 -8
  47. {readwright-0.3.0 → readwright-0.4.0}/.github/workflows/ci.yml +0 -0
  48. {readwright-0.3.0 → readwright-0.4.0}/.github/workflows/release.yml +0 -0
  49. {readwright-0.3.0 → readwright-0.4.0}/.gitignore +0 -0
  50. {readwright-0.3.0 → readwright-0.4.0}/.pre-commit-config.yaml +0 -0
  51. {readwright-0.3.0 → readwright-0.4.0}/.pre-commit-hooks.yaml +0 -0
  52. {readwright-0.3.0 → readwright-0.4.0}/.python-version +0 -0
  53. {readwright-0.3.0 → readwright-0.4.0}/LICENSE +0 -0
  54. {readwright-0.3.0 → readwright-0.4.0}/action.yml +0 -0
  55. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/README.md +0 -0
  56. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/docs/screenshots/CREDITS.md +0 -0
  57. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/docs/screenshots/captions.yaml +0 -0
  58. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/docs/screenshots/dashboard.jpg +0 -0
  59. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/docs/screenshots/editor-dark.jpg +0 -0
  60. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/docs/screenshots/editor-light.jpg +0 -0
  61. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/pyproject.toml +0 -0
  62. {readwright-0.3.0 → readwright-0.4.0}/examples/config-only/readme.yaml +0 -0
  63. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/.all-contributorsrc +0 -0
  64. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/.env.example +0 -0
  65. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/CHANGELOG.md +0 -0
  66. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/LICENSE +0 -0
  67. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/README.md +0 -0
  68. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/README.md.j2 +0 -0
  69. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/demo_tool/__init__.py +0 -0
  70. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/demo_tool/cli.py +0 -0
  71. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/logo.svg +0 -0
  72. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/CREDITS.md +0 -0
  73. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/captions.yaml +0 -0
  74. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/main.jpg +0 -0
  75. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/mobile/captions.yaml +0 -0
  76. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/mobile/phone.jpg +0 -0
  77. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/settings-dark.jpg +0 -0
  78. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/screenshots/settings-light.jpg +0 -0
  79. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/docs/usage.md +0 -0
  80. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/pyproject.toml +0 -0
  81. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/readme.yaml +0 -0
  82. {readwright-0.3.0 → readwright-0.4.0}/examples/kitchen-sink/templates/partials/contributing.md.j2 +0 -0
  83. {readwright-0.3.0 → readwright-0.4.0}/readme.yaml +0 -0
  84. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/__init__.py +0 -0
  85. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/badges.py +0 -0
  86. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/py.typed +0 -0
  87. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/renderer.py +0 -0
  88. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/base.md.j2 +0 -0
  89. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/badges.md.j2 +0 -0
  90. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/contributing.md.j2 +0 -0
  91. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/donate.md.j2 +0 -0
  92. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/header.md.j2 +0 -0
  93. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/install.md.j2 +0 -0
  94. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/license.md.j2 +0 -0
  95. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/screenshots.md.j2 +0 -0
  96. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/templates/partials/usage.md.j2 +0 -0
  97. {readwright-0.3.0 → readwright-0.4.0}/src/readwright/toc.py +0 -0
  98. {readwright-0.3.0 → readwright-0.4.0}/tests/conftest.py +0 -0
  99. {readwright-0.3.0 → readwright-0.4.0}/tests/golden/base.md +0 -0
  100. {readwright-0.3.0 → readwright-0.4.0}/tests/test_badges.py +0 -0
  101. {readwright-0.3.0 → readwright-0.4.0}/tests/test_changelog.py +0 -0
  102. {readwright-0.3.0 → readwright-0.4.0}/tests/test_config.py +0 -0
  103. {readwright-0.3.0 → readwright-0.4.0}/tests/test_helpers.py +0 -0
  104. {readwright-0.3.0 → readwright-0.4.0}/tests/test_images.py +0 -0
  105. {readwright-0.3.0 → readwright-0.4.0}/tests/test_metadata.py +0 -0
  106. {readwright-0.3.0 → readwright-0.4.0}/tests/test_renderer.py +0 -0
  107. {readwright-0.3.0 → readwright-0.4.0}/tests/test_toc.py +0 -0
  108. {readwright-0.3.0 → readwright-0.4.0}/tox.ini +0 -0
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: readwright
3
+ description: Use when creating or editing a project's README.md that is managed by readwright — writing/extending README.md.j2, configuring readme.yaml or [tool.readme], adding badges/screenshots/TOC/changelog sections, or a "readwright check" / pre-commit readwright-check failure shows README.md is stale or was hand-edited.
4
+ ---
5
+
6
+ # readwright
7
+
8
+ ## Overview
9
+
10
+ readwright renders `README.md` from a Jinja2 template (`README.md.j2`) plus a config
11
+ file (`readme.yaml` or `[tool.readme]` in `pyproject.toml`). `README.md` carries a
12
+ `<!-- generated by readwright -->` marker and is **never hand-edited** — edit the
13
+ template/config, then re-render.
14
+
15
+ ## Workflow
16
+
17
+ 1. New project: `readwright init` (autodetects owner/repo/name/license from git
18
+ remote + manifest files). Existing README to preserve: `readwright init
19
+ --from-readme`. Prefer config in `pyproject.toml`: `readwright init --pyproject`.
20
+ 2. Edit `README.md.j2` — it extends the packaged `base.md.j2` and overrides only the
21
+ `{% block %}` sections it needs — and/or `readme.yaml`.
22
+ 3. `readwright render` to write `README.md` (`--watch` to re-render on save, `-o -`
23
+ to preview on stdout instead of writing).
24
+ 4. `readwright check` before committing — exits 1 with a diff if `README.md` is
25
+ stale versus what the template+config would produce. This is what CI / the
26
+ `readwright-check` pre-commit hook run; if it fails, run `render` again, don't
27
+ hand-patch `README.md`.
28
+
29
+ ## Commands
30
+
31
+ | Command | Purpose |
32
+ | --- | --- |
33
+ | `readwright init [--from-readme] [--pyproject]` | Scaffold `readme.yaml` + `README.md.j2` |
34
+ | `readwright render [--watch] [-o -] [--user-config]` | Write `README.md` |
35
+ | `readwright check` | Fail with a diff if `README.md` is stale (CI/pre-commit) |
36
+ | `readwright badges` | List available badge presets |
37
+ | `readwright blocks` | List overridable template blocks/partials |
38
+ | `readwright skill [--install] [--dest DIR] [--force]` | Print the bundled copy of this skill, or install it into a project's `.agents/skills/` (or `--dest`) |
39
+ | `readwright show <template>` | Print a packaged template (`base.md.j2` for the block order, or e.g. `partials/install.md.j2`) to copy and customize |
40
+
41
+ All accept `-C/--root` (repo root) and `-c/--config` (explicit config path) as
42
+ options *after* the subcommand, e.g. `readwright render -C /path/to/repo` —
43
+ `readwright -C /path render` fails with "No such option: -C".
44
+
45
+ ## Template helpers
46
+
47
+ Full reference with examples: [helpers.md](helpers.md). Quick index:
48
+
49
+ | Helper | Purpose |
50
+ | --- | --- |
51
+ | `badge()`, `shield()`, `badges()`, `donate_badges()` | Badges from presets, custom shields.io badges, or config-driven rows |
52
+ | `screenshot()`, `screenshots()`, `image()`, `logo()`, `video()`, `unsplash()` | Images: single shot, gallery, explicit image, theme-aware logo, video/gif, Unsplash hero |
53
+ | `toc()` | Table of contents from headings below the call |
54
+ | `changelog()` | Latest N entries from `CHANGELOG.md` |
55
+ | `cli_help()` | Runs a command and fences its `--help` output (needs `allow_exec: true`) |
56
+ | `include_file()`, `code_block()`, `snippet()` | Pull in a file, a fenced file, or a marked region |
57
+ | `config_table()`, `env_table()`, `entry_points_table()` | Tables from YAML/TOML/JSON, `.env` files, `[project.scripts]` |
58
+ | `gh_link()`, `spdx_link()`, `my_ha_link()` | Repo-relative GitHub links, SPDX license link, My Home Assistant buttons |
59
+ | `callout()`, `details()`, `center()`, `columns()` | GitHub alerts, collapsibles, centered blocks, side-by-side layout |
60
+ | `contributors()` | Avatar grid |
61
+ | `flow_install_cmd()`, `mc_versions()`, `mod_dependencies()`, `related_repos()` | Flow Launcher / Minecraft mod / related-repo tables |
62
+ | `git_sha()`, `git_tag()`, `today()` | Build metadata — these change between renders, so `check` will flag a README rendered with them as stale until re-rendered at release/CI time |
63
+ | `project.*`, `vars.*` | Autodetected repo metadata and free-form config values |
64
+
65
+ Image helpers emit plain markdown by default; pass `width=`, `html=True`, or set
66
+ `screenshots.style: html` to get `<img>`/`<picture>`/`<table>` output instead.
67
+
68
+ ## Overriding blocks and partials
69
+
70
+ `base.md.j2` blocks: `header`, `badges`, `donate`, `toc`, `screenshots`, `install`,
71
+ `usage`, `extra`, `contributing`, `license`. Override any block in `README.md.j2`:
72
+
73
+ ```jinja
74
+ {% extends "base.md.j2" %}
75
+ {% block usage %}
76
+ ## Usage
77
+ {{ screenshot("main", width=600) }}
78
+ Run `{{ project.name }} --help`.
79
+ {% endblock %}
80
+ ```
81
+
82
+ Add to the top badge row without touching the config list via the `badges_extra` /
83
+ `donate_extra` hooks. Any packaged partial can be shadowed by a same-named file
84
+ under `templates/partials/` in the repo (or `~/.config/readwright/templates/` for
85
+ all repos) — `readwright show <partial>` prints the original to copy.
86
+
87
+ To insert a whole new section where there's no dedicated hook (e.g. a Changelog
88
+ section between Contributing and License — there's no `contributing_extra` block),
89
+ override the nearest existing block and call `{{ super() }}` to keep its content,
90
+ then append (or prepend) yours:
91
+
92
+ ```jinja
93
+ {% block contributing %}
94
+ {{ super() }}
95
+
96
+ ## Changelog
97
+
98
+ {{ changelog(2) }}
99
+ {% endblock %}
100
+ ```
101
+
102
+ ## Configuration (`readme.yaml`)
103
+
104
+ ```yaml
105
+ template: README.md.j2
106
+ templates: [../shared-readme-templates, "pkg:my_org_templates"] # extra search paths
107
+ output: README.md
108
+ strict: false # missing screenshot -> error, not warning
109
+ allow_exec: false # let cli_help() run commands during render
110
+ badges_style: flat-square # shields.io style for every badge
111
+ related: [{repo: other-tool, description: Sibling project}]
112
+ banner: {unsplash: photo-1518770660439-4636190af475, credit: Name, user: handle}
113
+ screenshots: {dir: docs/screenshots, width: 720, style: markdown}
114
+ badges: [pypi, python, license, {preset: ci, workflow: test.yml}, {shield: {label: Docs, message: latest, color: success}}]
115
+ badges_custom:
116
+ discord: {label: Discord, message: chat, color: 5865F2, link: https://discord.gg/xyz}
117
+ donate: [kofi, github-sponsors]
118
+ donate_handles: {kofi: yourname, github-sponsors: yourname}
119
+ project: {name: ..., owner: ..., repo: ..., tagline: ..., pypi: ..., npm: ..., license: ..., ci_workflow: ...}
120
+ vars: {anything: you like}
121
+ ```
122
+
123
+ Metadata not set explicitly is autodetected from the git remote, `LICENSE`, and
124
+ whichever manifest exists (`pyproject.toml`, `package.json`, `Cargo.toml`, `go.mod`,
125
+ `*.csproj`, Gradle `gradle.properties`, `hacs.json`, Flow Launcher `plugin.json`) —
126
+ the install section adapts to the detected project type. Shared values (donation
127
+ handles, owner, custom badges) go in `~/.config/readwright/config.yaml`; `init`
128
+ bakes them into the new `readme.yaml`, or merge them ad hoc with `render
129
+ --user-config`.
130
+
131
+ ## Screenshots
132
+
133
+ Drop images in `docs/screenshots/` (or the configured `screenshots.dir`).
134
+ `screenshot("main")` finds `main.{png,jpg,gif,webp,svg}`; a `main-dark.*` +
135
+ `main-light.*` pair becomes a theme-aware image using GitHub's
136
+ `#gh-light-mode-only` / `#gh-dark-mode-only` fragments. `screenshots(columns=2)`
137
+ builds a gallery of everything in the directory; control order/captions with
138
+ `order=[...]`, `captions={...}`, or a `captions.yaml` file in the folder.
139
+
140
+ ## pre-commit and CI
141
+
142
+ ```yaml
143
+ # .pre-commit-config.yaml
144
+ - repo: https://github.com/Garulf/readwright
145
+ rev: v0.4.0 # pin to the latest release tag
146
+ hooks:
147
+ - id: readwright-check
148
+ ```
149
+
150
+ ```yaml
151
+ # .github/workflows/ci.yml
152
+ - uses: Garulf/readwright@v0.4.0
153
+ with:
154
+ mode: check # or render
155
+ ```
156
+
157
+ ## Common mistakes
158
+
159
+ | Mistake | Fix |
160
+ | --- | --- |
161
+ | Editing `README.md` directly | Edit `README.md.j2`/`readme.yaml`, then `readwright render` |
162
+ | `readwright check` fails in CI only | A helper like `git_sha()`/`git_tag()`/`today()` makes output change between renders — avoid them in checked README content, or re-render right before the check |
163
+ | `cli_help()` renders empty/errors | Set `allow_exec: true` in config — it's off by default |
164
+ | Screenshot not picked up | Check the file lives in `screenshots.dir` (default `docs/screenshots/`) and matches the base name passed to `screenshot()` |
165
+ | Custom badge/partial ignored | Custom badges go under `badges_custom` in config, not a template edit; custom partials go in `templates/partials/<same-name>` to shadow the packaged one |
@@ -0,0 +1,130 @@
1
+ # readwright template helpers — full reference
2
+
3
+ All helpers are called from `README.md.j2` (or any partial it includes). Signatures
4
+ below match the Python implementation; Jinja calls omit `self`.
5
+
6
+ ## Badges
7
+
8
+ - `badge(preset, **options)` — a preset badge (`readwright badges` lists names:
9
+ `pypi`, `pypi-downloads`, `python`, `license`, `ci`, `codecov`, `npm`,
10
+ `github-release`, `github-stars`, `pre-commit`, `ruff`, `version`, `modrinth`,
11
+ `curseforge`, `hacs`, `ha-version`; donation presets: `kofi`, `buymeacoffee`,
12
+ `github-sponsors`, `patreon`, `paypal`). Presets pull from `project.*` in config —
13
+ e.g. `badge("ci", workflow="test.yml")` needs `project.owner`/`project.repo`.
14
+ - `shield(label, message, color, link=None, style=None)` — a custom static
15
+ shields.io badge: `shield("Discord", "chat", "5865F2", link=gh_link("wiki"))`.
16
+ - `badges()` — renders every entry in config's `badges:` list (preset names, or
17
+ `{preset: ..., **opts}` / `{shield: {...}}` dicts) plus anything under
18
+ `badges_custom:`, in one row.
19
+ - `donate_badges()` — same, for config's `donate:` list.
20
+ - `badges_extra` / `donate_extra` block hooks — add a badge to the row without
21
+ editing the config list:
22
+ `{% block badges_extra %} {{ shield("docs", "latest", "success") }}{% endblock %}`
23
+ - Pass `style=` to any badge helper, or set `badges_style:` in config, to apply a
24
+ shields.io style (`flat-square`, etc.) to everything.
25
+
26
+ ## Images
27
+
28
+ - `screenshot(name, alt=None, width=None)` — finds `docs/screenshots/{name}.{png,jpg,gif,webp,svg}`
29
+ (dir configurable via `screenshots.dir`). If `{name}-dark.*` and `{name}-light.*`
30
+ both exist, renders a theme-aware pair using GitHub's `#gh-light-mode-only` /
31
+ `#gh-dark-mode-only` markdown fragments (or an HTML `<picture>` if
32
+ `screenshots.style: html` / `html=True` via a wider call, or `width=` is set,
33
+ since markdown can't express width).
34
+ - `screenshots(columns=2, order=None, captions=None, subdir=None)` — a gallery
35
+ table of every image in the screenshots dir. `order=["main", "settings"]` fixes
36
+ ordering; `captions={"main": "Main window"}` or a `captions.yaml` file in the
37
+ folder supplies captions.
38
+ - `has_screenshots()` — boolean, for conditionally rendering a screenshots section.
39
+ - `image(path, alt="", width=None)` — an explicit image (local path or URL), no
40
+ discovery.
41
+ - `logo(width=None, alt=None, name="logo")` — theme-aware logo from
42
+ `docs/logo.{png,svg,...}` (or `logo-dark`/`logo-light` pair).
43
+ - `video(name, width=None, alt=None)` — embeds a video/gif from the screenshots dir.
44
+ - `unsplash(photo, alt=None, width=1200, height=None, credit=None, user=None, photo_id=None, link=None, quality=80, html=False)` —
45
+ hero image from Unsplash's CDN. `photo` is a photo id like
46
+ `"photo-1518770660439-4636190af475"` or a full `images.unsplash.com` URL.
47
+ **Always pass `credit=` and `user=`** — Unsplash's license requires attribution;
48
+ omitting them renders the image with a `warn()` and no attribution line. `banner:`
49
+ in config renders one automatically above the title via the same helper.
50
+
51
+ Image helpers emit plain markdown by default (no `<picture>`/`<img>`), and only
52
+ fall back to HTML when markdown can't express what was asked (a `width=`, an
53
+ explicit `html=True`).
54
+
55
+ ## Structure
56
+
57
+ - `toc(min_level=2, max_level=3)` — table of contents built from the markdown
58
+ headings that appear *below* this call in the rendered output.
59
+ - `changelog(n=1)` — the newest `n` entries from `CHANGELOG.md` /
60
+ `CHANGES.md` / `HISTORY.md` (Keep-a-Changelog `##` headings), with heading levels
61
+ shifted to nest under the calling context.
62
+
63
+ ## Pulling in files and command output
64
+
65
+ - `include_file(path)` — raw contents of a file, relative to repo root.
66
+ - `code_block(path, language=None)` — `include_file` wrapped in a fenced code
67
+ block; language defaults to the file extension.
68
+ - `snippet(path, start, end, language=None, dedent=True)` — the lines between the
69
+ first line containing `start` and the first line at/after it containing `end`,
70
+ fenced. Useful for pulling a marked region out of a source file instead of the
71
+ whole thing.
72
+ - `cli_help(command, language="text", strip_ansi=True)` — runs `command` (shell-split,
73
+ no shell interpolation) via subprocess and fences stdout/stderr.
74
+ **Requires `allow_exec: true` in config** — raises `PermissionError` otherwise,
75
+ since it executes code during render.
76
+
77
+ ## Tables
78
+
79
+ - `config_table(path, section=None, headers=("Key", "Value"))` — flattens a
80
+ YAML/TOML/JSON file (optionally a dotted `section=`) into a two-column markdown
81
+ table.
82
+ - `env_table(path=".env.example")` — parses `KEY=value` lines (using preceding `#`
83
+ comment lines as descriptions) into a Variable/Default/Description table.
84
+ - `entry_points_table()` — table of `[project.scripts]` from `pyproject.toml`.
85
+
86
+ ## Links
87
+
88
+ - `gh_link(path="", text=None)` — `{project.owner}/{project.repo}`-relative GitHub
89
+ URL, e.g. `gh_link("issues", "Issues")`. Needs `project.owner`/`project.repo` set
90
+ or autodetected from the git remote.
91
+ - `spdx_link(license_id=None)` — link to the SPDX page for the project's license
92
+ (or an explicit id).
93
+ - `my_ha_link(redirect, text=None, **params)` — a "My Home Assistant" redirect
94
+ button/link, e.g. `my_ha_link("hacs_repository", owner=..., repository=...)`.
95
+
96
+ ## Layout
97
+
98
+ - `callout(kind, text)` — a GitHub alert (`kind` is `note`/`tip`/`important`/
99
+ `warning`/`caution`).
100
+ - `details(summary, body, open=False)` — a `<details>` collapsible.
101
+ - `center(content)` — centers a block of markdown/HTML.
102
+ - `columns(cells, align="center")` — lays out a list of markdown cells
103
+ side-by-side (as an HTML table row).
104
+ - `contributors(logins=None, size=64)` — avatar grid; `logins` defaults to
105
+ contributors autodetected from the repo.
106
+
107
+ ## Ecosystem-specific
108
+
109
+ - `flow_install_cmd()` — Flow Launcher plugin install command.
110
+ - `mc_versions()`, `mod_dependencies()` — Minecraft mod metadata tables (from
111
+ Gradle `gradle.properties`).
112
+ - `related_repos()` — table from config's `related:` list
113
+ (`[{repo: other-tool, description: ...}]`).
114
+ - `pyversions_list(sep=", ")` — joined list of supported Python versions.
115
+
116
+ ## Build metadata
117
+
118
+ - `git_sha(short=True)`, `git_tag()`, `today()` — current commit/tag/date. These
119
+ change on every render, so a checked-in `README.md` that used them will always
120
+ show as stale to `readwright check` unless re-rendered immediately before the
121
+ check (e.g. in a release job). Avoid them in a README that's committed and
122
+ linted by CI; fine for a render step that runs at publish time.
123
+
124
+ ## Context available in every template
125
+
126
+ - `project.*` — `name`, `owner`, `repo`, `tagline`, `pypi`, `npm`, `license`,
127
+ `ci_workflow`, plus anything autodetected from the git remote / `LICENSE` /
128
+ manifest file. `gh_link()` and badge presets read from here.
129
+ - `vars.*` — free-form values from config's `vars:` map, for anything
130
+ project-specific that doesn't fit elsewhere.
@@ -0,0 +1,85 @@
1
+ # AGENTS.md
2
+
3
+ readwright is a Python CLI that renders GitHub `README.md` files from Jinja2 templates
4
+ (`README.md.j2` + `readme.yaml`), with badge, screenshot, TOC, and changelog helpers.
5
+ Package lives under `src/readwright/`; console entry point is `readwright.cli:app`
6
+ (Typer). Python >=3.11, dependency/build managed with `uv` + `hatchling`.
7
+
8
+ ## Setup
9
+
10
+ ```sh
11
+ uv sync --group dev
12
+ ```
13
+
14
+ ## Running things
15
+
16
+ Always run tools through `uv run` (or `uv run tox -e <env>`) so the project's own venv
17
+ and locked dependencies are used, not whatever's on PATH.
18
+
19
+ ```sh
20
+ uv run pytest # run the test suite
21
+ uv run pytest tests/test_cli.py # single file
22
+ uv run ruff check src tests # lint
23
+ uv run ruff format src tests # format
24
+ uv run tox # full matrix: py311, py312, py313, lint
25
+ uv run tox -e lint # lint env only (ruff check + ruff format --check)
26
+ uv run readwright render # regenerate README.md from README.md.j2 + readme.yaml
27
+ uv run readwright check # fail with a diff if README.md is stale vs. the template
28
+ ```
29
+
30
+ `tests/golden/` holds golden-file fixtures for renderer output — if you touch
31
+ `renderer.py`, `helpers.py`, or any template partial, check whether golden files need
32
+ regenerating rather than hand-editing expected output.
33
+
34
+ ## Before committing
35
+
36
+ - `pre-commit` is configured (`.pre-commit-config.yaml`): gitleaks, standard hygiene
37
+ hooks, and `ruff`/`ruff-format` run on every commit; `pytest` and
38
+ `readwright check` run on `pre-push`. Run `uv run pre-commit run --all-files` if you
39
+ want to check before pushing without waiting for the hook.
40
+ - **`README.md` is generated — never edit it directly.** Edit `README.md.j2` (the
41
+ Jinja2 template) and/or `readme.yaml` (the config), then run
42
+ `uv run readwright render` to regenerate `README.md`. The file itself carries a
43
+ `<!-- generated by readwright -->` marker; editing it by hand will be silently
44
+ overwritten and will fail the `readwright check` pre-push hook / CI.
45
+ - Keep `ruff` clean: `select = ["E", "F", "I", "UP", "B", "SIM"]`, line length 100
46
+ (see `pyproject.toml`).
47
+ - This project versions with hand-bumped `pyproject.toml` (no release-please). Bump
48
+ `version` yourself for a release-worthy change — patch for fixes, minor for new
49
+ features/helpers — and follow Conventional Commits (`feat:`, `fix:`, `chore:`, ...).
50
+
51
+ ## Layout
52
+
53
+ - `src/readwright/cli.py` — Typer commands: `init`, `render`, `check`, `badges`,
54
+ `blocks`, `show`, `skill`.
55
+ - `src/readwright/renderer.py` — Jinja2 environment setup and rendering pipeline.
56
+ - `src/readwright/helpers.py`, `badges.py`, `images.py`, `toc.py`, `changelog.py`,
57
+ `metadata.py` — the template helper functions exposed to `README.md.j2`
58
+ (`badge()`, `screenshot()`, `toc()`, `changelog()`, `project.*`, etc.) and repo
59
+ metadata autodetection (git remote, `LICENSE`, manifest files like
60
+ `pyproject.toml`/`package.json`/`Cargo.toml`/`go.mod`/`*.csproj`).
61
+ - `src/readwright/config.py` — `readme.yaml` / `[tool.readme]` config model
62
+ (pydantic).
63
+ - `src/readwright/templates/` — packaged `base.md.j2` and partials that a project's
64
+ own `README.md.j2` extends/overrides.
65
+ - `examples/` — worked example projects (`kitchen-sink`, `rust-cli`, `go-cli`,
66
+ `dotnet-tool`, `node-cli`, `config-only`) exercising every helper; useful as
67
+ reference when adding or changing a helper's behavior.
68
+ - `action.yml` — GitHub Action wrapper for `readwright check`/`render` in CI.
69
+ - `.agents/skills/readwright/` — the agent skill (`SKILL.md` + `helpers.md`) that
70
+ documents the render/check workflow, config keys and template helpers for coding
71
+ agents. `.claude/skills/readwright` is a symlink to it, and hatch `force-include`s
72
+ it into the wheel as `readwright/.agents/skills/readwright/`; `readwright skill
73
+ --install` copies it out again (in the dev checkout the command falls back to the
74
+ repo-root directory). When a helper, config
75
+ key, CLI flag or block is added or changed, update the skill in the same change.
76
+
77
+ ## Testing conventions
78
+
79
+ - `tests/` mirrors `src/readwright/` module-for-module (`test_badges.py`,
80
+ `test_renderer.py`, etc.) plus `test_examples.py`, which renders the projects
81
+ under `examples/` and is a good smoke check when changing template helpers or the
82
+ renderer.
83
+ - New template helpers should get both a unit test and, where relevant, coverage
84
+ in `examples/kitchen-sink` since the README documents the full helper set from
85
+ that project's usage.
@@ -0,0 +1,18 @@
1
+ # CLAUDE.md
2
+
3
+ See `AGENTS.md` for project layout, setup, and commands — it applies here too.
4
+
5
+ ## Claude-specific notes
6
+
7
+ - `README.md` is a generated file (from `README.md.j2` + `readme.yaml`). If a task
8
+ touches the README, edit the template/config and run `uv run readwright render`;
9
+ never hand-edit `README.md` itself.
10
+ - After changing anything under `src/readwright/templates/`, `helpers.py`,
11
+ `badges.py`, `images.py`, `toc.py`, or `changelog.py`, run
12
+ `uv run pytest tests/test_examples.py` — it renders every project under
13
+ `examples/` and is the fastest way to catch a broken helper across real usage.
14
+ - Prefer `uv run tox -e lint` over invoking `ruff` directly when you want the same
15
+ check CI runs (`ruff check` + `ruff format --check`, no auto-fix).
16
+ - This repo is dogfooding itself: `readwright`'s own `README.md.j2`/`readme.yaml`
17
+ are a real usage example of the tool, not just project docs — check them for
18
+ helper usage patterns before asking "how do I use X helper".
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: readwright
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Render GitHub READMEs from Jinja2 templates with badge and screenshot helpers
5
5
  Project-URL: Homepage, https://github.com/Garulf/readwright
6
6
  Project-URL: Issues, https://github.com/Garulf/readwright/issues
@@ -36,6 +36,7 @@ Render GitHub READMEs from Jinja2 templates with badge and screenshot helpers.
36
36
  - [Template helpers](#template-helpers)
37
37
  - [Configuration](#configuration)
38
38
  - [pre-commit and GitHub Actions](#pre-commit-and-github-actions)
39
+ - [Agent skill](#agent-skill)
39
40
  - [Contributing](#contributing)
40
41
  - [License](#license)
41
42
 
@@ -82,7 +83,7 @@ Run `{{ project.name }} --help`.
82
83
  ```
83
84
 
84
85
  See [`examples/`](https://github.com/Garulf/readwright/tree/main/examples) for a kitchen-sink project using every helper,
85
- plus Minecraft mod, HACS card and Flow Launcher plugin examples.
86
+ plus Rust, Go, .NET and Node examples showing how the install section adapts per language.
86
87
 
87
88
  ## Template helpers
88
89
 
@@ -167,18 +168,33 @@ stays reproducible in CI. `readwright render --user-config` merges them ad hoc.
167
168
  ```yaml
168
169
  # .pre-commit-config.yaml
169
170
  - repo: https://github.com/Garulf/readwright
170
- rev: v0.3.0
171
+ rev: v0.4.0
171
172
  hooks:
172
173
  - id: readwright-check
173
174
  ```
174
175
 
175
176
  ```yaml
176
177
  # .github/workflows/ci.yml
177
- - uses: Garulf/readwright@v0.3.0
178
+ - uses: Garulf/readwright@v0.4.0
178
179
  with:
179
180
  mode: check # or render
180
181
  ```
181
182
 
183
+ ## Agent skill
184
+
185
+ The repo ships an [agent skill](https://agentskills.io) at `.agents/skills/readwright/`
186
+ that teaches coding agents (Claude Code, Codex, Copilot CLI, Gemini CLI, ...) the
187
+ render/check workflow, the config keys and every template helper, so they edit
188
+ `README.md.j2` instead of the generated `README.md`. Claude Code picks it up from
189
+ this repo automatically via `.claude/skills/readwright`; the same directory is
190
+ bundled inside the wheel, so any project can install it:
191
+
192
+ ```sh
193
+ readwright skill --install # copies it to ./.agents/skills/readwright
194
+ readwright skill --install --dest ~/.claude/skills # or a user-level skills directory
195
+ readwright skill # just print where the bundled copy lives
196
+ ```
197
+
182
198
  ## Contributing
183
199
 
184
200
  Issues and pull requests are welcome at [Garulf/readwright](https://github.com/Garulf/readwright).
@@ -10,6 +10,7 @@ Render GitHub READMEs from Jinja2 templates with badge and screenshot helpers.
10
10
  - [Template helpers](#template-helpers)
11
11
  - [Configuration](#configuration)
12
12
  - [pre-commit and GitHub Actions](#pre-commit-and-github-actions)
13
+ - [Agent skill](#agent-skill)
13
14
  - [Contributing](#contributing)
14
15
  - [License](#license)
15
16
 
@@ -56,7 +57,7 @@ Run `{{ project.name }} --help`.
56
57
  ```
57
58
 
58
59
  See [`examples/`](https://github.com/Garulf/readwright/tree/main/examples) for a kitchen-sink project using every helper,
59
- plus Minecraft mod, HACS card and Flow Launcher plugin examples.
60
+ plus Rust, Go, .NET and Node examples showing how the install section adapts per language.
60
61
 
61
62
  ## Template helpers
62
63
 
@@ -141,18 +142,33 @@ stays reproducible in CI. `readwright render --user-config` merges them ad hoc.
141
142
  ```yaml
142
143
  # .pre-commit-config.yaml
143
144
  - repo: https://github.com/Garulf/readwright
144
- rev: v0.3.0
145
+ rev: v0.4.0
145
146
  hooks:
146
147
  - id: readwright-check
147
148
  ```
148
149
 
149
150
  ```yaml
150
151
  # .github/workflows/ci.yml
151
- - uses: Garulf/readwright@v0.3.0
152
+ - uses: Garulf/readwright@v0.4.0
152
153
  with:
153
154
  mode: check # or render
154
155
  ```
155
156
 
157
+ ## Agent skill
158
+
159
+ The repo ships an [agent skill](https://agentskills.io) at `.agents/skills/readwright/`
160
+ that teaches coding agents (Claude Code, Codex, Copilot CLI, Gemini CLI, ...) the
161
+ render/check workflow, the config keys and every template helper, so they edit
162
+ `README.md.j2` instead of the generated `README.md`. Claude Code picks it up from
163
+ this repo automatically via `.claude/skills/readwright`; the same directory is
164
+ bundled inside the wheel, so any project can install it:
165
+
166
+ ```sh
167
+ readwright skill --install # copies it to ./.agents/skills/readwright
168
+ readwright skill --install --dest ~/.claude/skills # or a user-level skills directory
169
+ readwright skill # just print where the bundled copy lives
170
+ ```
171
+
156
172
  ## Contributing
157
173
 
158
174
  Issues and pull requests are welcome at [Garulf/readwright](https://github.com/Garulf/readwright).
@@ -37,7 +37,7 @@ Run `{{ project.name }} --help`.
37
37
  ```
38
38
 
39
39
  See [`examples/`]({{ gh_link("tree/main/examples") }}) for a kitchen-sink project using every helper,
40
- plus Minecraft mod, HACS card and Flow Launcher plugin examples.
40
+ plus Rust, Go, .NET and Node examples showing how the install section adapts per language.
41
41
 
42
42
  ## Template helpers
43
43
 
@@ -134,4 +134,19 @@ stays reproducible in CI. `readwright render --user-config` merges them ad hoc.
134
134
  mode: check # or render
135
135
  ```
136
136
 
137
+ ## Agent skill
138
+
139
+ The repo ships an [agent skill](https://agentskills.io) at `.agents/skills/readwright/`
140
+ that teaches coding agents (Claude Code, Codex, Copilot CLI, Gemini CLI, ...) the
141
+ render/check workflow, the config keys and every template helper, so they edit
142
+ `README.md.j2` instead of the generated `README.md`. Claude Code picks it up from
143
+ this repo automatically via `.claude/skills/readwright`; the same directory is
144
+ bundled inside the wheel, so any project can install it:
145
+
146
+ ```sh
147
+ readwright skill --install # copies it to ./.agents/skills/readwright
148
+ readwright skill --install --dest ~/.claude/skills # or a user-level skills directory
149
+ readwright skill # just print where the bundled copy lives
150
+ ```
151
+
137
152
  {% endblock %}
@@ -1,15 +1,17 @@
1
1
  # readwright examples
2
2
 
3
- Each directory is a self-contained fake project with a `readme.yaml`, a `README.md.j2` and the
4
- `README.md` that `readwright render` produces from them. Run `readwright render` inside one to regenerate.
3
+ Each directory is a self-contained fake project with a `readme.yaml` (some also have a `README.md.j2`)
4
+ and the `README.md` that `readwright render` produces from them. Run `readwright render` inside one to
5
+ regenerate.
5
6
 
6
7
  | Example | Shows |
7
8
  | --- | --- |
8
9
  | [kitchen-sink](kitchen-sink/) | Every general helper: logo/center header, badge presets + custom + donation badges with a global style, toc, screenshots with captions and dark/light variants, subdir gallery, `include_file`, `cli_help`, `snippet`, `details`, `callout`, `config_table`, `env_table`, `entry_points_table`, `columns`, `video`, `changelog`, `gh_link`, `related_repos`, `contributors`, `git_sha`/`git_tag`/`today`, `spdx_link`, an `unsplash()` hero image, a repo-local partial override |
9
10
  | [config-only](config-only/) | No template at all: a fully annotated `readme.yaml` using every config key (including an Unsplash `banner:`), rendered by the packaged `base.md.j2`. Read it as the config reference |
10
- | [minecraft-mod](minecraft-mod/) | Gradle/NeoForge detection, Unsplash `banner:`, `modrinth`/`curseforge` badges, `mc_versions()`, `mod_dependencies()` |
11
- | [ha-card](ha-card/) | `hacs.json` detection, `unsplash()` from an image URL, `hacs`/`ha-version` badges, `my_ha_link()`, `code_block()` |
12
- | [flow-plugin](flow-plugin/) | Flow Launcher `plugin.json` detection and the `pm install` snippet |
11
+ | [rust-cli](rust-cli/) | `Cargo.toml` detection and the `cargo install` snippet; a custom `{shield: ...}` badge for crates.io, since there's no built-in preset |
12
+ | [go-cli](go-cli/) | `go.mod` detection and the `go install ...@latest` snippet |
13
+ | [dotnet-tool](dotnet-tool/) | `*.csproj` detection (`PackAsTool`) and the `dotnet tool install --global` snippet |
14
+ | [node-cli](node-cli/) | `package.json` detection, the `npm install` snippet and the `npm` badge preset |
13
15
 
14
16
  The kitchen sink uses `git_sha()` and `today()`, so its committed `README.md` will always be a little
15
17
  behind; that is deliberate, to show why those helpers are a poor fit for `readwright check`.
@@ -0,0 +1,10 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <TargetFramework>net8.0</TargetFramework>
4
+ <PackAsTool>true</PackAsTool>
5
+ <PackageId>DotTool.Cli</PackageId>
6
+ <Version>2.1.0</Version>
7
+ <Description>A .NET global tool for scaffolding project templates</Description>
8
+ <PackageLicenseExpression>MIT</PackageLicenseExpression>
9
+ </PropertyGroup>
10
+ </Project>
@@ -0,0 +1,20 @@
1
+ <!-- generated by readwright from base.md.j2; edit the template, not this file -->
2
+ # DotTool.Cli
3
+
4
+ A .NET global tool for scaffolding project templates
5
+
6
+ [![License](https://img.shields.io/github/license/octocat/dottool)](https://github.com/octocat/dottool/blob/main/LICENSE) [![CI](https://img.shields.io/github/actions/workflow/status/octocat/dottool/ci.yml)](https://github.com/octocat/dottool/actions/workflows/ci.yml) [![Release](https://img.shields.io/github/v/release/octocat/dottool)](https://github.com/octocat/dottool/releases/latest) [![version](https://img.shields.io/badge/version-2.1.0-informational)](https://github.com/octocat/dottool) [![nuget](https://img.shields.io/badge/nuget-v2.1.0-004880?logo=nuget)](https://www.nuget.org/packages/DotTool.Cli)
7
+
8
+ ## Installation
9
+
10
+ ```sh
11
+ dotnet tool install --global DotTool.Cli
12
+ ```
13
+
14
+ ## Contributing
15
+
16
+ Issues and pull requests are welcome at [octocat/dottool](https://github.com/octocat/dottool).
17
+
18
+ ## License
19
+
20
+ MIT
@@ -0,0 +1,7 @@
1
+ badges:
2
+ - license
3
+ - {preset: ci, workflow: ci.yml}
4
+ - github-release
5
+ - version
6
+ - {shield: {label: nuget, message: v2.1.0, color: 004880, logo: nuget, link: https://www.nuget.org/packages/DotTool.Cli}}
7
+ project: {owner: octocat, repo: dottool}
@@ -0,0 +1,20 @@
1
+ <!-- generated by readwright from base.md.j2; edit the template, not this file -->
2
+ # gopher-cli
3
+
4
+ A tiny HTTP load generator written in Go
5
+
6
+ [![License](https://img.shields.io/github/license/octocat/gopher-cli)](https://github.com/octocat/gopher-cli/blob/main/LICENSE) [![CI](https://img.shields.io/github/actions/workflow/status/octocat/gopher-cli/ci.yml)](https://github.com/octocat/gopher-cli/actions/workflows/ci.yml) [![Release](https://img.shields.io/github/v/release/octocat/gopher-cli)](https://github.com/octocat/gopher-cli/releases/latest) [![go.dev](https://img.shields.io/badge/go.dev-reference-00ADD8?logo=go)](https://pkg.go.dev/github.com/octocat/gopher-cli)
7
+
8
+ ## Installation
9
+
10
+ ```sh
11
+ go install github.com/octocat/gopher-cli@latest
12
+ ```
13
+
14
+ ## Contributing
15
+
16
+ Issues and pull requests are welcome at [octocat/gopher-cli](https://github.com/octocat/gopher-cli).
17
+
18
+ ## License
19
+
20
+ MIT
@@ -0,0 +1,3 @@
1
+ module github.com/octocat/gopher-cli
2
+
3
+ go 1.22
@@ -0,0 +1,6 @@
1
+ badges:
2
+ - license
3
+ - {preset: ci, workflow: ci.yml}
4
+ - github-release
5
+ - {shield: {label: go.dev, message: reference, color: 00ADD8, logo: go, link: https://pkg.go.dev/github.com/octocat/gopher-cli}}
6
+ project: {owner: octocat, repo: gopher-cli, tagline: A tiny HTTP load generator written in Go, license: MIT}