slhx agent b4833de441 docs(requirements): split convention rows
Add explicit ring fields to convention requirements and split UX convention constraints without changing behavior.

req: convention/001

req: convention/002

req: convention/003

req: convention/004

req: convention/005

req: convention/006

req: convention/007

req: convention/008

req: convention/009

req: convention/010

req: convention/011

req: convention/012

req: convention/013

req: convention/014

req: convention/015

req: convention/016

req: convention/017
2026-06-25 18:05:05 +02:00
2026-06-12 14:40:25 +02:00
2026-06-25 18:01:26 +02:00

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 repository currently has a strong v0 example/API path, a compile-tested SaaS tutorial app, an advanced Kanban milestone sketch, and a full techdemo. The v1 story now has tutorial, recipe, diagnostics, and stability docs; see docs/v1-readiness.md for the remaining close-gap audit.

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

  1. Templates declare the surface. .heml files declare roots, slots, forms, handles, keys, page targets, optional pending states, and explicit leaf islands with data-hemx-* attributes. The stable syntax surface lives in docs/hemplate-syntax.md.
  2. 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
  3. Handlers are plain Rust. App code uses #[hemx::handler] functions with ordinary domain types, framework extractors, generated Form<T> inputs, explicit data-* params, and impl IntoEffect or fallible returns. req: derive_handler/001 req: derive_handler/002 req: derive_handler/003 req: derive_handler/004 req: derive_handler/005
  4. 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
  5. 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 explicit SafeHtml only 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-for must have a stable h-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, IntoEffect composition, and explicit leaf islands when browser-owned behavior is necessary. See docs/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, and docs/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 EffectBatch payloads. See docs/recipes/pwa-offline.md and docs/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-host manifests/calls/events. Adapters return host facts to app code; UI still changes through normal hemx effects. See docs/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 with cargo 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/005
  • examples/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/001
  • examples/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 in docs/tutorial-saas.md; the SQLx persistence recipe in docs/recipes/sqlx-persistence.md shows the provider boundary without moving SQL into core.
  • examples/workout: phone-first local-first product exemplar. Create a starter with cargo run -p hemx-xtask -- workout new PATH; run the exemplar with cargo run -p hemx-xtask -- workout dev and open http://127.0.0.1:3028. It keeps workout truth as commands/events/projections and routes export through the host capability boundary; examples/workout/README.md documents the canonical dev, test, production build, mobile release, verification, and failure-mode paths. req: examples/001 req: examples/006 req: local/001 req: host/005
  • examples/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

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. req: test/004

S
Description
No description provided
Readme 1.9 MiB
Languages
Rust 92.3%
JavaScript 7.6%