The shared component vocabulary: the shadcn/ui roster Cinatra ships, the design rules each primitive inherits, and the host-provided composite steps. Part of Cinatra Application Design — the tokens, surfaces and accents these components map to live in that reference. Everything here is normative; match it exactly.
Cinatra ships shadcn/ui primitives with the design tokens of the Application Design reference mapped to their semantic variables. Use the components from @/components/ui directly — do not re-skin them inline. Each component below is a brief on its role and the design rules it inherits; the roster closes with the host-provided Standard scheduling step composite.
<PageHeader /> · @cinatra-ai/sdk-ui · @/components/page-header
The page-header h1 owns the page-title typography end-to-end — Archivo italic 800, -0.018em tracking, 1.05 line-height, balanced wrap — so pages never roll their own. The title scale is lg 28px (the default — every top-level page), md 24px (action-heavy admin / settings / detail subpages with long titles), sm 20px (nested sub-screens); the scale is monotonic — a smaller step never renders larger than the one above it. Title tone is ink by default; brand-mustard is a per-route opt-in for brand-y top-level pages, never on settings or admin chrome. An optional mono uppercase kicker label sits above the h1, an optional one-line description below it. The etched paired-line rule closes the header on every page — unless a toolbar sits directly beneath, which replaces the rule (see Toolbar).
<Button /> · @/components/ui/button
7 variants · 5 sizes · cva
Primary, default, outline, secondary, destructive, ghost, link. Sizes: default, xs, sm, lg, icon (xs/sm/lg). Indigo primary, ink default border, destructive uses red-on-tint not solid red.
<Card /> · @/components/ui/card
Non-interactive cards use --surface. Clickable cards (agent tiles, run rows, popovers, anything with hover or focus) use --surface-strong per rule #8.
<Input />, <Textarea /> · @/components/ui/input
Always pure white background. Border is the strong navy hairline. Focus ring picks up --ring (indigo). Use InputGroup for compound inputs with addons.
<Select />, <DropdownMenu /> · @/components/ui/select
Trigger mirrors Input chrome. Open popover sits on --surface-strong with the same hairline border, slightly higher shadow. Use scrollbar-thin on long lists.
<Dialog />, <Sheet /> · @/components/ui/dialog
Modal dialogs use --paper — the same background as pages; right-side sheets sit at full-height. Overlay top: 4rem so it doesn't cover the navbar. Dialog header uses an etched paired-line rule for separation.
<Badge />, <LifecycleBadge /> · @/components/ui/badge
Status pills (see V) use bg tinted from the status colour, text in the same colour, border at higher alpha. Use icon-led pills; never just dots.
<Tabs />, <TabsList />, <TabsTrigger /> · @/components/ui/tabs
Tab labels are 13px sans, slate when inactive, indigo when selected with a 2px indigo underline. No pill tabs; underline only. When tabs appear under a section heading, the etched paired-line rule begins to the right of the last tab and stretches to the page edge — the tablist takes the left portion of the row, the rule the right.
<Toolbar /> · @/components/ui/toolbar (composition)
Controls inside a toolbar must look different from standalone ones: they carry no individual border. The toolbar ground is their container, so a button, tab, or field placed inside it drops the border (and the fill) it would have on its own and reads only as a tinted region of the bar. A horizontal bar that groups related view controls — tablist, search, primary view action. The toolbar provides the chrome, so controls inside it carry no individual borders: the toolbar ground is their container. Hover and selected states are background tints on a rounded rectangle (7px radius, same geometry as the search pill); the font weight and colour never change between states. Vertical hairlines (24px tall, centred) separate logical groups: between the tablist and search, and between search and the action button. The search field keeps its white interactive surface — the only white element inside the toolbar. The toolbar sits directly below the page header and replaces the section rule for that view — never stack a toolbar and the etched paired rule.
<Toolbar /> → <Toolbar.Child /> · @/components/ui/toolbar (composition)
When a selected toolbar item has its own sub-controls, they open in a child toolbar directly beneath the parent rather than in a menu — and that child can in turn carry a third. Each level inherits every toolbar rule (borderless controls, hairline group separators, the lone white search field) and adds three of its own. Ground steps lighter with depth — the parent sits on the darkest chrome (var(--toolbar)) and each child lightens ~6L toward the page, so the deepest row reads as the one nearest the content it edits. The lightening stops short of the paper: even the deepest ground stays a clear step darker than the page, so every level remains legible as its own bar. Each child is inset 20px from the level above and stacked 6px beneath it, so the active path reads top-to-bottom at a glance — the inset and the lightening carry the lineage; no connectors are drawn. Cap the depth at three. A fourth level means the navigation is too deep for a toolbar — move it into the page body or a sidebar instead. Only one item per level is selected, and selecting a different item replaces every level below it.
<Sidebar />, <AppSidebar /> · @/components/ui/sidebar
Cinatra's sidebar from app-sidebar.tsx. Mustard fedora + Archivo wordmark in the brand head. Active item is indigo bg at 6% alpha; section labels are 10px mono uppercase.
<SidebarGroupLabel /> · @/components/ui/sidebar
Group labels in the sidebar — the small uppercase mono-spaced tag that sits above a cluster of nav items (Intelligence, Management, Information, Tools). Slate-muted slate at 10px with 0.18em letter-spacing reads as a quiet section break rather than a clickable item. Always above its group, never indented to match its children.
<Tooltip />, <Popover /> · @/components/ui/tooltip
Tooltips are navy with cream type; popovers are surface-strong with navy text. Tooltips read at 12px; popovers at 13–14px.
<Avatar />, <AvatarImage />, <AvatarFallback /> · @/components/ui/avatar
User avatars carry the user's initials in Archivo italic 800 on a random categorical accent (never indigo or navy). Per-extension instances same pattern (see IV).
<Form />, <Field />, <Label /> · @/components/ui/form
Form scaffolding — labels above inputs, helper or error text below. Errors swap helper text colour to brand red and add aria-invalid to the input.
<Checkbox />, <RadioGroup />, <Switch /> · @/components/ui
Single-select (radio), multi-select (checkbox), and instant-binary (switch). Indigo for active state. Switches are reserved for immediate-effect settings; checkboxes for confirmable form choices.
<Alert />, <AlertDialog /> · @/components/ui/alert
Inline alerts for warnings and errors; AlertDialog for destructive confirmations. Use the destructive variant (red) for terminal failures, warning (mustard) for cautions, info (indigo) for neutral notices.
<Sonner />, toast() · @/components/ui/sonner
Transient confirmations and async progress. Five variants — default · success · warning · error · info — each on the popover surface with a status-coloured border and matching text; an icon on the left identifies the type. Every toast carries a Copy action and a Close (X) on the right, so the user can grab the message text or dismiss the toast. Never block on a toast; use Dialog when the user must acknowledge. Stack vertically, newest on top.
<Table />, <PaginatedTable /> · @/components/ui/table
PaginatedTable handles offset, sort, and selection; Table is the dumb DOM primitive. Headers always uppercase mono with the navy underline; never centre body cells; right-align numerics and timestamps.
<Command />, <CommandDialog /> · @/components/ui/command
Global cmd+K palette and inline pickers. Section labels in 10px mono; rows at 13px; the selected row uses the indigo soft-tint background, not a border.
<Breadcrumb /> · @/components/ui/breadcrumb
Always in the topbar. Three to four crumbs maximum; truncate the middle with an ellipsis if longer. Never combine with tabs.
A crumb that stands for an entity id shows that entity's display name — at every position, not only the last. Names come from the owning page's server render, strictly after its access checks; the shell never fetches a name from the client after paint. While a name is genuinely unavailable, the crumb shows the id's first eight characters plus an ellipsis ("9c0dfce6…") — never a title-cased raw id. Visiting a not-found or not-authorized surface clears every remembered name before paint, so a previously seen name can never survive into an unauthorized view. The browser-tab title mirrors the resolved trail under the same rules: an id-bearing route never shows a raw id in the tab.
<Pagination /> · @/components/ui/pagination
For long lists and tabular data. Active page is ink-filled; surrounding pages are line-bordered on white. Always pair with a "X of N" caption in mono slate.
<Skeleton />, <Spinner /> · @/components/ui/skeleton
Skeletons mirror the layout they're replacing; never use a global spinner overlay when a skeleton would do. Spinner only for short (<500ms) inline waits inside buttons or icons.
<Empty /> · @/components/ui/empty
Use whenever a list, table, or section has zero content. Always include a single primary action button — never just empty text.
<Accordion />, <Collapsible /> · @/components/ui/accordion
Use for sectioned settings panels and FAQ-style content. Default to single-open; allow multi-open only when items are truly independent.
<Separator /> · @/components/ui/separator
Section breaks use the etched paired-line (the spec's signature divider). It stretches edge-to-edge of the content column by default. If a tablist is present in the same row, the rule starts immediately to the right of the last tab and runs to the page edge — never overlap a tablist with the rule, and never stack them. If a toolbar sits below the page header, the toolbar replaces the section rule entirely; never stack both.
<Slider /> · @/components/ui/slider
Single-value and range. Track is the muted surface, the filled portion indigo, the thumb a white interactive disc with an indigo ring (white per rule #8). Pair with a mono value readout; never label the thumb itself.
<Progress /> · @/components/ui/progress
Determinate for known-length work (a run with N steps), indeterminate for open-ended waits. Same geometry as the slider track. Show the percentage in mono above the bar; never render text inside it.
<Toggle />, <ToggleGroup /> · @/components/ui/toggle
A two-state button. Pressed state is the indigo soft-tint with ink/indigo content; rest is transparent with slate content. As a single-select group it becomes a segmented control — the canonical way to choose one of two or more options (the List / Board / Timeline view switcher above); as a multi-select group it toggles several at once (the formatting icons). Either way the buttons share one outer border with hairlines between segments — no gaps, exactly one or any number pressed. Use for view modes and inline formatting, not for settings that take immediate effect (use Switch).
<Calendar />, <DatePicker /> · @/components/ui/calendar
Month grid on the white popover surface. Weekday heads are mono uppercase; the selected day is an indigo-filled disc; today carries an indigo ring; a date range fills the in-between days with the indigo soft-tint. DatePicker is the calendar inside a Popover triggered from an Input-styled button.
<Combobox /> · @/components/ui/combobox
A Select crossed with the Command menu: an Input-chrome trigger opens a type-to-filter list. The current value carries an indigo check; the highlighted row uses the indigo soft-tint. Reach for it over Select whenever the option count passes ~8.
<HoverCard /> · @/components/ui/hover-card
A preview card on hover — for people, agents, and links. Sits on the white popover surface with a softer, longer open delay than a tooltip (≈700ms). Use when the preview carries structure (an avatar, stats); for a one-line hint use Tooltip instead.
<ContextMenu />, <DropdownMenu /> · @/components/ui/context-menu
Right-click context menus and the chevron DropdownMenu share this surface. Rows highlight on the indigo soft-tint; keyboard shortcuts sit right-aligned in mono slate; destructive items take brand red. Group with the 1px hairline, never the etched paired rule.
<Menubar /> · @/components/ui/menubar
A persistent horizontal menu bar (desktop-app style) on the toolbar ground. The open trigger takes the indigo soft-tint; its dropdown reuses the context-menu surface. Reserve it for dense editor surfaces; most product chrome should prefer the Toolbar or a DropdownMenu.
<NavigationMenu /> · @/components/ui/navigation-menu
Top-level site/product navigation with optional mega-panels. The active top link takes the 2px indigo underline (same as Tabs); the dropdown panel is a white card holding a two-column grid of titled links. Distinct from the left Sidebar — use this only for marketing or horizontal product shells.
<ScrollArea /> · @/components/ui/scroll-area
Replaces the OS scrollbar inside scrollable panels — command lists, sidebars, long popovers. A 6px overlay track with a low-alpha navy thumb that fades when idle. Same scrollbar-thin treatment referenced by Select.
<InputOTP /> · @/components/ui/input-otp
One-time-code and verification entry. Each digit is a 40px white slot with the strong navy border; the focused slot picks up the indigo ring and a blinking caret. Digits set in mono. Split groups with a short navy dash, never a vertical line.
<Drawer /> · @/components/ui/drawer
A bottom-anchored sheet for mobile and touch flows. Carries the grab handle, white surface, and a 14px top radius; the overlay dims everything below the 4rem navbar like Dialog. On desktop prefer the right-side Sheet; reserve Drawer for narrow viewports.
<ResizablePanelGroup /> · @/components/ui/resizable
Draggable split panes for master-detail layouts (a runs list beside a run detail). The handle is the strong navy hairline with a small grip; it brightens to indigo while dragging. Supports nested horizontal and vertical groups.
<AspectRatio /> · @/components/ui/aspect-ratio
Locks a child (image, embed, map, chart) to a fixed width-to-height ratio so layouts don't jump before media loads. Unfilled, it shows the seersucker-striped placeholder with a mono label naming the expected ratio. Clip the child with the 8px radius.
<Carousel /> · @/components/ui/carousel
Horizontal slide track for stat tiles, onboarding steps, or media. Arrows are white interactive discs placed outside the frame so they never cover content; the dot pager marks the current slide with an elongated indigo pill. Keep slide counts low and never auto-advance critical content.
<ChartContainer /> · @/components/ui/chart
A thin wrapper over Recharts with the tokens pre-mapped: indigo for the primary series (faded indigo for prior periods), sea-green for positive trends and brand red for negative, the navy hairline for gridlines, and mono ticks. Keep charts quiet — one or two series, no drop shadows or gradients beyond a faint area fill.
Host-provided composite · run scheduling gate + persistent /trigger tab · 3 modes · 2 surfaces
Scheduling is a platform default: every agent can run immediately, once at a future time, or on a repeating schedule, with no scheduling declaration of its own. One host-provided standard scheduling step renders the choice — in the run's first step when an agent opens on the scheduling gate, and again as a persistent /trigger tab once a future or repeating run is armed. It supersedes the retired per-agent trigger embed: an agent no longer carries a hand-copied scheduling subflow, its own confirm gate, or a version-pinned trigger dependency. A definition may still carry a metadata flag that disables or restricts scheduling, but that flag is metadata only — never a form or subflow copy.
Run scheduling gate · when-to-run choice + date-time / recurring builder + timezone + Continue
The step is the run's first gate whenever an agent opens un-triggered: the workspace content is replaced by this form until a choice is made and submitted. Under the heading When should this run? sit three selectable rows — Run right after setup, Schedule for later, and Recurring. Schedule for later reveals a Run at date-time field and its own Timezone select; Recurring reveals a structured builder — Repeat every N day(s) / week(s) / month(s) / quarter / year, the frequency-appropriate selectors beneath it (weekday toggles for weekly; a day-of-month or nth-weekday choice for monthly, quarterly and yearly; a quarter anchor; a month), an At hour:minute time-of-day, and its own Timezone select. There is no raw cron field — the host compiles the builder's selections into the stored 5-field cron expression. An Estimated run duration line sits above the actions, and submitting Continue arms the trigger and advances the run — there is no separate confirm step. When the run carries a natural-language prompt, the always-visible assistant panel pre-fills these controls (the loading state); a validation failure — a past instant, or a recurring schedule with no time chosen — surfaces inline on the field (the error state).
/trigger · configuration summary + Cancel trigger / Release now (admin)
Once a scheduled or recurring trigger is armed, the run keeps a persistent /trigger tab. It opens with a read-only Trigger configuration summary — Type, the human-readable Schedule (a recurring row shows the server-rendered plain-language reading of the schedule; a one-off shows its formatted instant), and Timezone — followed by a Steps held until trigger fires list (the side-effect steps gated behind the trigger, or a note that it acts as a start gate only). Two right-aligned controls follow, each confirming through an AlertDialog before it fires: Cancel trigger deletes the trigger and pauses the run (disabled once the trigger has been released); Release now — admin only — makes every gated step eligible immediately. This surface is unchanged by the retirement; only the in-flow step above becomes host-standard.
Three modes, one required control each. Every mode records an IANA timezone; the stored shape is the platform's per-run schedule row — no per-agent copy.
| Mode | Required control | Stored as |
|---|---|---|
| Run right after setup | — (none) | triggerType: immediate |
| Schedule for later | Run at — a future date & time | scheduledAt (ISO 8601 UTC) · timezone |
| Recurring | Recurring builder — frequency, interval, day/weekday & time-of-day | cronExpression (host-compiled) · timezone |
The previous approach delivered scheduling as a per-agent renderer chain: a hand-inlined configure subflow, a separate read-only confirm gate, and an exact-version trigger dependency pinned into every embedding agent. That chain is retired. The confirm gate is removed — the in-flow step arms the trigger directly on Continue — and no agent declares a trigger renderer or pins a trigger dependency. What stays is exactly the platform machinery it always ran on: the per-run schedule storage, the schedule firing, and the persistent /trigger tab with its Cancel / Release-now controls. The change is only that the in-flow renderer is now host-standard, available to every agent for free rather than copied into each one.