Record the complete 164-mutant hemx-sync package proof and narrow the remaining mutation frontier to sync macros and wasm. req: test/020 req: test/021
hemx
hemx is checked hypermedia for Rust: write hemplate templates, write typed Rust handlers, and return generated UI commands. The browser receives checked UI commands; ordinary server-first apps do not need a frontend framework, handwritten UI JavaScript, selector targeting, or raw runtime primitives. req: pitch/001 req: canonical_authoring/001
Status: the evidence-backed v1 behavior slices are implemented and browser-proven:
server-first/page-enhanced behavior, client-local WASM, durable offline/sync, the
multiplayer Kanban milestone, and the production reference. Local workspace,
browser, performance, documentation, and canonical-example gates pass. The
warning-denied vulnerability and source audits are clean; strict license closure
awaits a repository license allowlist. See docs/v1-product-evidence.md for the
product boundary, REQUIREMENTS.md for authority, PLAN.md for execution state,
and docs/v1-readiness.md for evidence. No publishing is implied.
Template authoring: .heml is HTML plus a small hemplate overlay for escaped
text, trusted HTML, dynamic attributes, Rust-shaped control directives, generated
slots/forms/handles, and keyed partial targets. See docs/hemplate-syntax.md.
Editor setup for VS Code, Cursor, and Neovim lives in docs/editor-support.md;
VS Code/Cursor share the repo extension in editors/vscode-hemx, while all
editors keep normal HTML/tree-sitter highlighting and layer hemx-build
diagnostics on top.
Local checkout note: until the hemplate crates are published, this repository
expects hemplate checked out next to hemx as ../hemplate/hemplate. The app
scaffolder fails with that exact path if the prerequisite is missing, instead of
creating an app that fails later with a vague Cargo path-dependency error.
The normal path
For beginner and production-shaped app code, stay on this path. req: public_api/001 req: public_api/005
- Templates declare the surface.
.hemlfiles declare roots, slots, forms, handles, keys, page targets, optional pending states, and explicit leaf islands withdata-hemx-*attributes. The stable syntax surface lives indocs/hemplate-syntax.md. - Build generates typed helpers.
hemx_build::app().run()consumes the hemplate Surface and emits generated Rust helpers for slots, forms, handles, page targets, classes, and events. req: ceremony/003 req: build/001 - Handlers are plain Rust. App code uses
#[hemx::handler]functions with ordinary domain types, framework extractors, generatedForm<T>inputs, explicitdata-*params, andimpl IntoEffector fallible returns. req: derive_handler/001 req: derive_handler/002 req: derive_handler/003 req: derive_handler/004 req: derive_handler/005 - Handlers return generated commands. Common handlers return helpers such
as
todos.append(todo),todo_row.replace(row),new_todo.error("title", "Required"),new_todo.clear(),page.replace(view), or tuples of those commands. req: dx/006 req: dx/007 - The runtime only applies effects. The JavaScript runtime is a small, root-scoped effect interpreter: no VDOM, no hydration framework, no client expression engine, no selector retargeting, and no app state store. req: runtime/003 req: invariant/002
Mental model: render → slot/key → effect → runtime
- Render: hemplate renders Rust view structs into checked HTML. App code
normally reaches rendering through generated
ui::page(...)helpers at a server page boundary, with explicitSafeHtmlonly for already-rendered fragments, not raw HTML construction. req: html_safety/002 req: html_safety/004 req: view/001 - Slot/key: a generated slot names the target, and a generated keyed slot
also carries the stable row key. A list target inside
h-formust have a stableh-key, so row updates are addressable without CSS selectors. req: list/001 - Effect: handlers return typed commands that become a checked effect
response. Tuple composition is the normal fixed batch syntax; arrays and
Vec<T: IntoEffect>cover fixed or dynamic repeated partial updates. - Reuse: the hemx answer to framework components is reusable hemplate
partials plus generated helpers, app-owned state,
IntoEffectcomposition, and explicit leaf islands when browser-owned behavior is necessary. Seedocs/recipes/reusable-partials.md. - Runtime: the browser checks the build fingerprint, resolves targets within
the current
data-hemx-root, and applies compatible batches. Mismatched server/runtime builds fail closed instead of silently mutating the wrong DOM. req: abi/002 req: check/004 req: failure/005
Forms and errors
Forms remain HTML forms. hemx checks the generated form contract against a
user-authored Rust form type, so domain newtypes such as Email, TodoId, and
Title parse through ordinary Rust traits rather than generated DTOs. req: form/001
Use validation effects for expected user mistakes, and Result<impl IntoEffect, E> for fallible domain, database, or infrastructure work. Integration crates map
E to generated UI effects, redirects, events, or HTTP responses; the canonical
app code still uses the same handler shape for plain and fallible handlers. See
docs/diagnostics.md for common compile/build/runtime mistakes and fixes.
req: failure/004 req: derive_handler/004
Pages, push, CSS, and islands
- Page navigation is a specialized generated page/slot effect around real anchors and ordinary HTTP routes. hemx does not own routing. req: modes/002 req: axum_integration/002
- Server push streams send checked effect responses over framework-managed transports such as SSE; auth and connection policy stay in the server integration. req: wire/004 req: push/002
- Appearance is plain CSS. Generated class tokens can make dynamic classes checked, but hemx does not introduce a styling runtime. req: style/001 req: style/002 req: style/003 req: style/004 req: style/005 req: style/006
- Custom JavaScript belongs at explicit opaque leaf boundaries: charts, maps, editors, Web Components, or similar widgets. Islands communicate through generated handles/events and do not create a second UI model. req: canonical_authoring/007 req: canonical_authoring/017 req: interop/003
Production boundary
hemx is not a SaaS platform. Production concerns stay in normal Rust/web crates and integrate at explicit boundaries. req: laws/002 req: auth/001
- Persistence: use SQLx or another storage adapter in your application
state/handlers. hemx should see ordinary domain values and generated UI
commands, not own the database layer. See
docs/recipes/sqlx-persistence.md. - Auth/session: use Axum/Tower extractors and middleware. Handlers may accept
typed auth/session context and return ordinary HTTP failures or generated UI
failures. See
docs/recipes/auth-session-csrf.md. req: auth/002 - CSRF: keep CSRF policy in middleware/extractors with hidden form fields,
cookies, and normal SameSite/browser semantics. hemx preserves submitted form
fields and credentials semantics. See
docs/recipes/auth-session-csrf.md. req: auth/004 req: auth/005 - Observability, feature flags, killswitches, deploy: use explicit platform
integrations around handlers, routes, runtime assets, and mobile shells. Core
hemx must not vendor providers or add framework-specific magic. See
docs/recipes/observability-flags.md,docs/recipes/deploy-versioning.md, anddocs/recipes/mobile-release.md. req: examples/011 - Mobile starter: create the phone-first path with
cargo run -p hemx-xtask -- app new --mobile PATH. The starter carries a real app flow, typed host capabilities, command/event/projection recovery truth, and inspectable mobile release-kit commands without adding a native UI framework. Use it for Rust-owned hypermedia apps; use explicit native shells/islands for heavy native UI, games, camera-heavy flows, deep OS integration, or complex offline sync. req: ceremony/006 req: host/002 - PWA/offline/sync: optional adapters may reuse generated targets/effects,
but core hemx must not gain a mandatory client state graph or local app
runtime. Local truth is commands/events/projections, not stored DOM patches or
stored
EffectBatchpayloads. Seedocs/recipes/pwa-offline.mdanddocs/recipes/local-command-log.md. req: canonical_authoring/008 req: canonical_authoring/018 req: canonical_authoring/019 req: local/001 req: local/002 - Host capabilities: browser, PWA, WebView, and native-shell capabilities use
hemx-hostmanifests/calls/events. Adapters return host facts to app code; UI still changes through normal hemx effects. Seedocs/recipes/host-capabilities.md. req: host/001 req: host/002 req: host/005
Escape hatches
Advanced APIs are named and isolated. Raw effects, low-level ids, manual registries, raw HTML/render/target construction, runtime hooks, SSE internals, and island internals are for integration crates, tests, migrations, or explicit leaf boundaries. They should not appear in beginner examples or ordinary handler docs. req: public_api/002 req: public_api/005
Versioning and deploy compatibility
The generated API, symbols, effect wire schema, and JavaScript runtime carry
schema/ABI versions. Deploy a matching server, generated output, and runtime
asset together. Build fingerprints are derived from the generated surface and ABI
parts; the runtime refuses incompatible effect responses and integrations should
fall back to a full page reload when possible. See docs/recipes/deploy-versioning.md. req: abi/001 req: abi/002 req: failure/005
Before a v1 release, the semver policy and upgrade notes should explicitly state
which surfaces are stable: beginner generated helpers and handler shapes; the
wire/runtime ABI; and advanced escape hatches that may remain integration-level.
See docs/versioning.md.
Examples
examples/v0: canonical beginner path covering counter, typed todo CRUD, form wizard, auth action, page swaps, SSE notifications, and keyed list updates. Create the generic starter withcargo run -p hemx-xtask -- app new PATH; it includes a page, form, keyed row partial, notice slot, handlers, tests, and generated append/replace/remove/dynamic-batch updates. Start here. req: ceremony/005examples/html_examples: copy-paste HTML pattern gallery for htmx-style CRUD/form/search/load UX patterns. It proves the hemx idiom for click-to-edit, edit row, delete row, inline validation, click-to-load, and active search with.heml, generated resources, server-owned Rust state, and tiny runtime behavior. req: htmx_equivalents/001 req: htmx_equivalents/005 req: examples/001examples/saas: compile-tested v1 tutorial app covering auth/session, CSRF-safe mutation, local persistence, generated swaps, page/push shape, plain CSS, and one explicit island without provider-heavy platform scope. Read the walkthrough indocs/tutorial-saas.md; the SQLx persistence recipe indocs/recipes/sqlx-persistence.mdshows the provider boundary without moving SQL into core.examples/workout: phone-first local-first product exemplar. Create a starter withcargo run -p hemx-xtask -- workout new PATH; run the exemplar withcargo run -p hemx-xtask -- workout devand openhttp://127.0.0.1:3028. It keeps workout truth as commands/events/projections and routes export through the host capability boundary;examples/workout/README.mddocuments the canonical dev, test, production build, mobile release, verification, and failure-mode paths. req: examples/001 req: examples/006 req: local/001 req: host/005examples/kanban: advanced / north-star milestone boundary sketch. It may expose manual registry or render escape hatches while exploring product limits.examples/techdemo: advanced integration demo with a leaf island and broader product interactions.
Local checks
# Fast compile/regression pass for the crate you touched.
cargo test -p <crate>
# Focused real-browser smoke for the HTML pattern gallery.
cargo run -p hemx-xtask -- html-examples-smoke
# Full local authority check; keep this green before shipping broad slices.
cargo run -p hemx-xtask -- test
cargo check --workspace
redgate health --strict
Use cargo run -p hemx-xtask -- test for the full local verification path so
jobs stay capped for local CPU and memory. The focused browser tier is
cargo run -p hemx-xtask -- html-examples-smoke; it owns dynamic html_examples
browser behavior and should complete in about 30 seconds locally. The full tier
should complete within a 10 minute local timeout; if it grows beyond that, split
it into deterministic repo-owned shards that together cover the same behavior,
with cargo run -p hemx-xtask -- test remaining the full authority wrapper.
req: test/004 req: test/006 req: test/015 req: test/016