Adds all Phase 0 content that was created but never committed: - CLAUDE.md and SCOPE.md — agent and developer orientation - specs/TailwindForInteractionHubs_v0.2.md — IHF Tailwind coding guide - docs/ — five IHP v1.5 reference guides (overview, data, controllers, realtime, ihf-mapping) - workplans/IHUB-WP-0001 — Phase 1 implementation plan (12 tasks, state-hub synced) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9.3 KiB
Tailwind for Interaction Hubs
Agentic Coding Best-Practice Guide
For building governed, observable, antifragile hub interfaces with Tailwind + IHP
Version: 0.2 (Agent-Optimized)
Status: Production-Ready Reference
Audience: Human developers and coding agents (LLMs)
Framework: IHP (Integrated Haskell Platform) + Interaction Hub Framework (IHF) layer
Date: March 2026
0. Quick-Start for Coding Agents (READ THIS FIRST)
When you receive a UI task for an Interaction Hub:
- Semantic first — Never start with classes. Ask: “What IHF primitive/widget does this map to?”
- Import hierarchy — Always
import Web.View.IHF.Primitives,Web.View.IHF.Widgets,Web.View.IHF.Classes. - Use wrappers — Render via
widgetFrame,signalBadge,hubActionButton, etc. - Token roles only — Reference
surfaceBase,signalSuccess,focusRing(defined inTheme.hs). - No raw soup — If you see >8 utility classes in one element, extract to a helper.
- Document for reproducibility — Every new primitive gets Haddock + example HSX.
This guide is your single source of truth. Follow it → zero drift.
1. Purpose
This guide makes Tailwind the shared visual grammar for all Interaction Hubs built on IHP + IHF, while keeping the IHF semantic model (Widget, Panel, SignalBadge, etc.) as the architectural control point.
It guarantees:
- Perfect visual coherence across hubs
- Zero CSS entropy
- Agent-reproducible styling (no folklore)
- Governed evolution via semantic contracts
- Full compatibility with IHP’s server-rendered HSX, partial updates, and future islands
Tailwind is the substrate. IHF widgets are the product.
2. Core Principle (Agent Rule #1)
-- ALWAYS do this
widgetFrame widget content
-- NEVER do this
<div class="rounded-xl border border-slate-700 bg-slate-900/80 px-4 py-3 shadow-sm ...">
Architecture layers (enforced order):
- IHF Semantic Model (
Widget,HubPanel,CommentThread…) - Visual Primitive Contracts (
Primitives.hs) - Tailwind Token Application (centralized in
Classes.hs+tailwind.config.js) - Screen Composition
3. IHP + Tailwind Setup (Mandatory Baseline)
Follow the official IHP Tailwind guide, then apply these IHF extensions:
Required Files (exact locations)
Project Root
├── tailwind/
│ ├── tailwind.config.js ← extend with IHF tokens
│ └── app.css
├── Web/View/IHF/
│ ├── Theme.hs ← semantic roles
│ ├── Tokens.hs ← spacing/radius/shadow maps
│ ├── Classes.hs ← reusable class builders
│ ├── Primitives.hs ← surface, panel, badge, button…
│ ├── Widgets.hs ← widgetFrame, inspectorPanel…
│ ├── Patterns.hs ← triageDashboard, decisionBoard…
│ ├── AnnotationUI.hs
│ └── GovernanceUI.hs
├── Web/View/CustomCSSFramework.hs ← IHP component override (required for JIT)
└── Config/Config.hs ← option customTailwind
Key tailwind.config.js snippet (add to IHF theme):
theme: {
extend: {
colors: {
surfaceBase: "hsl(var(--surface-base))",
signalSuccess: "hsl(var(--signal-success))",
// … all roles from Theme.hs
},
spacing: { /* baseline rhythm */ },
}
}
CustomCSSFramework.hs must expose customTailwind with Tailwind classes for all IHP form/button/flash helpers.
4. Recommended Layer Model (Agent Reference)
| Layer | Name | Lives In | Example Functions | Purpose |
|---|---|---|---|---|
| A | Semantic Interaction | Widgets.hs / Types | widgetFrame, commentRail |
What it is |
| B | Visual Primitive | Primitives.hs | panel, signalBadge, actionButton |
Reusable building blocks |
| C | Tailwind Utility Application | Classes.hs | panelClasses, badgeVariant |
Actual classes |
| D | Screen Composition | Patterns.hs | triageDashboard |
Workflow views |
5. Golden Rules for Agents
- Rule 1: Every visual element must have a named Haskell wrapper (no raw
<div class="…">longer than one line). - Rule 2: All color/spacing decisions go through
Theme.hsroles. - Rule 3: Variant logic must be exhaustive and named (
primary | ghost | danger). - Rule 4: Commentability is first-class — every widget primitive exposes
commentable :: Bool. - Rule 5: Before writing any new class string, check
Classes.hs. If missing, add it there with documentation.
6. Visual Language & Tokens (Copy-Paste Ready)
6.1 Color Roles (Theme.hs)
surfaceBase, surfaceRaised, surfaceMuted,
borderSubtle, borderStrong,
textPrimary, textSecondary, textMuted,
signalInfo, signalSuccess, signalWarning, signalDanger,
focusRing, commentAccent, policyAccent, outcomeAccent
Map these to CSS variables in tailwind/app.css @layer base.
6.2 Spacing Rhythm (Tokens.hs)
space1, space2, space3, space4, space6, space8, space12, space16
Use only these. Arbitrary values are forbidden.
6.3 Radius & Shadow
roundedPanel = "rounded-xl"
roundedBadge = "rounded-lg"
shadowLight = "shadow-sm"
7. Core Primitives (Primitives.hs — Starter Template)
-- Example: panel
panel :: [Attribute] -> Html -> Html
panel attrs content = div!
( [ class_ (panelClasses <> " " <> unwords (map renderAttr attrs))
, role_ "region"
] )
content
panelClasses :: Text
panelClasses = "bg-surfaceBase border border-borderSubtle rounded-xl shadow-sm px-4 py-3"
-- Example: signalBadge
signalBadge :: SignalStatus -> Html
signalBadge status = span!
[ class_ (badgeVariant status) ]
[ text (statusLabel status) ]
All primitives follow this exact signature pattern.
8. Widget-Centered Rules (IHF Core)
Every Widget must render via widgetFrame:
widgetFrame :: Widget -> (Widget -> Html) -> Html
widgetFrame w inner = div!
[ class_ widgetFrameClasses
, dataAttribute "widget-id" (widgetId w)
, dataAttribute "commentable" (show $ isCommentable w)
] $ do
widgetHeader w
inner w
widgetFooter w
State cues (inspectable, commentable, in-flight) use one consistent visual language (header accent + badge + subtle background shift).
9. Agent-Friendly Practices
9.1 Component Creation Protocol (Mandatory)
When creating a new primitive:
- Add to
Primitives.hswith full Haddock:{-# LANGUAGE OverloadedStrings #-} -- | A governed action button. Variants map to IHF policy levels. actionButton :: ActionVariant -> Text -> Html - Define variant type in
Types.hs. - Implement class builder in
Classes.hs. - Add example usage in
docs/Examples.hs. - Update
Short Operational Checklist(section 26).
9.2 Prompt Template for Future Agents
“Generate an IHF widget for X using only primitives from Web.View.IHF. Use semantic roles from Theme.hs. No raw Tailwind soup. Include comment affordance.”
10. Anti-Patterns (Hard-Coded Agent Rejection Rules)
- Utility soup longer than 6 classes
- Screen-local button/panel/badge reinvention
- Literal color names in component signatures
- Mixed density without system-level justification
- Styling logic inside business controllers
- Any custom CSS outside
tailwind/app.css@layer components
11. Forms, Tables, Annotations, Governance (IHF-Specific)
- Forms: Use
styledFormGroupClassfromCustomCSSFramework.hs+fieldWithPolicyNote. - Tables: Standardized
sortableTableinPatterns.hswith actor/timestamp/state columns. - Annotations: First-class
annotationThread+ triage variants (open | reviewed | policySensitive). - Governance:
decisionBanner,policyScopeBadge,traceabilityChain— all with built-in comment hooks.
12. File & Module Organization (Exact)
See section 3. All IHF UI lives under Web/View/IHF/.
Import graph is strict: Patterns.hs → Widgets.hs → Primitives.hs → Classes.hs → Theme.hs.
13. Rollout Phases & Minimum Standard
Phase 1 (MVP): Theme + Tokens + Primitives (panel, button, badge, widgetFrame)
Phase 2: AnnotationUI + GovernanceUI
Phase 3: Hub-specific accents + adaptive patterns
Every new component must ship with:
- Purpose
- Type signature
- Allowed variants
- Accessibility notes
- Commentability behavior
- Example HSX
14. Short Operational Checklist (Agent + Human Merge Gate)
Before any PR/merge:
- Semantic name used
- Imported only from IHF modules
- Classes composed via
Classes.hs - State signaling matches existing system
- Focus + contrast + color+icon rule satisfied
- Comment affordance present where applicable
- No custom CSS added
- Agent reproduction test passed (copy-paste into new context works)
15. Motto
“Use Tailwind for expression. Let IHF widgets define meaning.”
This guide is the contract between humans and agents. Follow it and Interaction Hubs stay coherent, evolvable, and antifragile forever.