The prototype kit
The header a prototype loads, the ten component classes it can use, and the rules that keep every agent-written prototype looking like one product.
A prototype is one self-contained HTML page: fake data, no backend, click-through only. The prototype kit is the shared stylesheet and three scripts every prototype loads. It makes forty agent-written pages look like one product, not forty different ones.
The header
Add these four lines to the prototype’s <head>:
<link rel="stylesheet" href="https://preview.codeherder.com/kit/tokens.css">
<script src="https://preview.codeherder.com/kit/tailwind.js"></script>
<script defer src="https://preview.codeherder.com/kit/alpine.js"></script>
<script defer src="https://preview.codeherder.com/kit/bridge.js"></script>
tokens.css carries CodeHerder’s design tokens: colors, spacing, type, radius, and shadow, in both themes. tailwind.js compiles Tailwind utility classes on the page, plus the ten component classes below. alpine.js gives you x-data for state. bridge.js reports your prototype’s current selections back to the task page, so a reviewer can see them.
Use these exact, absolute URLs. A viewer renders your prototype inside a frame with its own base address. A relative path resolves to the wrong place there.
The ten component classes
Each class works two ways: on its own, or combined with a Tailwind utility class. The utility class overrides one property, such as a color or a size. Add it after the component class in the class attribute.
proto-btn — a button.
<button type="button" class="proto-btn">Cancel</button>
<button type="button" class="proto-btn bg-cta text-white border-cta">Save</button>
proto-input — a text input.
<label for="title">Title</label>
<input id="title" type="text" class="proto-input" x-model="title" placeholder="What needs doing?">
proto-select — a dropdown.
<label for="status">Status</label>
<select id="status" class="proto-select" x-model="status">
<option value="done">Done</option>
</select>
proto-badge — a status pill. Set data-status to one of seven values: pending, in-progress, done, cancelled, blocked, ready-for-review, warning.
<span class="proto-badge" data-status="done">Done</span>
<span class="proto-badge" data-status="blocked">Blocked</span>
proto-card — a bordered, padded panel.
<div class="proto-card">
<h2 class="text-lg font-semibold">Usage this month</h2>
</div>
proto-table — a dense data table.
<table class="proto-table">
<thead><tr><th scope="col">Title</th><th scope="col">Status</th></tr></thead>
<tbody><tr><td>Ship it</td><td>Done</td></tr></tbody>
</table>
proto-dialog — a modal panel. Draw the dark backdrop yourself with plain Tailwind utilities, and toggle both with the same x-show.
<div class="fixed inset-0 flex items-center justify-center bg-black/50" x-show="dialogOpen" x-cloak>
<div class="proto-dialog" role="dialog" aria-modal="true">Content</div>
</div>
proto-tabs — a tab strip.
<nav class="proto-tabs" role="tablist" aria-label="View">
<button type="button" role="tab" aria-selected="true">All</button>
<button type="button" role="tab" aria-selected="false">Mine</button>
</nav>
proto-empty — an empty-state block.
<div class="proto-empty">
<p>No tasks match this filter.</p>
</div>
proto-toast — a floating notification.
<div class="proto-toast" x-show="toast" x-cloak x-text="toast"></div>
The rules
Follow these rules so your prototype opens correctly and renders like every other one.
- Write one file. Put your markup, your styles, and your script in a single
.htmlfile. - Put your data inline. Write your fake records as a JavaScript object in the file. Do not fetch data from a server.
- Make no network calls. The frame blocks every request except the four kit files. A
fetchcall, an image from a CDN, or an embedded video will not load. - Never use
<form action="...">. A form submit tries to navigate the frame, and the frame blocks that navigation. Handle a submit with@submit.preventand Alpine state instead. - Support both themes. The kit switches on a
data-themeattribute that the viewer sets outside your file. Open your prototype in both themes before you attach it — see the sample below. - Label every control. Give every input, select, and checkbox a
<label for="...">. Give an icon-only button anaria-label.bridge.jsreports each control by its label. An unlabeled control is invisible to a reviewer, not just to a screen reader. - Keep every control reachable by keyboard. Use real
<button>,<input>, and<select>elements. A clickable<div>cannot receive keyboard focus. - Hold your state in
x-data. Put the prototype’s state in onex-dataobject: the active filter, which dialog is open, your fake records. - Mark your state’s root element
data-proto-state. Add the attribute to the element carryingx-data.bridge.jsreads that element’s Alpine data and reports it to the task page. - Use no external images. Draw an icon as inline SVG, or encode a small image as a
data:URI. The frame cannot reach an image host.
The sample prototype
app/preview/samples/task-board.html in the codeherder repository is a full worked example, built from the ten classes above. It shows a status filter, a status badge per row, a dialog, an empty state, and a toast.
This file loads the kit with relative paths, since it sits next to the kit’s own directory. Use the absolute URLs in “The header” instead for a prototype you write yourself.
Related guides
- Attaching files and images — how to attach a finished prototype to a task with
ch task attachments create <taskId> <file> --prototype - Which model your agents run — how a workflow stage picks the model an agent runs its session on
