Agent Authoring Guidelines
Best practices for AI agents generating HyperGen-compatible HTML fragments: HTMX attributes, CSS theming, self-containment, and accessibility.
This section provides guidelines for AI agents (or any system) generating HTML fragments for HyperGen. These are recommendations for producing HTML that renders correctly in the sandboxed iframe and integrates well with the host application.
Fragment Self-Containment
Each HTML fragment delivered via SSE SHOULD be self-contained — it should include all the markup, styles, and behavior it needs to render correctly without depending on previously delivered fragments.
Why self-containment matters
- SSE events may arrive out of order after reconnection.
- HTMX swap strategies (
innerHTML,outerHTML) may replace entire subtrees. - The user may interact with the UI while new fragments are streaming.
What self-containment means in practice
- Include
<style>blocks within or adjacent to the fragment if the fragment introduces new CSS classes. - Use scoped class names (e.g.,
.hg-weather-cardrather than.card) to avoid collisions with other fragments. - If a fragment depends on a specific DOM structure, use
hx-targetwith an ID that the fragment itself creates.
<!-- Self-contained fragment with its own styles -->
<style>
.hg-weather-card {
background: var(--hg-surface-elevated, #f9fafb);
border: 1px solid var(--hg-border, #e5e7eb);
border-radius: var(--hg-radius, 8px);
padding: var(--hg-space-4, 16px);
}
</style>
<div class="hg-weather-card">
<h2>Weather in Tokyo</h2>
<p>18°C, partly cloudy</p>
<div id="weather-detail"></div>
<button hx-get="/api/agent/weather/detail"
hx-target="#weather-detail"
hx-swap="innerHTML">
Show Forecast
</button>
</div>HTMX Attribute Usage
Agents generate interactivity by including standard HTMX attributes in their HTML. No custom attributes or extensions are required (see ADR-005).
Commonly Used Attributes
| Attribute | Usage | Example |
|---|---|---|
hx-get | Fetch content on user action | hx-get="/api/agent/detail" |
hx-post | Submit data to the agent | hx-post="/api/agent/action" |
hx-target | Where to place the response | hx-target="#result" |
hx-swap | How to insert the response | hx-swap="innerHTML" or hx-swap="outerHTML" |
hx-trigger | When to send the request | hx-trigger="click" or hx-trigger="submit" |
hx-vals | Extra data to include | hx-vals='{"action":"approve","id":42}' |
hx-indicator | Show a loading element | hx-indicator="#spinner" |
hx-confirm | Require confirmation | hx-confirm="Delete this item?" |
Swap Strategies
Choose the swap strategy based on the interaction pattern:
| Strategy | When to use |
|---|---|
innerHTML | Replace the content inside the target, keeping the target element itself. Default for most cases. |
outerHTML | Replace the entire target element. Use when the response is a complete replacement for the current component. |
beforeend | Append to the target. Use for chat messages, log entries, or list items. |
afterend | Insert after the target element. Use for adding sibling content. |
none | Do not swap. Use when the request triggers a side effect (e.g., hg:data event) without changing the visible UI. |
Targeting Patterns
<!-- Target by ID -->
<button hx-get="/api/data" hx-target="#output">Load</button>
<div id="output"></div>
<!-- Target relative to the trigger element -->
<div class="card">
<button hx-post="/api/update"
hx-target="closest .card"
hx-swap="outerHTML">
Update Card
</button>
</div>
<!-- Target the element itself (default behavior) -->
<div hx-get="/api/refresh" hx-trigger="every 30s" hx-swap="innerHTML">
Auto-refreshing content
</div>Including Context Data
Use hx-vals to pass context to the agent server:
<button hx-post="/api/agent/action"
hx-vals='{"action":"analyze","dataset":"sales_q4","format":"chart"}'
hx-target="#result"
hx-swap="innerHTML">
Analyze Sales Data
</button>For forms, HTMX automatically includes all form field values. No hx-vals is needed for standard form submissions:
<form hx-post="/api/agent/query" hx-target="#result" hx-swap="innerHTML">
<input type="text" name="query" placeholder="Ask anything..." />
<select name="model">
<option value="fast">Fast</option>
<option value="thorough">Thorough</option>
</select>
<button type="submit">Ask</button>
</form>
<div id="result"></div>CSS Styling Best Practices
Use --hg-* variables
All visual properties that should match the host's design system MUST reference --hg-* variables with fallback values. See CSS Variable Theming for the complete variable list.
/* Good: uses theme variables with fallbacks */
.my-component {
background: var(--hg-surface, #ffffff);
color: var(--hg-text, #111827);
border: 1px solid var(--hg-border, #e5e7eb);
}
/* Bad: hardcoded colors that won't match the host theme */
.my-component {
background: #ffffff;
color: #333333;
border: 1px solid #ccc;
}Avoid fixed dimensions
Fragments render inside an iframe that may be any width. Use responsive techniques:
/* Good: responsive */
.chart-container {
width: 100%;
max-width: 600px;
aspect-ratio: 16 / 9;
}
/* Bad: fixed width may overflow */
.chart-container {
width: 600px;
height: 400px;
}Prefix class names
To avoid collisions between fragments, prefix CSS class names. A short prefix related to the component's purpose is sufficient:
/* Scoped to this fragment */
.hg-weather-card { ... }
.hg-weather-temp { ... }
.hg-weather-icon { ... }Inline styles vs style blocks
- Use
<style>blocks for fragments with multiple styled elements. - Use inline
styleattributes for one-off styling on a single element. - SHOULD NOT use
<link>to load external stylesheets (adds latency, may be blocked by CSP).
Inline Scripts
Agent-generated HTML MAY include inline <script> blocks for client-local behavior that does not require a server round-trip.
When to use inline scripts
- Local calculations (e.g., slider value display, live character count)
- Client-side rendering (e.g., charts via a charting library loaded in the bootstrap)
- Animations and visual effects
- Sending
hg:dataevents to the host - Triggering
hg:navigatefor host-level navigation
When NOT to use inline scripts
- Server communication — use HTMX attributes (
hx-get,hx-post) instead - State management that should persist across fragments — use the agent server
- Loading external scripts — the CSP may block them
Script execution in SSE fragments
When HTMX swaps HTML containing <script> tags, the scripts execute automatically (HTMX handles this). Agents can rely on this behavior for scripts included in SSE fragments.
<div id="chart-container" style="width:100%; height:300px;"></div>
<script>
// This script runs when HTMX swaps this fragment into the DOM
var container = document.getElementById('chart-container');
// ... render a chart using a library loaded in the bootstrap
</script>Sending data to the host
<button onclick="document.dispatchEvent(new CustomEvent('hg:data', {
detail: { action: 'selected', itemId: 42 }
}))">
Select Item
</button>Triggering host navigation
<a data-hg-navigate="/dashboard" href="#">Go to Dashboard</a>Or via script:
<button onclick="window.parent.postMessage({
type: 'hg:navigate', url: '/settings'
}, '*')">
Open Settings
</button>Loading Indicators
Use HTMX's built-in indicator mechanism to show loading states during agent interactions:
<button hx-post="/api/agent/analyze"
hx-target="#result"
hx-indicator="#spinner">
Analyze
</button>
<span id="spinner" class="hg-indicator">Loading...</span>
<div id="result"></div>The bootstrap document includes CSS that hides .hg-indicator by default and shows it when HTMX adds the .htmx-request class during a pending request.
Error Handling
Agents SHOULD generate user-friendly error states as HTML rather than relying on HTTP error codes:
<div class="hg-error" style="
background: var(--hg-surface-elevated, #f9fafb);
border: 1px solid #ef4444;
border-radius: var(--hg-radius, 8px);
padding: var(--hg-space-4, 16px);
color: var(--hg-text, #111827);
">
<strong>Something went wrong</strong>
<p style="color: var(--hg-text-muted, #6b7280);">
Unable to retrieve weather data. Please try again.
</p>
<button hx-get="/api/agent/weather"
hx-target="closest .hg-error"
hx-swap="outerHTML">
Retry
</button>
</div>For SSE stream errors, the bootstrap document's connection status CSS classes (hg-connected / hg-disconnected) provide automatic visual feedback.
Accessibility Considerations
Agent-generated HTML SHOULD follow web accessibility best practices:
Semantic HTML
Use appropriate HTML elements for their intended purpose:
<!-- Good: semantic -->
<nav aria-label="Results navigation">
<button hx-get="/api/page/1" hx-target="#results">Page 1</button>
<button hx-get="/api/page/2" hx-target="#results">Page 2</button>
</nav>
<!-- Bad: div soup -->
<div>
<div onclick="...">Page 1</div>
<div onclick="...">Page 2</div>
</div>ARIA attributes
Add ARIA attributes when semantic HTML alone is insufficient:
<div role="alert" aria-live="polite">
Analysis complete: 3 anomalies found.
</div>
<button hx-post="/api/agent/action"
aria-label="Delete report for Q4 2025"
hx-confirm="Delete this report?">
Delete
</button>Keyboard navigation
Ensure all interactive elements are keyboard-accessible:
- Use
<button>for clickable actions (not<div onclick>). - Use
<a>for navigation (withdata-hg-navigatefor host navigation). - Ensure custom widgets have appropriate
tabindex,role, and keyboard event handlers.
Color contrast
When using --hg-* theme variables, the contrast ratio depends on the host's theme. Agents SHOULD:
- Rely on
--hg-text/--hg-surfacepairs (the host is responsible for adequate contrast). - Avoid using
--hg-accentas a text color on--hg-surfacebackgrounds (accent colors may not have sufficient contrast with surface colors). - Use
--hg-accent-fgfor text on--hg-accentbackgrounds.
Live regions
For content that updates dynamically (e.g., streaming results), use ARIA live regions:
<div aria-live="polite" aria-atomic="false">
<div id="result" hx-swap="innerHTML">
<!-- Streaming content appears here; screen readers announce updates -->
</div>
</div>Summary of Dos and Don'ts
| Do | Don't |
|---|---|
Use --hg-* variables for all theme-dependent styles | Hardcode colors, fonts, or spacing |
Include var() fallback values | Assume theme variables are always set |
Use hx-post/hx-get for server communication | Use fetch() or XMLHttpRequest for agent communication |
| Make fragments self-contained | Depend on CSS/JS from previous fragments |
| Use semantic HTML elements | Use <div> and <span> for everything |
| Prefix CSS class names | Use generic class names that may collide |
Use responsive layouts (%, max-width) | Use fixed pixel dimensions |
| Include ARIA attributes for accessibility | Ignore keyboard navigation and screen readers |
| Generate error states as HTML | Rely solely on HTTP status codes |
CSS Variable Theming
The --hg-* CSS custom property namespace, defined variables, default values, and theme injection mechanism.
ADR-001: Project Concept — Why HyperGen Exists
Founding vision for HyperGen: a critical analysis of existing Generative UI protocols and the case for an HTMX-based, truly agent-agnostic alternative.