Files
hemx/AGENTS.md
T
slhx agent 1a9387dca9 docs(requirements): split v0 scope row
Add explicit northstar ring fields to v0_scope requirements and split stable-release scope without changing behavior.

req: v0_scope/001

req: v0_scope/002

req: v0_scope/003

req: v0_scope/004

req: v0_scope/005
2026-06-25 17:24:23 +02:00

14 KiB

hemx — AGENTS.md

Purpose

This file tells coding agents how to work in this repository. It is a durable operating contract, not a generated inventory.

Keep it stable. Prefer pointers to canonical sources over copied structure, file lists, metrics, architecture maps, command inventories, or status snapshots.

Agent workflow

  • Start from product intent and requirements; inspect code only after the target behavior is clear.
  • Read REQUIREMENTS.md before changing behavior.
  • If behavior changes, update REQUIREMENTS.md in the same change.
  • If implementation work does not change durable product obligations, acceptance, safety/recovery behavior, or verification duties, say REQUIREMENT IMPACT: none in the handoff and why.
  • Cite relevant requirements in code, tests, or docs as req: <component>/001.
  • Do not add citation-only padding to satisfy tooling; cite only where the requirement constrains the text.
  • Use requirement tags consistently: stable area tags like [parser], [auth], [ui]; temporary planning tags like [bootstrap], [mvp], or [milestone-1] only while they are useful.
  • Run redgate list, redgate refs, and redgate health when requirements change; include redgate lint when the change is meant to reduce requirement maintainability warnings.

Git workflow

  • Commit complete, coherent slices only; do not commit broken work or temporary debug output.
  • Use Conventional Commits: type(scope): summary.
  • Keep commit subjects readable; requirement IDs do not have to be in the subject.
  • Every behavior-changing or requirement-changing commit should cite relevant requirement IDs in the commit body or trailers using req: <component>/001.
  • Use commit history for evolution: git log --grep 'req: parser/012' should find the commits that changed that behavior.
  • Use the current tree for state: REQUIREMENTS.md, citations, tests, and redgate health describe what is true now.
  • Before committing requirement or behavior changes, run relevant tests and redgate health --strict.

Requirements-first TDD

  • Write requirements as desired behavior, not as a snapshot of current behavior.
  • Keep each requirement row to one checkable obligation with an explicit redgate ring field; shorten near-limit rows or split oversized examples, escape hatches, or negative cases into separate stable IDs while preserving the original ID's main intent.
  • First split intent into broad error classes: what can go wrong, and what outcome must hold.
  • Test the largest risky classes before narrow examples.
  • Add adversarial tests for malformed, hostile, ambiguous, missing, duplicated, and boundary inputs.
  • Do not over-codify existing behavior while direction is still moving.
  • Add narrow concrete tests only after requirements converge into a stable direction.

Redgate CLI

  • redgate list — show requirements as TSV.
  • redgate refs — show req: citations found in the repo.
  • redgate health — show uncited requirements, duplicate IDs, and stale citations.
  • redgate lint — show maintainability warnings such as missing rings and oversized requirement rows; when fixing one row in a section, normalize nearby rows with the same warning if it stays a requirement-only cleanup.
  • redgate health --strict — fail on hard errors: empty requirements, duplicate IDs, or stale citations.
  • redgate agents — print this starter template; review, shrink, and edit before committing.

