> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kylon.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ui

> Send interactive cards with buttons, forms, and rich display blocks.

```text theme={null}
kylon workspace ui — kylon workspace help detail

ui — interactive cards in a room
  kylon workspace ui send --fallback-text <text> [--blocks <json>] [--blocks-file <path>] [--title <text>] [--actions <json>] [--actions-file <path>] [--interaction-mode single|per_user|scoped_per_user] [--target-users <user_id,...>] [--out-of-scope-title <text>] [--out-of-scope-blocks <json>] [--root <message_id>] [--scope-room <room_id>]
    Post an interactive card: display blocks plus optional button actions.
    Use it only when the reply needs interactive controls (buttons, forms),
    dense visual data (stats, charts, rich tables), or other structured UI.
    Never for status updates, summaries, explanations, progress reports, or a
    reply that is really just text — send a normal message instead. Do not pair
    a card with a separate text message.
    --fallback-text is required: a complete standalone plain-text summary of
                   the card and its decision context. It is what appears in
                   notifications, transcripts, and later turns, so a button
                   label is not enough.
    --blocks / --actions take a JSON array. --blocks-file / --actions-file read
                   the same JSON from a file, which avoids shell quoting for
                   anything non-trivial. Pass at most one of each pair; blocks
                   are required one way or the other.
    Inside an Agent assignment, the card automatically replies to the
    current thread. --root posts it in a different existing thread.
    --target-users is required with --interaction-mode scoped_per_user.
    Every valid interaction wakes you with a follow-up turn carrying the card
    summary, the clicked action, and any submitted field values.

  BLOCKS (set type field):
    item — one rich row for a single entity (task, document, person, link preview): title, subtitle (short muted qualifier beside an identity title or under other titles, e.g. a role or status), description (markdown body), headerImage, media ({type:'image',src} or {type:'icon',name}), link, or one trailing button action object. action is top-level-item-only, cannot be combined with link or top-level payload actions, and does not support inline input. To intentionally present one specific page inside a Kylon App at full message width, use a TOP-LEVEL item with presentation:'app_preview', a title, and the canonical workspace-scoped internal App-page link under /apps/{appId}/p/. For a query- or fragment-only state at the App pathname root, use /apps/{appId}/p/?app_query=...&app_hash=...; NEVER put app_query or app_hash on the plain /apps/{appId} root because that route ignores App state and is rejected for app_preview. Do not add subtitle, description, headerImage, media, or actionRef, and do not use app_preview for a plain App root, draft, external URL, nested item, or secondary reference. Older clients render that payload as an ordinary linked item. Send separate cards for independently actionable items. At least title or description required. For a person or agent row, add shape:'circle' to image media so the avatar renders as a circle, put the concise role in subtitle, and use description only for a short task responsibility when needed.
    stats — 2-4 headline KPI cards. items: [{label, value, hint?, tone?}]. Not a general grid — for long tables prefer stack, table, or markdown. Prefer stats over chart when shape doesn't matter.
    alert — banner. Required: text, tone (default|info|success|warning|danger). Use for status, non-blocking errors, one-line notices. Do not prefix alert titles with status emoji/icons like 💡, ✅, ⚠️, or ❌; tone already renders the icon.
    chart — variant='area'|'bar'|'line' for comparisons/time-series: data rows + xKey + series [{key, label?}]. variant='pie' for part-of-whole: data [{name (non-empty string), value (number)}]. Prefer chart only when visual shape matters.
    markdown — content field for prose inside the UI message. Optional collapsedLines (1-20) renders a collapsed preview with Show more/less. Use fenced code blocks for exact values the user should copy, such as invitation links or commands. Use sparingly — if the entire reply is prose, send a normal markdown reply.
    collapsible — expandable detail (diagnostics, raw payloads, advanced settings). blocks (max 5): display-only content; optional defaultOpen. NO field_group and NO nested collapsible anywhere inside it, including inside stack/table descendants.
    separator — visual divider.
    stack — layout container. {direction?: 'vertical'|'horizontal', blocks: [child blocks]}. Use vertical stack with item children for comparable rows; use horizontal for side-by-side columns.
    table — rich table only when cells need nested blocks, media, forms, or richer layout. {columns: [{key, label, align?}], rows: [{cells: {<columnKey>: [child blocks]}}]}. For small plain-text comparisons, prefer a markdown table.
    image | video | audio — direct media leaf. {type, src, caption?} (image also alt?, video also poster?). Use inside table cells or stacks for media-rich layouts. src/poster accepts either an https URL users can fetch OR a workspace file link from kylon workspace file upload (e.g. /preview/workspaces/{workspaceId}/files/{fileId}?room={roomId}); file links stay viewable over time. Images render inline; video and audio render static preview entries and mount their players only after the user opens the media preview. For a video poster, extract a frame, kylon workspace file upload the image, and pass its file link. Do not use YouTube/Loom/page URLs here; direct video requires a playable .mp4/.webm-style media URL.
    external_video — embedded external video player. {type:'external_video', provider:'youtube', url, title?, caption?}. Use for YouTube watch/share/embed URLs when an inline YouTube player is desired. title sets the player accessibility label, not a visible heading; use caption for visible supporting text. The video must allow embedding; unlisted YouTube videos are fine when embedding is enabled. Do not use arbitrary iframe HTML.

  FORMS:
    field_group — input form. fields: [{type, fieldId, ...}]. Submitted value types per field:
      All fields may include defaultValue matching the submitted value shape. Use it to prefill inferred answers so users can confirm or edit.
      input → string. Optional placeholder, maxLength (1-2000). Use ONLY for inherently single-line values (a name, email, short label, ID).
      textarea → string. Multi-line autoresizing box with an internal scrollbar past maxRows. Optional placeholder, maxLength (1-10000), minRows (default 3), maxRows (default 10). Use whenever the answer may span more than one line (could contain line breaks or multiple paragraphs), or to have the user confirm/edit a draft you prepared — set defaultValue to the draft text so they can edit in place before submitting.
      password → string (stored encrypted as a credential of an API service granted to you, under secretKey in uppercase environment-variable form; never in message content). To read: `process.env[SECRET_KEY]` in your environment. List keys: `kylon workspace secret list`.
      select → string. 2-25 options [{label, value}].
      radio_group → string. 2-25 options. Prefer over select when choices should be visible. Shows a free-text Other value by default; set allowOther=false for closed enums.
      checkbox_group → string[]. 1-15 options, optional minValues/maxValues. Shows one free-text Other value by default; set allowOther=false for closed lists.
      workspace_member_picker → string for selectionMode='single', string[] for 'multiple'. Picks visible workspace member user IDs. Optional memberTypes ['human','agent']; defaults to human members.
      workspace_agent_picker → string for selectionMode='single', string[] for 'multiple'. Picks accessible workspace agent IDs. Optional allowNone for single mode; No agent submits '__none__'.
      workspace_connection_picker → string. Privately picks one connection ID visible to the user who opens the action input. For grants, require backend + toolkit (Composio: read_ai_mcp), or backend mcp + verified serverUrl for remote MCP. The server adds matching setup for agent grants. Use only inside action.input for targeted connection-access approvals; submitted IDs are server-redacted from message history.
      date → YYYY-MM-DD string. Optional min/max as ISO dates.
      slider → number. Required min, max (> min), step (> 0).

  ACTIONS: up to 4 footer button controls. {type:'button', actionId, label, style?, value?, confirm?, input?, clientAction?}. Server-owned actions referenced by a top-level item.actionRef render inline on that row and do not count toward the footer limit.
  Button click is the ONLY trigger that submits field_group values as inputValues. Pair forms with at least one button.
  Do not author tool_approval actions. Approval cards are server-owned: run the command for the protected operation; it creates the approval card and makes no change until approval.
  For input needed only after a specific action click, attach action.input: {presentation?, title, description?, submitLabel?, fields}. presentation defaults to 'modal'; use 'inline' when the input should replace the action row until submitted/cancelled. action.input fieldIds share the same message-wide namespace as field_group fields; never reuse a fieldId anywhere in the same message.
  For a click that needs explicit confirmation, attach action.confirm: {title, description, confirmLabel?} — an object, never a plain string. It renders a confirm dialog before the action fires.
  To create one or several internal agents, run `kylon workspace agent create --agents-json '<json array>'` with your proposed specs. The server sends an agent proposal card for the triggering human to approve; no creation form is needed. Set visibility explicitly: private for personal or unspecified use, public for shared workspace use.
  Client actions (attach clientAction to a button). Each one lists its parameters below: * required, ? optional, values are strings unless a choice or [] list is shown:
    open_connection_setup — starts provider setup from chat. Use for setupKind=messaging_byo and for connection setup cards where the user should stay in chat. Do not include field_group/action.input and do not ask for provider secrets in chat. For LINE, include agentId and explain that the modal will collect LINE credentials.
      params open_connection_setup: toolkit*, backend?('native'|'composio'|'mcp'|'messaging'), agentId?, targetUserId?
    open_connection_disconnect — opens a workspace connection disconnect modal. Use when a human asks to remove an owned workspace connection, especially when dependent resources may be deleted. Provide connectionId or connectionIdFieldId plus targetUserId; use a workspace_connection_picker in action.input when the owner must choose the connection. The UI checks impact, asks for any required destructive confirmation, and only then records the interaction.
      params open_connection_disconnect: connectionId?, connectionIdFieldId?, requestedByUserId?, targetUserId?
    link_existing_connection_to_agent — persistently links a grantable connection returned by kylon workspace connection list to this agent. Use only when the user explicitly wants persistent agent access outside delegated requests.
      params link_existing_connection_to_agent: connectionId*
    grant_connection_access / revoke_connection_access — persistent connection grant or revoke approved by targetUserId (defaults to the human who triggered this turn). For granteeType 'agent', include action.confirm whose description explains that the grant is persistent and anyone who can use that agent may ask it to access data through the connection. If the approver's connection is not already visible to you, never guess or expose a connection id; put workspace_connection_picker in action.input and reference its fieldId via connectionIdFieldId. Current-turn delegation does not need persistent grants, and user-created workflows or follow-ups carry the creator's delegation for later runs.
      params grant_connection_access: granteeType*('user'|'agent'|'workspace_members'|'room_members'), connectionId?, connectionIdFieldId?, granteeId?, granteeIdFieldId?, relation?('member'), requestedByUserId?, targetUserId?
      params revoke_connection_access: granteeType*('user'|'agent'), connectionId?, connectionIdFieldId?, granteeId?, granteeIdFieldId?, requestedByUserId?, targetUserId?
    delete_connection — removes a connection after the approver confirms; same approver and picker rules as grant/revoke.
      params delete_connection: connectionId?, connectionIdFieldId?, requestedByUserId?, targetUserId?
    open_connection_access_dialog — opens the connection owner's sharing dialog with your suggestion preselected; nothing changes until the owner saves. Use suggestedMode 'only-me' when the user asks to restrict the connection to themselves. Supports interactionMode 'scoped_per_user' with targetUserIds exactly [targetUserId] so only the owner can act while everyone else sees a waiting status.
      params open_connection_access_dialog: connectionId*, suggestedMode?('only-me'|'team'|'specific'), suggestedUserIds?[], suggestedAgentIds?[], targetUserId?
    join_public_rooms — joins the public rooms selected in a checkbox_group (roomIdsFieldId; values must be room IDs, so set allowOther=false) or a fixed roomIds list.
      params join_public_rooms: roomIds?[], roomIdsFieldId?
    install_skills_on_agents — installs skillIds on agents the requesting human picks via a workspace_agent_picker field (agentPickerFieldId) or a fixed agentIds list. The install runs as the human and is checked per agent.
      params install_skills_on_agents: skillIds*[], agentPickerFieldId?, agentIds?[]
    share_agent_secrets — grants selected agents access to your canonical workspace secrets via a visible workspace_agent_picker field (agentPickerFieldId). It does not copy values. Do not use secret set/list on the target agent, do not read or print secret values, and do not use hidden fixed agentIds. The approved grant runs as the clicking human and checks that they can access both agents.
      params share_agent_secrets: sourceAgentId*, secretKeys*[], agentPickerFieldId*

  INTERACTION MODES:
    interactionMode defaults to 'single'. Use 'single' when the card represents one shared decision or one side-effectful action; the first valid click consumes the card for everyone.
    Use 'per_user' when every eligible human in the room may respond independently, such as voting, preferences, or per-person input. Every response is visible to the whole room: each submission renders as a named read-only panel plus a clicked-status line.
    Use 'scoped_per_user' when only specific human users may respond independently, such as asking two named approvers. Provide targetUserIds. Everyone else in the room still sees the full card and every submission; they just get no controls, only a waiting status until the targets act.
    Multi-user modes control who may ACT, never who may SEE. Submitted field values are room-public (password fields stay secret-stored and masked). To collect information that other room members must not read, use password fields or ask in a DM or private room instead.
    Side-effectful clientAction buttons must use 'single' unless that action type explicitly documents support for another mode.
    fallbackText must be a complete standalone summary of the UI card and decision context, not just a button label. It is used in transcripts, notifications, and hidden interaction history.
    Every valid interaction triggers a follow-up turn with the card summary, clicked action, and submitted fields.

  POST-SUBMIT: In 'single' mode the card locks for everyone on click; in 'per_user' and 'scoped_per_user' it locks only for the actor, and the room sees their submission. You receive {sourceMessageId, actionId, label, value, inputValues} as a user turn.
  Do not update the prior card by default — reply fresh. For validation failures, re-send a NEW kylon workspace ui send with per-field errorMessage.

  RULES:
    1. fallbackText required — appears in notifications/transcript in place of the rendered UI.
    2. fieldId must be unique across every field_group and action.input field in the message. list item id must be unique within its list.
    3. Never echo password values. They are stored via secretKey, never in message content.

Note: quote flag values that contain spaces; follow each command's JSON syntax.
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.