ADR-005: Zero Custom Attributes
HyperGen defines zero custom HTMX attributes. Standard HTMX + SSE extension is sufficient for all Generative UI patterns.
Status: Accepted Date: 2026-03-29
Context
During the design of HyperGen's attribute system, we evaluated whether to define custom HTMX attributes (e.g., hg-agent, hg-stream, hg-context) using HTMX's extension API (htmx.defineExtension + getSelectors).
HTMX fully supports custom attribute prefixes — the SSE extension uses sse-connect/sse-swap, and WebSocket uses ws-connect/ws-send. A hg-* prefix was technically feasible.
However, we concluded that custom attributes would violate HyperGen's core philosophy.
Lessons from A2UI v0.9
Google's A2UI specification evolved from v0.8 to v0.9 with a clear theme: radical simplification. Key changes included:
- Flat component arrays instead of nested trees
- Discriminator pattern (
"component": "Text") instead of wrapper objects - Native JSON types instead of type wrappers (
"Alice"instead of{"valueString": "Alice"}) - Modular schema with swappable catalogs
- "Prompt First" design (optimized for LLM system prompts, not structured output constraints)
The lesson: the best protocol design removes abstractions rather than adding them.
HyperGen takes this principle further. Where A2UI simplified its JSON schema, HyperGen eliminates the JSON layer entirely — HTML is the protocol. And where A2UI defines a component vocabulary (18 types in the basic catalog), HyperGen imposes no vocabulary at all.
Decision
HyperGen defines zero custom HTMX attributes. All functionality is achieved with standard HTMX attributes and the official SSE extension.
What Standard HTMX Already Provides
| Need | HTMX Solution | Example |
|---|---|---|
| Stream UI from agent | SSE extension | sse-connect="/api/agent/stream" sse-swap="message" |
| Send user action to agent | Standard attributes | hx-post="/api/agent/action" |
| Specify where to render | Standard attributes | hx-target="#output" hx-swap="innerHTML" |
| Include context data | Standard attributes | hx-vals='{"key":"value"}' |
| Loading indicators | Standard attributes | hx-indicator="#spinner" |
| Trigger conditions | Standard attributes | hx-trigger="click" hx-trigger="submit" |
| Confirmation before action | Standard attributes | hx-confirm="Are you sure?" |
What Is NOT HyperGen's Responsibility
| Concern | Why it's out of scope |
|---|---|
| Session management | Agent framework concern. Use standard HTTP headers/cookies. |
| Conversation history | Agent framework concern. Not a UI protocol issue. |
| Tool call confirmation | Agent generates confirmation HTML like any other UI. No special attribute needed. |
| Authentication | Application concern. Use standard auth mechanisms. |
| Context/memory | Agent framework concern. Pass via hx-vals or HTTP headers if needed. |
Example: Complete HyperGen UI with Zero Custom Attributes
<!-- Inside sandboxed iframe (see ADR-004) -->
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/htmx.org@2"></script>
<script src="https://unpkg.com/htmx-ext-sse@2"></script>
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.card { background: var(--hg-surface); padding: var(--hg-space-4); border-radius: var(--hg-radius); }
.btn { background: var(--hg-accent); color: var(--hg-accent-fg); border: none; padding: 8px 16px; cursor: pointer; }
</style>
</head>
<body>
<!-- Stream agent-generated UI -->
<div hx-ext="sse"
sse-connect="/api/agent/stream"
sse-swap="message"
hx-swap="innerHTML">
</div>
</body>
</html>The agent generates HTML fragments that arrive via SSE:
<!-- Agent generates this fragment -->
<div class="card">
<h2>Weather in Tokyo</h2>
<p>Currently 18°C, partly cloudy</p>
<button class="btn"
hx-post="/api/agent/action"
hx-vals='{"action": "show_forecast"}'
hx-target="closest .card"
hx-swap="outerHTML">
Show 7-day forecast
</button>
</div>When the user clicks the button, HTMX sends a POST to the agent, which responds with a new HTML fragment replacing the card. No custom attributes anywhere.
Consequences
Positive
- Nothing to learn. Developers who know HTMX already know HyperGen. Zero new concepts.
- Nothing to install. No HyperGen-specific JavaScript extension. Just HTMX + SSE extension.
- LLMs generate it natively. Standard HTMX attributes are abundantly represented in LLM training data.
- Maximum simplicity. The protocol is "stream HTML with HTMX attributes over SSE." That's it.
- Future-proof. As HTMX evolves and adds features, HyperGen benefits automatically without specification updates.
Negative
- Less "brand presence." No
hg-*attributes means HyperGen is invisible at the HTML level. This is intentional — the protocol should be invisible. - No protocol-level validation. Without custom attributes, there's no way to syntactically distinguish "this is HyperGen UI" from "this is regular HTMX." The specification handles this at the transport/envelope level instead.
What HyperGen's Specification Actually Defines
If HyperGen has no custom attributes, what does it specify? The specification defines:
- The iframe bootstrap document — The minimal HTML loaded into the sandboxed iframe (HTMX + SSE extension + CSS variable bridge + postMessage handlers). See ADR-004.
- The SSE message format — How agent-generated HTML fragments are structured within SSE events.
- The postMessage protocol — Message types for iframe ↔ host communication (theming, resize, navigation).
- Security requirements — Sandbox attributes, CSP policies, allowed origins.
- CSS variable conventions — The
--hg-*variable namespace for design system integration. - Agent authoring guidelines — Best practices for agents generating HyperGen-compatible HTML.
The specification is about the system architecture, not about inventing new HTML attributes.
References
- A2UI v0.9 Specification — Simplified JSON-based Generative UI (design philosophy inspiration)
- HTMX Extensions API — Extension mechanism we chose NOT to use
- HTMX SSE Extension — The only extension HyperGen requires
- ADR-003: HTMX Technology Selection — Why HTMX
- ADR-004: Security Model — Iframe architecture