Local guidance

  • Add only durable style, ownership, gotchas, and at most a few stable commands agents should actually run.
  • Prefer links or pointers to canonical sources over copied lists.
  • Avoid project trees, architecture maps, generated inventories, current file sizes, issue lists, TODO inventories, and other snapshots that will rot.
  • Stable commands: cargo run -p hemx-xtask -- test, cargo run -p hemx-xtask -- html-examples-smoke, cargo check --workspace, redgate health --strict. Use the xtask runner for full verification so jobs are capped from local CPU and memory; use the html_examples smoke for focused repo-owned browser verification of the HTML pattern gallery, not /tmp scripts. req: test/004 req: test/006 req: test/012 req: test/013
  • Example behavior tests should prefer hemx_test generated-resource assertions over raw slot constants or raw effect/payload matching; keep browser selector helpers as test adapters only, not authoring APIs. req: test/008 req: test/009 req: test/010
  • Run the workout product exemplar with cargo run -p hemx-xtask -- workout dev and open http://127.0.0.1:3028; set HEMX_WORKOUT_ADDR=127.0.0.1:3030 if the default port is busy. Its durable visual direction and recovery expectations live in examples/workout/DESIGN.md. req: examples/008
  • Use the same Workout command surface for tests, production build, and mobile release: cargo run -p hemx-xtask -- workout test, cargo run -p hemx-xtask -- workout build, HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-release, and HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-verify; Android/iOS SDKs, store submission targets, and signing remain external blockers, not repo-owned secrets. req: examples/006 req: examples/011
  • hemx core stays small: effects, typed ids, registries, and wire schema only; keep features in core only when they fit typed resources plus the closed EffectBatch op set, and treat DOM details as runtime lowering. Public identifiers should flow through typed wrappers over internal ResourceId/ResourceRef, not special-case opcodes. Wire output lowers symbolic authoring names to compact metadata and postcard/form-encoded envelopes, not JSON. ABI/schema versions and build fingerprints must guard runtime/server compatibility. v0 scope is the checked hypermedia core plus page/runtime/wire/diagnostic/test/axum proof, not optional sync/wasm/query/auth/router breadth. req: v0_scope/001 req: v0_scope/002 req: v0_scope/005 req: laws/001 req: invariant/001 req: invariant/005 req: typed_id/001 req: typed_id/003 req: effect_algebra/001 req: effect_algebra/006 req: wire/001 req: wire/002 req: wire/003 req: wire/004 req: wire/005 req: wire/006 req: abi/001 req: abi/002 req: abi/003 req: abi/004 req: abi/005
  • Routing, auth, sessions, transport, transitions, sync, async data helpers, and storage belong in integration/user crates; hemx-axum preserves normal HTTP auth, credentials, CSRF, and progressive-enhancement semantics rather than defining policy in core. Sync is optional integration state reconciliation over push/transport, not core. req: auth/001 req: auth/002 req: auth/003 req: auth/004 req: auth/005 req: async_data/001 req: async_data/002 req: async_data/003 req: sync/001 req: sync/008
  • Public examples and beginner APIs should use templates plus Rust, generated component APIs, resources, view wrappers, render/page helpers, and IntoEffect, not atoms, raw ids, selectors, wire formats, runtime opcodes, manual registries, $OUT_DIR includes, raw render/lower calls, raw HTML construction, imperative DOM mutation, or raw effect constructors; keep advanced layers out of starters. req: canonical_authoring/001 req: canonical_authoring/004 req: canonical_authoring/006 req: canonical_authoring/010 req: canonical_authoring/015 req: invariant/003 req: dx/001 req: dx/002 req: dx/010 req: component/003 req: component/004 req: view/001 req: view/002 req: html_safety/001 req: html_safety/003 req: html_safety/005 req: public_api/001 req: public_api/002 req: public_api/003 req: public_api/005 req: public_api/006 req: progressive_disclosure/001 req: progressive_disclosure/002 req: progressive_disclosure/003
  • Typed partial swaps should stay expressed as generated target plus rendered partial plus swap kind, not selector-driven rerendering; HTTP, page navigation, push, and island behavior adapt around that loop, and docs should layer new primitives progressively. Navigation is an effect/page-swap concern, not a core router framework, and enhanced links preserve real anchors/history semantics. Push streams carry postcard EffectBatch over server-owned SSE/WebSocket transport and keep data-hemx-sse root-scoped/same-origin by default. Preserve keyed/optional scope identity for addressable loop nodes and prefer generated keyed-slot helpers over low-level keyed calls. req: canonical_authoring/002 req: canonical_authoring/014 req: modes/001 req: scope/001 req: list/001 req: list/002 req: list/003 req: list/004 req: list/005 req: nav/001 req: nav/002 req: nav/003 req: nav/004 req: nav/005 req: push/001 req: push/002 req: push/003 req: push/004 req: push/005 req: push/006 req: push/007 req: progressive_disclosure/004 req: page_swap/001 req: page_swap/002 req: page_swap/003
  • examples/html_examples is the copy-paste HTML pattern gallery for htmx-style examples; keep exact htmx URL slugs visible while translating behavior to boring .heml, generated resources, and server-owned Rust state, not HTMX syntax or selector targeting. Boost containers enhance same-origin descendants only and preserve native external/download/new-tab behavior. req: htmx_equivalents/001 req: htmx_equivalents/003 req: htmx_equivalents/005 req: examples/007 req: page_swap/007 req: page_swap/008
  • Use cargo run -p hemx-xtask -- app new PATH for the generic page/form/keyed-row/notice starter, and cargo run -p hemx-xtask -- app new --mobile PATH for the phone-first starter with host capabilities, recovery truth, and release-kit commands; do not treat it as a mobile framework or store-submission bot. req: ceremony/005 req: ceremony/006 req: ceremony/007
  • The public component-reuse explanation lives in docs/recipes/reusable-partials.md; do not grow a client component framework to explain partial composition.
  • The stable public .heml authoring surface lives in docs/hemplate-syntax.md; Hemlate examples must use that real hemplate syntax, not Vue/Handlebars sketches. hemx-build consumes hemplate Surface facts and must not grow an independent .heml parser or CSS-path identity model. Generated resources, form/handle metadata, atoms, and event constants come from hemx-build facts, not hand-written app plumbing. Forms remain HTML-shaped, checked against user-authored Rust domain types, parsed through FormValue, and manipulated through generated form/control ids rather than selectors. req: surface/001 req: surface/002 req: surface/003 req: surface/004 req: surface/005 req: surface/006 req: surface/007 req: surface/008 req: surface/009 req: surface/010 req: codegen/001 req: codegen/003 req: codegen/004 req: codegen/005 req: codegen/006 req: form/001 req: form/004 req: form/007 req: form/008 req: form_effects/001 req: form_effects/002 req: form_effects/003
  • Optional .heml editor overlays must share authority with hemx-build diagnostics and docs/hemplate-syntax.md; hemx-lsp owns editor protocol glue for diagnostics/completion/hover and derive-known template facts, while VS Code/Cursor/Neovim keep normal HTML/tree-sitter tooling. Do not create a second template language, selector model, formatter, Rust type system, or custom editor framework. Cross-file template/handler references visible to build validation must fail at cargo check with useful spans; global completeness checks stay component-scoped unless caught at mount/tests. req: diagnostics/004 req: diagnostics/005 req: diagnostics/006 req: diagnostics/007 req: diagnostics/008 req: invariant/004 req: invariant/006 req: check/001 req: check/003
  • JS runtime changes must preserve root-scoped lookup, delegated listeners, postcard EffectBatch application, fail-closed request handling, transactional/recoverable failure behavior, root-scoped error outlets, and tiny pending/failure/trigger-timing conventions without selectors, handler-name parsing, VDOM, expressions, or per-node listeners. req: invariant/002 req: runtime/001 req: runtime/002 req: runtime/003 req: runtime/005 req: runtime/006 req: failure/001 req: failure/002 req: failure/003 req: failure/004 req: failure/005 req: failure/006 req: convention/001 req: convention/003 req: convention/005 req: convention/007
  • Opaque island JavaScript is a leaf adapter for high-frequency local behavior only; client-local handlers keep the server-handler shape while hemx-wasm owns concrete opt-in syntax. Use native events/generated helpers at the boundary and do not introduce a component runtime, client state graph, VDOM, selector interop, or second UI model. req: canonical_authoring/017 req: client_local/001 req: client_local/003 req: client_local/004 req: interop/001 req: interop/002 req: interop/003 req: interop/006 req: interop/007 req: interop/008 req: interop/009 req: interop/010 req: interop/011 req: interop/012
  • Host capability adapters must stay at the hemx-host boundary: typed capabilities use fire/request/stream/schedule shapes; adapters may call host APIs and return host events, but they must not mutate DOM or own app/domain state. req: host/001 req: host/002
  • Local/offline app behavior should be commands/events/projections; do not add hemx-local, stored DOM patches, stored EffectBatch truth, or a core client state graph without a proven reusable contract. Atoms are explicit addressable/bootstrap/sync resources, not the default state container or a reactive framework. Replay, reconciliation, export, and deletion rules stay explicit product decisions, and exemplars should show UI effects as app-state output. req: canonical_authoring/018 req: canonical_authoring/019 req: state/001 req: state/002 req: state/003 req: state/004 req: state/005 req: state/006 req: state/007 req: local/001 req: local/002 req: local/003 req: local/004
  • Axum apps should serve and load the shared runtime through hemx-axum helpers such as runtime_js_path() and runtime_js(), not hard-coded /hemx.js URLs or app-owned cache-busting strings; keep hemx-axum as route/runtime/handler adapter around generated partial swaps, not a routing owner. req: axum_integration/001 req: axum_integration/002 req: axum_integration/003 req: axum_integration/005 req: axum_integration/006