Block catalog
Every primitive the build agent can compose. New blocks added to @atriux/blocksautomatically appear here and become available to the agent — there's no separate registration step. In Atriux v2's narrow scope, the agent primarily uses HeroBlock + AgentResearchBlock + ItemListBlock (or ItemDetailBlock); the rest of the catalog stays in the registry but is rarely chosen unless a brief specifically calls for it.
Currently available
The closed catalog as of this build of the docs:
HeroBlock— Page header with optional eyebrow label, large editorial title, and subtitle. Always place at the top of a project. Renders via @atriux/ui's EditorialHero — Anthropic editorial style.MarkdownBlock— Long-form prose section. Use for intros, methodology notes, executive summaries, disclaimers, 'how this works' explanations — anything where you want to author static-ish copy at build time. Supports a safe markdown subset: **bold**, *italic*, `code`, [links](https://...), - bullets, 1. ordered lists, blank-line paragraph breaks. Props: `content` (required, the markdown body, MAX 1500 CHARS — keep it short, split into multiple MarkdownBlocks if you need more; ~300 chars is ideal for repo imports), `heading` (optional section heading), `eyebrow` (optional uppercase label above heading).CalloutBlock— Tinted info/warning/success/danger/tip box. Use for project-wide warnings, deadline reminders, methodology notes, onboarding hints, or anything that should catch the user's eye without being a full prose section. Props: `variant` ('info' | 'warning' | 'success' | 'danger' | 'tip'), `title` (optional bold lede), `body` (the message, max 800 chars).DividerBlock— Thin section separator with optional centered label. Use to break long pages into named sections (e.g. 'KPIs' / 'Pipeline' / 'Vendors'). Props: `label` (optional centered text), `spacing` ('sm' | 'md' | 'lg' — vertical margin, default 'md').—ItemListBlock— Renders the user's items for this project as a vertical list. Reads from project_items table filtered by project + current user. Required props: `primary` (the field key to use for each item's main label). Optional: `secondary` (field key for sub-line), `empty` (copy when there are no items).TableBlock— Compact tabular view of project_items — preferred over ItemListBlock when the project is data-heavy (finance dashboards, transaction logs, CRMs). Props: `columns` (array of field keys to display, max 8), `headers` (optional column header overrides), `currencyColumn` (one column to format as $X,XXX.XX), `colorColumn` (one column rendered red/green by sign — useful for amounts on income/expense tables), `sortBy` (field key to sort by; default created_at DESC), `sortDir` ('asc' | 'desc'), `limit` (max rows; default 50, max 500), `title` (section label above the table), `empty` (empty-state copy). Numeric/currency columns are right-aligned with tabular nums.TimelineBlock— Chronological timeline of items grouped by day. Use for journal-style projects (workouts, meals, deals, calls, research log) where 'what happened when' is the primary view. Each entry has a colored dot, headline, optional subtext, optional status badge, and the time of day. Props: `primary` (headline field key — required), `secondary` (optional sub-line), `statusField` (a select-typed field that drives dot color), `statusColors` (object mapping status value → color name: amber/emerald/rose/blue/violet/zinc), `title`, `empty`, `daysLimit` (default 60). Differs from ItemListBlock: TimelineBlock groups by day with a vertical rail; ItemListBlock is a flat list.ResearchStatusBlock— At-a-glance progress of AI research across the user's items. Pairs with AgentResearchBlock / WebSearchBlock (action) — this is the read-only 'how far through am I?' affordance. Renders 'X of Y researched (Z%)' with a progress bar and the most recent N completed items. Props: `outputField` (the field that AgentResearchBlock writes to — same value as that block's outputField), `primary` (row label field), `title`, `hint`, `recentLimit` (default 5, max 20).StatBlock— A single big-number stat aggregated from project_items. Props: `label` (display name), `aggregate` (sum | count | avg | min | max | latest), `field` (item field key — required for sum/avg/min/max/latest, ignored for count), optional `prefix` / `suffix` (e.g. '$' or ' lbs'), `precision` (decimal places), `since` (today | week | month | year — optional time-window filter). Use multiple StatBlocks side-by-side for a dashboard top row.StatRowBlock— A row of 2–5 KPI tiles aggregated from project_items. Use this for the top-of-dashboard summary row on finance / metric / ops projects. Preferred over multiple StatBlocks for grouped KPIs because the tiles share grid alignment and can show period-over-period deltas. Props: `title` (optional row label), `tiles` (array of {label, aggregate, field?, prefix?, suffix?, precision?, since?, compareTo?, invertSentiment?}). `compareTo` shows a colored % delta (green=better, red=worse). Set `invertSentiment: true` on tiles where 'up = bad' (e.g. expenses).ChartBlock— Renders a chart from project_items. Props: `title` (heading), `type` (bar | pie | line), `field` (numeric item field to aggregate; omit for 'count of items'), `groupBy` (categorical field — required for bar/pie if you want grouping), `aggregate` (sum | count — defaults to sum when field is set, count otherwise), `height` (default 280). Use 'pie' for category breakdowns, 'bar' for ranked groups, 'line' for time-series (x-axis is created_at, aggregated by day).FormulaBlock— Display a computed value derived from a formula over aggregations of project_items. The 'algorithm' primitive — use for derived KPIs the user can't compute by hand: runway months, burn ratio, equity remaining, conversion rate, etc. Props: `label` (display label), `formula` (a string with named variables, +-*/, parentheses — e.g. 'cash / monthly_burn' or '(revenue - expenses) / revenue * 100'), `variables` (object mapping variable name → {aggregate, field?, since?, filter?: {field, equals}}), `prefix`, `suffix`, `precision` (decimal places), `hint` (sub-line explaining the metric). Examples: Runway months → formula 'cash / monthly_burn', vars {cash: {aggregate: 'latest', field: 'balance'}, monthly_burn: {aggregate: 'sum', field: 'amount', since: 'month', filter: {field: 'category', equals: 'expense'}}}.GoalProgressBlock— Progress bar toward a numeric target. Use for goals where 'percent to target' is the headline metric — fundraising progress, runway target, milestone count, Q-end revenue, etc. Props: `label`, `target` (the goal number), `aggregate` (sum/count/avg/min/max/latest), `field` (required for non-count), `since`, `filter` ({field, equals}), `prefix`/`suffix`/`precision`, `hint`. Bar color shifts amber → emerald as progress increases.
Block details
HeroBlock
Page header. Always at the top of a project. Anthropic-editorial style: large display title, optional eyebrow label, optional subtitle. The build agent fills in copy from your prompt.
Props:
title(required) — display headlineeyebrow— small uppercase label above the titlesubtitle— one or two sentences below
ChatBlock
The universal end-user data-entry primitive. Renders a chat surface; users describe what they want to add in natural language and the data agent translates that into rows in project_items. Replaces forms entirely — Atriux has no forms.
Props:
placeholder— input hint (e.g. "Try: just spoke with Acme, status warm")greeting— optional opener message from the assistantemptyState— copy when there's no history yet
ItemListBlock
Renders the user's items for the project as a vertical list, newest first. Reads from project_items filtered by (project_id, user_id). Each user sees their own items only.
Props:
primary(required) — schema field key to use as each row's main labelsecondary— optional sub-line field keyempty— copy when there are no items
StatBlock
Single big-number stat aggregated from project_items. Use multiple side-by-side for a dashboard top row.
Props:
label(required) — display nameaggregate(required) —sum|count|avg|min|max|latestfield— required for sum/avg/min/max/latest; ignored for countprefix/suffix— e.g.$orlbsprecision— decimal places (default 0 for sum, 1 for avg)since—today|week|month|year(time-window filter)
ChartBlock
Three chart types painted in pure SVG: bar, pie, line. Reads from project_items, aggregates by groupBy (categorical) or by day (line).
Props:
title(required) — headingtype(required) —bar|pie|linefield— numeric field to aggregate (omit for "count of items")groupBy— categorical field (required for bar/pie if you want grouping)aggregate—sum|count(defaults to sum when field is set)height— default 280px
TableBlock
Compact tabular view of project_items. Preferred over ItemListBlock when the project is data-heavy (transaction logs, ledgers, CRMs). Numeric and currency columns render right-aligned with tabular nums; sign-color columns tint negatives red and positives green.
Props:
columns(required) — array of field keys, max 8headers— optional column header overridescurrencyColumn— one column to format as$X,XXX.XXcolorColumn— one column rendered red/green by signsortBy/sortDir— defaults tocreated_atDESClimit— max rows; default 50, max 500title/empty— section copy
StatRowBlock
A row of 2–5 KPI tiles aggregated from project_items. Use this for the top-of-dashboard summary on finance, ops, or metric projects. Each tile can show a period-over-period delta (green for better, red for worse) — set invertSentiment: trueon tiles where "up = bad" (e.g. expenses).
Props:
title— optional row labeltiles— 2–5 array of {label, aggregate, field?, prefix?, suffix?, since?, compareTo?, invertSentiment?}
AgentResearchBlock 💰
Per-row Claude research with credit charge — the canonical monetization primitive for compose-mode trackers. Each row gets a Research button; clicking runs Claude Haiku with the project schema + the row's data + a creator-defined task prompt; the result is written back into data[outputField] and rendered inline. ~1–3 credits per click; rounds up to the nearest whole credit.
Props:
primary(required) — field key for the row headlineoutputField(required) — where Claude's reply lands. Must be schema-declared OR start withresearch_/ai_/notes_prompt(required) — the task. e.g. "Find the official careers page URL and the next likely hiring window for this company."secondary,buttonLabel,title,description,costHint
WebSearchBlock 💰
Per-row Tavily-backed web search with a flat 3-credit charge per call. Each row gets a Search button; clicking runs a query built from queryTemplate with {field}placeholders substituted from the row's data, then renders the top 6 results inline as link cards. Pairs naturally with AgentResearchBlock — search returns the raw web links, research summarizes them.
Props:
primary(required),secondaryqueryTemplate(required) — e.g. "recent funding news about {company}"outputField— defaults tosearch_resultsbuttonLabel,title,description
Requires TAVILY_API_KEYin the platform env. The endpoint returns 503 if unset; the block surfaces "Web search isn't configured" inline.
StatusFilterBlock
Pill-style filter strip bound to a select-typed schema field. Click a pill to scope the visible rows to one value (warm/hot/passed, or vendor/transaction/investor, etc.). Lifted from Job Lister's status filter pattern.
Props:
field(required) — must be aselectfield on the projecttitle— optional headerincludeAll— defaults true; show an "All" pill that clears the filter
TimelineBlock
Chronological timeline of items grouped by day with status dots. Use for journal-style projects (workouts, meals, calls, deals, research log) where "what happened when" is the primary view. Differs from ItemListBlock: groups by day with a vertical rail.
Props:
primary(required),secondarystatusField— a select field that drives dot colorstatusColors— record mapping status value → color name (amber/emerald/rose/blue/violet/zinc)title,empty,daysLimit(default 60)
CategoryTabsBlock
Multi-domain dashboard primitive. Binds to a select-typed schema field (conventionally category) and renders one tab per option value. Each tab picks its own display style — table (transactions, cap tables), list (prose), timeline (chronological), summary (KPI tiles). The data agent infers category from natural language so users add to the right tab without picking it.
Use for: projects covering multiple correlated categories of data — e.g. a finance tracker for vendors / transactions / cap table / reimbursements / budget — DO NOT split into multiple projects.
Props:
categoryField(required) — the select field; usuallycategorytabs(required) — 2–8 array of {value, label?, display, primary, secondary?, columns?, currencyColumn?, colorColumn?, empty?}title— optional header
category select field with options enumerating every category. Schema fields cover the union (date, amount, party, notes, etc.). One CategoryTabsBlock with one tab per category. ChatBlock for entry. AgentResearchBlock for monetization. Top-level StatRowBlock for cross-tab KPIs (total spend, runway months).MarkdownBlock
Long-form prose section with safe inline markdown. Use for intros, methodology notes, executive summaries, disclaimers, "how this works" explanations. Supports a subset of markdown: bold, italic, inline code, [links](https://...), bullets, ordered lists, blank-line paragraphs.
Props:
content(required) — markdown body, max 4000 charsheading— section headingeyebrow— uppercase label above heading
CalloutBlock
Tinted info / warning / success / danger / tip box. Use for project-wide warnings, deadline reminders, methodology notes, onboarding hints.
Props:
variant(required) —info|warning|success|danger|tiptitle— bold ledebody(required) — message text, max 800 chars
DividerBlock
Thin section separator with optional centered label. Use to break long pages into named sections.
Props:
label— centered textspacing—sm|md|lg(vertical margin)
FormulaBlock
The algorithm primitive. Display a computed value derived from a formula over aggregations of project_items. Use for derived KPIs the user can't compute by hand: runway months, burn ratio, equity remaining, conversion rate.
Safety: the formula is parsed by a tokenizer + recursive-descent evaluator that supports ONLY + - * /, parentheses, numeric literals, and named variables. No JS eval, no function calls, no property access.
Props:
label(required),formula(required) — e.g.cash / monthly_burnvariables(required) — record mapping name → {aggregate, field?, since?, filter?: {field, equals}}prefix,suffix,precision,hint
GoalProgressBlock
Progress bar toward a numeric target. Use for fundraising goals, runway targets, milestone counts, Q-end revenue.
Props:
label,target(required) — the goal numberaggregate(required),field(for non-count),since,filterprefix,suffix,precision,hint
CountdownBlock
Countdown to a target date. Two modes:
- Static — pass
targetDate(YYYY-MM-DD) for a fixed deadline. - Dynamic — pass
field(a date-typed schema field) and the block finds the soonest UPCOMING date across your items.
Updates every minute. Renders cleanly past zero.
CalendarBlock
Month-view calendar plotting items by a date field. Each day with events shows up to 4 colored dots; click a day to expand the events. Pairs naturally with CountdownBlock and TimelineBlock.
Props:
dateField(required),primary(required),secondarystatusField+statusColors— drives dot colortitle
ItemDetailBlock
Expandable per-row detail panel — the "click a row to see everything" pattern lifted from Job Lister's JobDetailPanel. Each row expands inline to show ALL its fields, including AI research output rendered as auto-linkified prose.
Props:
primary(required),secondary,badgeFielddetailFields— specific keys to show in expansion (omit to show ALL)title,empty
ResearchStatusBlock
At-a-glance progress of AI research across rows. Pairs with AgentResearchBlock — the read-only sibling. Renders "X of Y researched (Z%)" with a progress bar and the most recent N completed items.
Props:
outputField(required) — the field AgentResearchBlock writes toprimary(required) — row label fieldtitle,hint,recentLimit(default 5)
Monetization rule
Every compose-mode project MUST include at least one credit-charging block: ChatBlock, AgentResearchBlock, or WebSearchBlock. The build agent enforces this in finish_compose_project — projects without one are rejected. The marker 💰 in the catalog identifies which blocks satisfy the rule.
Block context
Every block component receives a BlockContext alongside its props:
interface BlockContext {
project: { id, name, slug, description, creator_user_id };
schema: { noun, noun_plural, fields } | null;
userId: string;
}Blocks that read data (ItemListBlock, StatBlock, ChartBlock) use ctx.project.id + ctx.userIdto scope their queries. Blocks never see other users' rows.
Adding a new block
New blocks are added to packages/blocks/blocks/<Name>.tsx and registered in packages/blocks/registry.tsx. The build agent picks them up automatically via describeCatalog() — no separate prompt edit needed.
A block is a BlockDef:
{
name: string; // matches BlockInstance.type
description: string; // shown to the build agent
schema: ZodType; // validates props at mount + agent-output time
Component: React.ComponentType<{ block: P; ctx: BlockContext }>;
}Next: Runtime SDK →