HyperGen

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-card rather than .card) to avoid collisions with other fragments.
  • If a fragment depends on a specific DOM structure, use hx-target with 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

AttributeUsageExample
hx-getFetch content on user actionhx-get="/api/agent/detail"
hx-postSubmit data to the agenthx-post="/api/agent/action"
hx-targetWhere to place the responsehx-target="#result"
hx-swapHow to insert the responsehx-swap="innerHTML" or hx-swap="outerHTML"
hx-triggerWhen to send the requesthx-trigger="click" or hx-trigger="submit"
hx-valsExtra data to includehx-vals='{"action":"approve","id":42}'
hx-indicatorShow a loading elementhx-indicator="#spinner"
hx-confirmRequire confirmationhx-confirm="Delete this item?"

Swap Strategies

Choose the swap strategy based on the interaction pattern:

StrategyWhen to use
innerHTMLReplace the content inside the target, keeping the target element itself. Default for most cases.
outerHTMLReplace the entire target element. Use when the response is a complete replacement for the current component.
beforeendAppend to the target. Use for chat messages, log entries, or list items.
afterendInsert after the target element. Use for adding sibling content.
noneDo 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 style attributes 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:data events to the host
  • Triggering hg:navigate for 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 (with data-hg-navigate for 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-surface pairs (the host is responsible for adequate contrast).
  • Avoid using --hg-accent as a text color on --hg-surface backgrounds (accent colors may not have sufficient contrast with surface colors).
  • Use --hg-accent-fg for text on --hg-accent backgrounds.

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

DoDon't
Use --hg-* variables for all theme-dependent stylesHardcode colors, fonts, or spacing
Include var() fallback valuesAssume theme variables are always set
Use hx-post/hx-get for server communicationUse fetch() or XMLHttpRequest for agent communication
Make fragments self-containedDepend on CSS/JS from previous fragments
Use semantic HTML elementsUse <div> and <span> for everything
Prefix CSS class namesUse generic class names that may collide
Use responsive layouts (%, max-width)Use fixed pixel dimensions
Include ARIA attributes for accessibilityIgnore keyboard navigation and screen readers
Generate error states as HTMLRely solely on HTTP status codes

On this page