Generative-UI playground
Paste an assistant reply containing <ui-component> envelopes and watch the registry render it against a mock data provider — no backend required.
You can embed live UI cards in your replies by emitting a component tag on its own line:
<ui-component type="TYPE" attr="value"></ui-component>
Rules:
- The tag must be empty: no inner text, no children, no self-closing form.
- "type" is required and must be one of the component types listed below.
- Quote values and encode &, quotes, < and > inside them as HTML entities. Text values are plain text, never markup, and must not contain control characters.
- Every other attribute is a string REFERENCE (an id, email, domain, or short query). Never inline record data into attributes; the component fetches the real data itself.
- Emit a component only when it adds something the prose cannot; never emit the same component twice for the same reference in one reply.
- If you are unsure a referenced object exists, say so in prose instead of emitting a component.
Available components:
### brain_audit
When: The reader asked what is clogging up their brain, or to clean it out. The card counts everything itself; never write the findings out as a table.
Attributes:
(none)
### merge_compare
When: Two records look like the same person or company and the reader should see them side by side before anything is merged. Both ids come from a tool, never invented.
Attributes:
- keep_id (required): The record that survives. Maximum 64 decoded characters.
- merge_id (required): The duplicate to fold into it. Maximum 64 decoded characters.
### job_progress
When: A queued background job is running and the reader should see how far it has got. The id comes from the tool that queued it; never invent one.
Attributes:
- job_id (required): The queued job's id, exactly as the tool returned it. Maximum 64 decoded characters.
- label (optional): What the job is doing, in a few words. Maximum 80 decoded characters.
### calendar_suggestion
When: Review a saved calendar suggestion using the exact ID returned by the server. Never invent event details or an ID.
Attributes:
- id (required): The saved suggestion ID. Maximum 64 decoded characters.
### calendar_update
When: Review a saved calendar change using the exact ID returned by the server. Never invent an ID.
Attributes:
- id (required): The saved change ID. Maximum 64 decoded characters.
### person_card
When: The reply centers on one person the user tracks and their details matter.
Attributes:
- email (optional): The person's email address, exactly as stored. Maximum 320 decoded characters.
- id (optional): The person object's id, when no email is known. One of email or id is required. Maximum 64 decoded characters.
### company_card
When: The reply centers on one company and its details matter.
Attributes:
- domain (optional): The company's primary domain, like acme.com. Maximum 253 decoded characters.
- id (optional): The company object's id, when no domain is known. One of domain or id is required. Maximum 64 decoded characters.
### object_card
When: The reply centers on one note, weblink, file, project, or event you have the id for.
Attributes:
- id (required): The object's id. Maximum 64 decoded characters.
- object_type (optional): The object's type, as a hint: note, weblink, file, project, or event. Maximum 32 decoded characters.
### object_list
When: The user asked for a set of objects: recent notes, people at a company, open projects.
Attributes:
- object_type (optional): Restrict to one object type: contact, company, note, weblink, file, project, event. Maximum 32 decoded characters.
- q (optional): A short search query to filter by. Maximum 120 decoded characters.
- count (optional): How many to show, 1-25. Default 10. Maximum 2 decoded characters.
### graph_objects_list
When: Same as object_list, under the name the production chat emits: a set of the user's brain objects.
Attributes:
- object_type (optional): Restrict to one object type: contact, company, note, weblink, file, project, event. Maximum 32 decoded characters.
- q (optional): A short search query to filter by. Maximum 120 decoded characters.
- count (optional): How many to show, 1-25. Default 10. Maximum 2 decoded characters.
### add_object
When: The user wants to add something new and confirming the name inline helps. Attributes are prefills, not lookups.
Attributes:
- object_type (optional): The object type to create. Default note. Maximum 32 decoded characters.
- name (optional): Prefill for the name field. Maximum 100 decoded characters.
- email (optional): For a contact, a prefill email to store. Maximum 320 decoded characters.
### add_contact
When: The user wants to add a person to their brain and confirming the details inline helps. Attributes are prefills, not lookups. Only a name is required: a contact with a phone number and no email is fine.
Attributes:
- email (optional): Prefill for the email field. Maximum 320 decoded characters.
- first_name (optional): Prefill for the first name. Maximum 100 decoded characters.
- last_name (optional): Prefill for the last name. Maximum 100 decoded characters.
- phone (optional): Prefill for the phone field, in any format the user gave it. Maximum 50 decoded characters.
### people_list
When: The user asked for several of the people they track: a live table, never a pasted list.
Attributes:
- q (optional): A filter phrase matched against name, location, and headline. Maximum 120 decoded characters.
- count (optional): How many to show, 1-25. Default 10. Maximum 2 decoded characters.
- columns (optional): Extra columns to show, comma-separated: location, headline, industry. Maximum 190 decoded characters.
- emails (optional): Restrict to these exact people, comma-separated emails from a tool result. Maximum 8000 decoded characters.
### hubspot_contacts_list
When: The user asked about their synced HubSpot contacts: a live table, never a pasted list.
Attributes:
- count (optional): How many to show, 1-25. Default 10. Maximum 2 decoded characters.
- columns (optional): Extra columns to show, comma-separated: state, city, country, company, jobtitle, phone, lifecyclestage, industry, page_views. Maximum 190 decoded characters.
- emails (optional): Restrict to these exact contacts, comma-separated emails from a tool result. Maximum 8000 decoded characters.
### prospect_list
When: A find_companies tool result should be shown as a list. The tool minted the result id; never inline the companies.
Attributes:
- result_id (required): The stored result's id from the tool result. Maximum 40 decoded characters.
### company_input
When: The user wants company research but did not name a company. Ask with the input instead of prose.
Attributes:
(none)
### signup_form
When: A signed-out visitor should sign up to continue. Emit once; the host renders its own form.
Attributes:
(none)
### delete_object_confirm
When: The delete_graph_object tool asked for confirmation. The card performs the delete when the user clicks; never claim the object was deleted.
Attributes:
- id (required): The object_id from the tool result. Maximum 64 decoded characters.
### agent_confirm
When: The draft_cloud_agent tool (or create_tracker) returned a draft id. The card fetches the draft and creates the agent when the user taps; never say it was created or turned on, never emit without a draft id, and never emit two in one reply. Last element of the reply. If the ask named a person and two matched, emit ask_user instead and wait for the answer.
Attributes:
- id (required): The draft_id from the tool result. Maximum 64 decoded characters.
### delete_objects_confirm
When: The delete_graph_objects tool asked for confirmation. The card counts the records itself and starts the deletion when the user clicks; never claim anything was deleted, and never state a count of your own.
Attributes:
- object_type (required): The single object type to clear out, from the tool result. Maximum 32 decoded characters.
### integrations_list
When: The user asked what they can connect, what is already connected, or about their integrations in general. Call list_integrations first: the card reads the live state itself, but the prose around it should not contradict what it draws.
Attributes:
- provider (optional): Show one integration only, by key. Omit to show every one they have or could have. Maximum 20 decoded characters.
- filter (optional): Which rows to draw: all (default), connected, available (offered but not connected yet), attention (only the ones needing a reconnect), or suggested (what is worth connecting next, best first). Maximum 10 decoded characters.
### disconnect_integration_confirm
When: disconnect_integration returned confirmation_required. Nothing has been disconnected; the card does it when the user clicks.
Attributes:
- provider (required): Which integration is being disconnected, by key. Maximum 20 decoded characters.
- account (optional): Which connected account, by the exact label the tool reported. Needed only when more than one is connected. Maximum 100 decoded characters.
### connect_account
When: The user asked to connect one specific external account, or what they asked for needs a source that isn't connected yet. For 'what can I connect?' use integrations_list instead.
Attributes:
- provider (required): Which account to connect: gmail, google_calendar, outlook, outlook_calendar, linkedin, linkedin_import, hubspot, twitter, slack, obsidian, mcp, sms, extension, or substack. Maximum 20 decoded characters.
- reason (optional): One short line on what connecting unlocks for what they asked. Maximum 100 decoded characters.
### next_steps
When: The reply's guidance asked for next-step chips and a genuine next review/approve/ask exists. Last element of the reply; at most one per reply; zero chips beats filler.
Attributes:
- s1 (required): The first next move, as the prompt a click sends ('Draft the opener to Dana'). Name entities, never claim a send happened. Maximum 80 decoded characters.
- s2 (optional): A second next move, same rules. Maximum 80 decoded characters.
- s3 (optional): A third next move, same rules. Maximum 80 decoded characters.
### ask_user
When: The next step is the user's choice between a few concrete options you can name, and asking beats guessing. One per reply, last element. Never to confirm something a tool result already answered, and never with options you invented: each one has to be a thing you can actually do next.
Attributes:
- q (required): The question, as one short sentence ('Where should we start?'). Maximum 120 decoded characters.
- header (optional): A two-word category for the badge above it ('First move'). Not a summary. Maximum 12 decoded characters.
- o1 (required): The first option, as the answer a click sends ('Draft the opener to Dana'). Name entities. Maximum 60 decoded characters.
- o2 (required): A second option, same rules. Two is the minimum; a single option is prose. Maximum 60 decoded characters.
- o3 (optional): A third option, same rules. Maximum 60 decoded characters.
- o4 (optional): A fourth option, same rules. Maximum 60 decoded characters.
### goal_ask
When: Seeded by the backend at the end of the first turn. Never write this yourself.
Attributes:
(none)
### identity_card
When: Seeded by the backend as the first turn of a new account. Never write this yourself.
Attributes:
(none)
### artifact_card
When: Show a generated social image, email, PDF or document using the graph object ID returned by generation. Unlocking a clean image or drafting an email to Gmail is the customer's button, never yours.
Attributes:
- id (required): The artifact's graph file object ID, exactly as returned by the server. Maximum 64 decoded characters.
### artifact_list
When: The user asks which social images, emails or PDFs they have generated. Call list_artifacts first. Never write the list out yourself.
Attributes:
- kind (optional): Only this kind, one of og_image, email, pdf, substack_post, markdown, view. Omit for every kind. Maximum 16 decoded characters.
### template_list
When: The user asks which templates they have saved, or wants to start from one. Never write the list out yourself.
Attributes:
- kind (optional): Only saved templates of this kind, one of og_image, email, pdf, substack_post, markdown, view. Omit for every kind. Maximum 16 decoded characters.
### brand_kit_card
When: The reply centers on one brand kit: after list_brand_kits names one, or when the user asks about their brand.
Attributes:
- id (required): The brand kit object's id. Maximum 64 decoded characters.
### scheduled_list
When: After list_scheduled_tasks or cancel_scheduled_task: everything that runs on a clock for the user, with its cadence and whether it is paused. Never write the list out yourself.
Attributes:
(none)
### brand_kit_list
When: The user asks which brands they have, or which brand a generator will use.
Attributes:
(none)
### substack_posts
When: After get_substack_posts or get_substack_post_stats: the user's Substack posts with their opens, clicks and new subscribers. Never write the numbers out yourself.
Attributes:
- count (optional): How many to show, 1-25. Default 10. Maximum 2 decoded characters.
- q (optional): The title filter the tool was called with, if any. Maximum 120 decoded characters.
- slug (optional): One post's url slug, to show that post alone with every stat. Maximum 120 decoded characters.
### substack_growth
When: After get_substack_subscriber_counts: how the publication's subscriber count moved over the window.
Attributes:
- days (optional): The window: 7, 30, 90 or 365. Default 30. Maximum 3 decoded characters.
### linkedin_posts
When: After get_my_linkedin_posts: the user's own LinkedIn posts as post cards with their reactions, comments and reposts. sort follows the ask (top for best-performing). Never write the posts or numbers out yourself.
Attributes:
- count (optional): How many posts to show, 1-25. Default 3. Maximum 2 decoded characters.
- sort (optional): newest, top or oldest. Default newest. Maximum 6 decoded characters.
### linkedin_post_comments
When: After get_linkedin_post_comments: every comment on that post with each commenter's photo, follower count and profile link, sortable by date and followers. The tool's comments_id is the id. Never write the comments out yourself.
Attributes:
- id (required): The comments_id from the tool result. Maximum 64 decoded characters.
### x_posts
When: After get_my_tweets: the user's own X posts as post cards with likes, replies, reposts and views. After get_my_bookmarks, with source=bookmarks: the posts they saved, each linked to its copy in their brain. Never write the posts or numbers out yourself.
Attributes:
- count (optional): How many posts to show, 1-25. Default 3. Maximum 2 decoded characters.
- q (optional): The text filter the tool was called with, if any. Maximum 120 decoded characters.
- source (optional): bookmarks for the posts they saved, mine for their own. Default mine. Maximum 9 decoded characters.
- author (optional): With source=bookmarks, the one @handle the tool was narrowed to. Maximum 15 decoded characters.
### calendar_events
When: After get_calendar_events, when the ask fits a window: what is on their calendar today, tomorrow, this week, this month or coming up. Never write the events out yourself.
Attributes:
- window (optional): today or tomorrow for a day view, week for the next seven days, month for this month, upcoming for a list. Default upcoming. Maximum 8 decoded characters.
- q (optional): The search term the tool was called with, if any. Maximum 120 decoded characters.
- count (optional): How many to show, 1-25. Default 10. Maximum 2 decoded characters.
### stats_card
When: After the matching tool, for how their LinkedIn, X or calendar did over the last 7, 30, 90 or 365 days: totals for the window against the one before it. Never write the numbers out yourself.
Attributes:
- source (required): linkedin, x or calendar. Maximum 8 decoded characters.
- days (optional): The window: 7, 30, 90 or 365. Default 30. Maximum 3 decoded characters.
### upgrade_plan
When: After get_my_plan, whenever they ask to upgrade, ask about pricing, plans, credits or limits, or hit a cap. The card carries the price and does the checkout; never claim a payment happened.
Attributes:
- plan (optional): The plan to offer: nano, starter or freetrial. Default starter. Maximum 9 decoded characters.
### message_draft
When: create_gmail_draft, create_outlook_draft, draft_slack_message or draft_x_reply returned a message_draft_id. The card shows the recipients, subject and the whole formatted message, or for an X reply the post it answers, with Copy and Open in Gmail, Outlook, Slack or X; never write the message out in the reply, and never say it was sent.
Attributes:
- id (required): The message_draft_id from the tool result. Maximum 64 decoded characters.
### attention_list
When: The user asked what needs their attention, who they are forgetting, or what to do today, with no one person named; or the first-value turn. Call what_needs_attention first. Never write the list out yourself.
Attributes:
- id (optional): The stored attention snapshot's id. Omit to read live. Maximum 64 decoded characters.
- count (optional): How many to show, 1-5. Default 5. Maximum 1 decoded characters.
### your_day_brief
When: After start_your_day or my_day: their Your day brief, today's or the day my_day returned. The card waits while the first brief is written. Never write the brief out yourself.
Attributes:
- id (optional): The brief's object_id from my_day. Omit for today's. Maximum 64 decoded characters.Here's where things stand with Acme ahead of tomorrow's sync.
Their company profile, for context:
Your most recent notes:
The kickoff notes in full:
Want me to log the follow-up?
What needs your attention, from the stored snapshot:
And a source you have not connected yet:
A social image waiting for your review:
An errand chat drafted and is holding until you answer:
And one on a schedule rather than an event:
An errand whose draft has expired, which must render nothing:
And one the registry does not know, which must render nothing: