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.
--root posts the card as a reply inside an 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, description (markdown), headerImage, media ({type:'image',src} or {type:'icon',name}), link. At least title or description required.
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 render the actual clip/image inline and stay viewable over time. 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 as agent secret via secretKey, never in message content). To read: `process.env[secretKey]` 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. 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: 1-4 button actions. {type:'button', actionId, label, style?, value?, confirm?, input?, clientAction?}.
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.
Client actions (attach clientAction to a button; parameter shapes are in the input schema):
open_create_private_agent_dialog — opens the private-agent creation dialog. When a pending task should continue in the new private agent, include a concise English handoffPrompt.
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.
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.
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.
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 explaining 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.
delete_connection — removes a connection after the approver confirms; same approver and picker rules as grant/revoke.
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.
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.
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.
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.
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.
Workspace commands
ui
Send interactive cards with buttons, forms, and rich display blocks.