You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make hayate-htmx an engine-neutral, statically typed hypermedia layer with
first-party Jinja2, htpy, Jx, and experimental tdom rendering paths. This
implements the direction recorded in the maintainer-owned DESIGN.md without
making the Hayate core depend on a template engine.
Why now
The competitive capability matrix still gives Django and Hono stronger
framework-native HTML/component ergonomics in important profiles.
htpy supplies typed Python components and async rendering.
Jx supplies Jinja-backed components, typed props, slots, and component
assets.
tdom supplies Python 3.14 t-string components with default escaping.
The existing page/fragment selection and Vary behavior are already
renderer-independent; the remaining public type assumed string template
names.
Phase 1 — public renderer boundary
Introduce Renderer[ViewT] with one view type shared by page and
fragment targets.
Make HtmxTemplates[ViewT] generic without changing request selection,
response, status, headers, or cache variation.
Preserve the existing TemplateRenderer import as a compatible
string-view protocol for the 0.x transition.
Keep Jinja2 as the installed and documented default.
Add strict typing tests proving that page and fragment targets cannot
silently use incompatible view types.
Phase 2 — first-party adapters
Add hayate-htmx[htpy] using htpy 26.x, including async component
rendering and default escaping.
Add hayate-htmx[jx] using Jx 0.11.x, including catalog reuse, props,
slots, assets, default escaping, and normalized missing-component identity.
Add hayate-htmx[tdom] using tdom 0.1.x only on Python 3.14+, with an
actionable Python/extra error and no tdom import from the base package on
Python 3.12/3.13.
Add hayate-htmx[all] with environment markers that preserve the base
package's Python 3.12 floor.
Exercise the same page, fragment, history restore, htmx 4, escaping,
async, missing-view, Vary, content-type, and response contract for every
applicable adapter.
Phase 3 — runtime and scaffold evidence
Prove every adapter currently claimed as Workers-compatible through real
workerd/Pyodide: Jinja2 is covered by the golden app and htpy by a dedicated
gate. Jx and tdom remain explicitly unclaimed.
Add a renderer axis to create-hayate while keeping Jinja2 as the
compatibility default and tdom experimental/Python-3.14-only.
Keep generated routing, handlers, security, htmx behavior, and tests
structurally equivalent across renderers.
Publish package, compatibility, dependency, payload, and browser
evidence before changing the competitive matrix.
hayate-htmx PR Test Jx slot and asset contracts #11, squash commit e26de517b301b7caf119609f62085bbf900ba7c3, proving named slot/fill and
transitive CSS/JavaScript asset contracts
dependency audit, CodeQL, and workflow static analysis
Chromium htmx 2 and observational htmx 4 browser checks
real workerd/Pyodide htpy full-page and fragment rendering with escaping,
content type, and Vary assertions
renderer source is immutable and auditable while the public package is
unavailable: ASGI uses the reviewed Git commit and Workers bundles
hash-checked source files from the same commit
Remaining publication gate
The implementation and generated-scaffold evidence are complete. The package
is not yet on PyPI because its one-time pending trusted publisher has not been
configured. Until that external setting is complete, create-hayate remains
unreleased with the renderer axis and the competitive matrix must not claim
public-package availability.
Outcome
Make
hayate-htmxan engine-neutral, statically typed hypermedia layer withfirst-party Jinja2, htpy, Jx, and experimental tdom rendering paths. This
implements the direction recorded in the maintainer-owned
DESIGN.mdwithoutmaking the Hayate core depend on a template engine.
Why now
framework-native HTML/component ergonomics in important profiles.
assets.
Varybehavior are alreadyrenderer-independent; the remaining public type assumed string template
names.
Phase 1 — public renderer boundary
Renderer[ViewT]with one view type shared by page andfragment targets.
HtmxTemplates[ViewT]generic without changing request selection,response, status, headers, or cache variation.
TemplateRendererimport as a compatiblestring-view protocol for the 0.x transition.
silently use incompatible view types.
Phase 2 — first-party adapters
hayate-htmx[htpy]using htpy 26.x, including async componentrendering and default escaping.
hayate-htmx[jx]using Jx 0.11.x, including catalog reuse, props,slots, assets, default escaping, and normalized missing-component identity.
hayate-htmx[tdom]using tdom 0.1.x only on Python 3.14+, with anactionable Python/extra error and no tdom import from the base package on
Python 3.12/3.13.
hayate-htmx[all]with environment markers that preserve the basepackage's Python 3.12 floor.
async, missing-view,
Vary, content-type, and response contract for everyapplicable adapter.
Phase 3 — runtime and scaffold evidence
workerd/Pyodide: Jinja2 is covered by the golden app and htpy by a dedicated
gate. Jx and tdom remain explicitly unclaimed.
create-hayatewhile keeping Jinja2 as thecompatibility default and tdom experimental/Python-3.14-only.
structurally equivalent across renderers.
evidence before changing the competitive matrix.
Landed evidence
92dfb05f387d2704597b53e73880144d5f594609e26de517b301b7caf119609f62085bbf900ba7c3, proving named slot/fill andtransitive CSS/JavaScript asset contracts
c133900998c487a44d40a103c52f2d469047dedac8543a3487d2ff2e534e8f1e7a6b954e2704a6cehttps://github.com/hayatepy/create-hayate/actions/runs/30316313742
https://github.com/hayatepy/create-hayate/actions/runs/30316313791
https://github.com/hayatepy/create-hayate/actions/runs/30316596549
content type, and
Varyassertionsunavailable: ASGI uses the reviewed Git commit and Workers bundles
hash-checked source files from the same commit
Remaining publication gate
The implementation and generated-scaffold evidence are complete. The package
is not yet on PyPI because its one-time pending trusted publisher has not been
configured. Until that external setting is complete, create-hayate remains
unreleased with the renderer axis and the competitive matrix must not claim
public-package availability.
Sources reviewed
Non-goals
hayatecore.