Draft 2 · 2026-10-13 · Energy Thought Summit 2027 · Austin, TX · May 3–6, 2027 · Zpryme
This brief covers the mechanics of the proposed site, the models and how they are wired, the data the site runs on, the design direction, the state of the prototypes, costs, risks and a phased plan. Everything stated as a fact about the current site, the Claude API or the generative-UI landscape was checked on 2026-10-13 and recorded in the research folder; the wiring code compiles and passes its tests, and the live prototype has run real exchanges against Claude. Supporting documents, the verification record and the prototypes live beside this file (file index at the end).
Most event sites are a map: a navbar, a dozen pages, and the visitor does the finding. ETS27's theme is Free Your Mind, so the site should do the opposite of boxing people in. It opens as an open realm — pale, cloud-soft, no edges — with a single presence in it: a mind, a smooth mannequin head seen from the nose bridge up. Nothing is laid out in advance. The visitor is asked, in effect, "how do you want to take this in?", and the site shapes itself to the answer.
Both routes run on one engine: one concierge model, one knowledge snapshot pulled from the systems Zpryme already edits, one fixed catalog of interface components the model is allowed to compose. The only difference is how much of the site is pre-laid-out around it.
The content inventory (research/ets-content-inventory.md) established the facts the design has to start from:
portfolio post type) are the ETS23–ETS25 archive; there is no ETS26 term at all. The ETS26 lineup (147 speakers) and agenda (68 sessions over four days) live in Whova embeds on /lineup/ and /agenda/, readable as public Whova JSON that sends no CORS headers — so only a server-side job can read them. Speaker job titles and organizations are not in the WordPress REST output either (they are Uncode theme tokens); a one-line register_post_meta(... show_in_rest) fix exposes them./about/ is an unedited theme demo, /sponsor/ still says "start@ETS19", three speaker images return 401). The redesign is the moment to retire it.The prototypes therefore run on a validated fixture of real ETS26 stand-ins (77 speakers, 50 sessions across four days, 39 partners, the four real ticket classes, eight FAQ items, venue "to be announced"), every stand-in flagged placeholder: true so the interface shows a visible sample marker until the ETS27 program exists.
/ opens the mind with the composer focused, and typing any character on the fork opens the mind with that character already in the composer. The design direction evaluated three copy systems and picked this one for instant comprehension by a mixed utility-industry audience (brief/design-direction.md §3)./agenda/#day-2 in the map, and vice versa. The chosen door can be remembered for return visits (recommended; owner decision).The loop is deliberately simple, and that is what makes it reliable:
visitor utterance
→ concierge model (persona + knowledge snapshot + UI contract in a cached prefix)
→ one structured answer: { say, ui: [components], sources, coverage }
→ renderer draws each component from the site's own data (by id)
→ the visitor reads, taps a chip or a component, or asks again
What the model controls. The words it says (one or two sentences, under about 45 words), which components appear in what order, the record ids inside them, and a few props (a day, a tier, a type). That is the whole surface.
What the model never controls. Markup, scripts, styling, prices, times, photos or links — the renderer reads all of those from the snapshot by id. It cannot invent a speaker: a speaker_grid carries ids that must exist, and unknown ids are dropped by a sanitizer before anything reaches the browser. The prototype's live test confirmed zero dropped ids across its exchanges, including an off-topic question that was answered in one line and steered back to the event.
Why one structured answer, not per-component tool calls. Claude's structured outputs (output_config.format) constrain the whole answer to a JSON schema, so the shape is guaranteed in one pass. The alternative — one strict tool per component — has a documented trap on Opus 5.5 and Fable 5.1: text the model writes before or between tool calls comes back as progress-update thinking blocks, empty by default, so the narration can disappear. The landscape research (research/genui-landscape.md §3.10, §6.1) recommends the single structured answer for exactly that reason, and the prototype uses it.
The component catalog (reconciled). The data-model, landscape and design-direction documents converged on ten components; the prototype implements seven today.
| Component | Model supplies | Renderer reads from the snapshot |
|---|---|---|
speaker_grid |
speaker ids (≤12) | name, title, organization, photo, category, featured |
speaker_card |
one speaker id | grid fields plus bio, honors, session ids, page URL |
agenda_day (absorbs session_list) |
a day, or session ids, or a filter (type, track) | times, titles, type, track, room, speaker names |
session_card |
one session id | list fields plus description, moderators, sponsors |
venue_card |
optional section (hotels, getting there, prior venue) | name, address, status, hotels, prior venue |
sponsor_wall |
optional tier | tier, name, logo, URL |
ticket_cta |
nothing | tiers, prices, phase dates, refund policy, Eventbrite URL |
faq (replaces free-text text_block) |
an FAQ id | site-authored question and answer |
choices (absorbs link_out) |
up to four follow-ups, optionally a register/page link | nothing |
sources (a field on the answer, not a component) |
page ids | the source line under factual answers |
Every id is an enum generated from the site's data, so the schema itself rejects unknown ids; the full schema must be tested against Claude's grammar-size limit once the real speaker and session counts are known (fallback: plain string ids with server-side resolution, which is what the prototype does). Adding a component is a design task, not a model task.
Streaming. say is the first property in the schema, so its words stream before the components; each component materializes the moment its JSON object closes. The prototype's incremental JSON reader emits text deltas and one ui event per completed component over server-sent events (a subset of the AG-UI 1.0 event vocabulary, blocks shaped like A2UI component objects, so a later move to those ecosystems is a mapping exercise, not a rewrite).
Grounding and memory. A lean snapshot (ids, names, titles, organizations, session titles and times, venue, tickets, partners, FAQ — about 8k tokens on the fixture; the prototype's full cached prefix measured 19,468 tokens including persona, instructions and schema) sits behind a one-hour cache breakpoint shared by every visitor. Conversations are append-only, held server-side for the session, pinned to one snapshot version and one model, and discarded afterwards. Nothing personal is retained.
Tone. Helpful, direct, slightly dry; sentence case; no exclamation marks; a source line under facts; "I don't have that yet" plus the nearest real thing when it lacks something; sponsorship, press and speaking requests handed to people. One dry aside per conversation if the visitor opens the door; no film lines anywhere (brief/design-direction.md §10).
The standard route is a normal site generated from the same snapshot, so it exists without any model call and is what search engines index. The dock sends the same request to the same endpoint with mode: "standard" and the current page as a note appended to the conversation (so switching routes never edits the cached prefix). The only difference is the renderer: five merge rules decide whether an answer filters a list already on the page, reveals a section, materializes a component near its related section, navigates, or acts (register, contact). If the answer is pure text it stays in the dock. One engine, one prompt, one catalog, one eval set for both experiences.
Verified against the bundled Claude API guidance and the live pricing and model pages on 2026-10-13 (research/claude-wiring.md, checked claim by claim in research/verification.md: 107 claims, 99 confirmed, 7 corrected in place).
| Role | Model | Price per million tokens (in / out / cache read) | Why |
|---|---|---|---|
| Concierge, both routes | claude-opus-5-5, adaptive thinking, effort low |
$4 / $20 / $0.20 (1-hour cache write $8) | Best judgement about what to show; low effort keeps chat latency tight. medium only if an effort sweep on real transcripts shows a gain worth paying for. |
| Speed alternative | claude-sonnet-5-5, effort low |
$2 / $10 / $0.10 | Same context and structured-output surface at half the price; A/B per session, never switched mid-conversation. Its fallback model rejects mid-conversation system messages, so on this arm the page note travels inside the user message. |
| Router and abuse filter | claude-haiku-5-5 (evaluate) or claude-haiku-4-5 (proven) |
$0.10 / $0.50 (Haiku 5.5) · $1 / $5 (Haiku 4.5) | One-line verdict per message: answer, redirect or block. Haiku 5.5 shipped 2026-10-07 and is now the current Haiku, but it thinks by default and needs its own parameter test; Haiku 4.5 is now listed as legacy. Decide after a short re-test. |
| Offline eval judge | claude-sonnet-5-5 |
as above | Grades the eval set; never in the request path. |
The request. One streamed call per turn (client.beta.messages.stream): a frozen system prompt (persona, rules, the snapshot digest) behind a one-hour cache breakpoint; the append-only conversation; the structured-output schema for {say, ui, sources, coverage} (coverage is a four-value enum that powers evals and content-gap analytics at the cost of a few tokens); server-side fallbacks (fallbacks: "default" with the server-side-fallback-2026-07-01 beta) so a safety refusal degrades to a plainer model instead of an error; a 60-second timeout and one retry. The prototype combined fallbacks, structured output and streaming on every live turn without error.
Server. A Next.js route handler (Node runtime) holds the key, builds the request, relays the stream as server-sent events, and runs the router in parallel, holding the first byte until it approves (a blocked message costs about $0.002 of Opus input; the strict "never reaches Opus" reading is possible at the price of the router's latency on every turn). Rate limits: a Turnstile-backed session cookie, per-session and per-hashed-IP caps, daily spend thresholds with alerts. Logging keeps usage numbers and component types, never message text. Four SDK behaviours the bundled guidance does not mention were reproduced and designed around (the zod schema helper drops enums; the final-message helper throws when a fallback splits an answer; a stream iterated late loses events; aborting without a listener raises). The wiring document's TypeScript compiles under strict mode and passes 19 offline tests in a clean-room rebuild.
Data freshness. WordPress and Whova are synced into a versioned JSON snapshot; publishing a new version warms a new cache. Knowledge stays in the prompt until it passes roughly 50k tokens; at that point the speaker block moves to small search tools (search_speakers, list_sessions, get_speaker, get_session, search_faq) and the rest stays in the prefix.
Measured in the prototype (live Opus 5.5 at low, four exchanges): time to first word 1.2 s best case warm and 3.1 s cold; worst total 6.5 s; words always streamed before components; turn 1 wrote 19,468 tokens to the one-hour cache and turns 2–4 each read 19,468 from it. Cost: the cold turn about $0.16 (one-time per snapshot version per hour window, shared by all visitors), each warm turn $0.006–0.012; the four test exchanges together about $0.19.
Cost model (8-turn session, arithmetic verified; research/claude-wiring.md §4):
| Configuration | Per 8-turn session | 1,000 sessions / month | 10,000 | 50,000 |
|---|---|---|---|---|
Opus 5.5, low |
$0.146 | $162 | $1,524 | $7,576 |
Opus 5.5, medium |
$0.265 | $282 | $2,719 | $13,552 |
Sonnet 5.5, low |
$0.073 | $84 | $790 | $3,928 |
Sonnet 5.5, medium |
$0.133 | $144 | $1,388 | $6,916 |
Monthly totals include the router and cache re-warms. Output tokens are 71–75% of the bill, so the levers are effort, the word cap on say, and returning ids instead of descriptions; caching saves 69% at low. Real sessions will mostly be shorter than eight turns. Fast mode doubles the price and only matters if completion time, not time-to-first-word, turns out to be the complaint.
Staff keep editing speakers, FAQ, venue and hotel in WordPress and the program in Whova; the front end and the concierge read the same records and never keep a competing copy. Four things make the headless path work (research/ets-content-inventory.md §13):
portfolio type with show_in_rest, and expose navigation.The schema (research/ets-data-model.md: Edition, Day, SessionType/Track, Session, Person and Appearance, Venue/Hotel/Room, SponsorTier/Sponsor, TicketClass, FAQ, Post) models speakers per edition with a stable person behind them, because roles change between editions, and carries placeholder and confirmed flags on every record. The sample marker is renderer-owned: the model cannot switch it off.
brief/design-direction.md is the full direction; the decisions it locks:
// tags, [ bracket ] verbs, the > prompt, lowercase mono), never by film props: no green rain, no sunglasses, no quotes, and the word "construct" never appears.#C1115A (6.0:1 on white). The ETS26 aqua is retired for the light; nothing on the site is black except type, the wordmark and the footer band.// tag for labels and chips, [ verb ] for small actions, > for the composer and the mind's own lines; title tag ETS27 | free_your_mind [OPEN].All three pages are single-file, no-build HTML served from prototype/, sharing shared.css tokens and the fixture.
index.html — the opening and the fork. three.js 0.180 raymarch: an infinite pale realm with a volumetric sea of clouds, the mannequin head surfacing over four seconds, breathing and turning slowly, pointer parallax, temporal accumulation for a clean image. The lockup, the dates line and the two doors. Reduced-motion still, no-WebGL CSS realm, no-JS fork. Measured at about 100 fps at 1440×900 on an M1 Max; adaptive render scale for weaker GPUs is present but untested on phones and Safari.mind.html — the interactive route. The realm continues as a CSS light field; composer, chips, a streaming caption with a live cursor, components materializing from the fixture by id, older answers receding, the "open the full site" link. If the proxy is unreachable it switches to a scripted demo built from the fixture and says so.standard.html — the standard route. Sticky nav, hero with the real dates, the full speaker grid (grayscale, TLOY badges, initials fallback), agenda with day tabs, venue, ticket tiers, partner wall, dark footer with a countdown, and the omnipresent dock that merges answers into the page.server.py — the local proxy. A uv script (anthropic SDK) on 127.0.0.1:8777 that serves the pages and streams POST /api/mind as server-sent events: Opus 5.5, adaptive thinking at low, structured output {say, ui} over seven components, the one-hour cached prefix, server-side fallbacks, an incremental JSON reader, a sanitizer that drops unknown ids, append-only sessions, Host, Origin and Content-Type checks, a per-process budget (30 turns per 10 minutes, 80,000 output tokens per day), client-supplied assistant turns never trusted, a --public-host gate for any non-loopback bind, and an offline --selftest. The API key is read at request time from the local secrets store and never printed or logged. Run with cd prototype && uv run --script server.py, then open /index.html, /mind.html or /standard.html.Round 1 was pixel-verified at 1440×900 and 390×844 with zero console errors (prototype/shots/). Rounds 2 and 3 — a three-lens critique (visual, interaction and accessibility, engineering), fixes per file group and clean-room verification from fresh pixels, run twice — are recorded in studio/. Clean-room scores as shipped now: the opening 86/100 (round 2: 78), the mind and the standard route with the proxy 92/100 (round 2: 86). In round 3 three live exchanges through the proxy all returned ok, each reading 19,293 tokens from the cache, in 3.7 to 5.1 seconds end to end at effort low.
What the two rounds landed:
/ opens the mind, typing on the fork opens it with the draft carried over (buffered until a pause, never sent, never in a URL), a [ shortcuts off ] switch, an intro skip, and focus that never lands on an invisible door.prototype/img/) that the mind and the standard route use in place of the interim drawing; the mind's presence fades out once content appears.Still open after round 3, all minor and listed with fixes in studio/verify-03-opening.md and studio/verify-03-mind-standard.md: the 24 px head glyph still draws the earlier capsule shape; the standard nav overflows under the open dock between 821 and about 1040 px; a phone deep link to a day lands 51 px low until the web fonts settle; the opening's fallback realm (no WebGL, no JavaScript) still draws a CSS egg rather than the still; a soft cheek corner on the turned side of the head at the extreme of its yaw; the door B hover glow from the direction; and --public-host cannot express an https front.
Not in the prototype yet, by design: the router and abuse filter, Turnstile and rate limits, spend alerts, the faq and agenda_day component merges, sources and coverage fields, and the WordPress/Whova sync (the fixture stands in).
Recommendation: a Next.js (TypeScript) front end with one API route for the mind, deployed on Vercel or WP Engine's headless platform (the route needs a Node runtime with streaming responses), reading the versioned snapshot. The three.js opening is a client component loaded only on the entry page. The standard route is statically generated and revalidated on publish. Analytics and the Eventbrite registration flow carry over unchanged. The renderer is framework-neutral (plain web components or React islands); the contract already speaks AG-UI event names, so a React chat shell, an A2UI export or an MCP Apps channel inside ChatGPT and Claude are later options, not rewrites.
#C1115A, or pick another single colour.brief/design-direction.md — the design direction (concept, storyboard, fork copy, grammar, standard route, type and palette, motion and fallbacks, mobile, the head and clouds, persona, open questions)research/ets-content-inventory.md, research/ets-data-model.md — what the current site and Whova hold, the gaps ETS27 must fill, the headless path, and the schema with the snapshot and catalog recipesresearch/genui-landscape.md — the generative-UI landscape (A2UI, AG-UI, MCP Apps, assistant-ui, OpenUI, json-render, Vercel AI SDK, OpenAI Intelligent UI, the Claude mechanism), verified, with the protocol recommendation and migration pathresearch/claude-wiring.md — models, request shapes, the UI contract, caching, fallbacks, server architecture, rate limits, cost model, evals, with compiled and tested TypeScriptresearch/verification.md — the claim-by-claim check of the two research documents and the corrections appliedprototype/index.html, prototype/shared.css, prototype/vendor/ — the opening scene and the fork; three.js 0.180 self-hosted with pinned hashesprototype/img/ — the baked head stills (transparent PNG, 1x and 2x) the mind and the standard route displayprototype/mind.html, prototype/standard.html, prototype/server.py, prototype/data/ets.sample.json — the two routes running against a real Claude endpoint on local dataprototype/data/tools/, prototype/data/captures/ — the stdlib fixture builder and the 2026-10-13 raw reads it consumes (Whova program JSON, WordPress REST, page text, Eventbrite); prototype/data/README.md says how to rebuildprototype/shots/ — pixel captures per roundresearch/wiring-check/ — the TypeScript route handler, mind library and offline tests behind the wiring documenthtml/build.py — renders the brief, the direction, the research and the studio reports to html/ for local reading (uv run --script html/build.py)studio/ — critiques, fix logs and verification reports per round