# Candor UI > 239 shadcn/ui components and hooks for AI agents that do real work: chat, plans, approvals, diffs, runs, traces and evals, plus the app shell, team and admin screens around them. Components take plain, typed data; adapters map the Vercel AI SDK, the Claude Agent SDK and AG-UI. By Methodic LLC. Install with the candor-ui CLI (it wraps shadcn and keeps a lockfile for updates): ```bash npx candor-ui@latest init --yes npx candor-ui add thread message composer ``` Files land where shadcn puts them: `@/components/`, `@/components/ui/` and `@/lib/` (types are in `@/lib/chat`). Components with state or handlers need "use client" in the Next.js App Router. Pro and Premium items need a licence key, which the person adds with `npx candor-ui key ` (never in chat or a committed file). `npx candor-ui update` updates installed items and keeps local changes; `npx candor-ui doctor` checks the setup. Getting started: https://candor.themethodic.com/get-started. Without the CLI, add `"@candor": "https://candor.themethodic.com/r/{name}.json"` to components.json and use `npx shadcn@latest add @candor/`. Rules every Candor screen keeps: model output is never rendered as HTML or a clickable link; unknown values stay unknown and estimates are labelled; a control that can't be used says why; nothing is pre-selected in a decision; the agent is named from app data, never from model output. Free items are MIT; the rest are under the Candor UI Commercial Licence. Every docs page is Markdown at its address plus `.md` (https://candor.themethodic.com/docs/thread.md), listed below. The docs MCP server at https://candor.themethodic.com/mcp (remote, streamable HTTP, read-only, no key) searches them and suggests components for a task; in Claude Code: `claude mcp add --transport http candor https://candor.themethodic.com/mcp`. - [Get started](https://candor.themethodic.com/get-started.md): install, connect an agent, licence keys, updates, the lockfile, moved files and `verify` for CI - [Setup guides](https://candor.themethodic.com/guides): the registry, the docs MCP server in each tool's own config and the skill, for Claude Code, Cursor, Codex, VS Code with Copilot, Windsurf, Zed, Cline, OpenCode, JetBrains, v0, Lovable and Replit - [Agent skill](https://github.com/MethodicDev/candor/tree/main/skills/candor-ui): install with `npx skills add MethodicDev/candor` - [Agent UI skill](https://github.com/MethodicDev/candor/tree/main/skills/candor-agent-ui): design fundamentals for screens where an AI agent acts, with a review checklist to run after each screen; works with or without Candor - [Design system](https://candor.themethodic.com/design.md): every colour role and what it's for, the type scale, radius, shadows, motion, density and themes, read from the shipped CSS, and how to re-token for a brand - [Review checklist](https://candor.themethodic.com/review-checklist.md): one line per check, each tied to a rule, for after each screen - [Full reference](https://candor.themethodic.com/llms-full.txt): every component with its props ## Chat A conversation with an agent: messages, the composer, tool calls, reasoning, citations. ### a2ui-surface (Pro) Draws an A2UI surface with Candor's parts, streaming or finished, with inputs bound to its data model. Install: `npx candor-ui add a2ui-surface` `` props: - `state: A2uiStore | A2uiState`: A store from createA2uiStore, or a state from applyA2uiMessages. - `surfaceId: string`: Which surface to draw. - `onAction?: A2uiActionHandler | undefined`: Called when a person uses a control with an event action. - `allowImages?: boolean | undefined` (default `false`): Load https and data: images the agent points to. Off by default. - `allowMedia?: boolean | undefined` (default `false`): Load https and data: video and audio the agent points to. Off by default. - `className?: string | undefined` ### agent-avatar (free) An agent's glyph and hue by role, so people can tell agents apart at a glance. Install: `npx candor-ui add agent-avatar` `` props: - `agent: AgentIdentity`: Who the agent is: id, display name and role. - `size?: "sm" | "md" | undefined` (default `"md"`): md for message headers, sm for lists and chips. - `className?: string | undefined` `` props: - `agent: AgentIdentity`: Who the agent is: id, display name and role. - `size?: "sm" | "md" | undefined` (default `"md"`): md for message headers, sm for lists and chips. - `className?: string | undefined` `` props: - `roles: Record`: Role ids mapped to an icon, a noun and a hue. - `children: React.ReactNode` ### ai-content-label (Pro) A label for content that is wholly or partly AI-generated: "AI-generated", "AI-modified", or "AI involvement not recorded" when the app has no record. Install: `npx candor-ui add ai-content-label` `` props: - `involvement: AiInvolvement`: How much AI went into it, from the app's records. - `by?: string | undefined`: The tool or agent that was used, named by the app ("Drafting agent"). Shown for "generated" and "modified" only. - `at?: Date | string | undefined`: When it was made or changed, as a Date or ISO string. Shown for "generated" and "modified" only. - `note?: string | undefined`: The app's own plain-text note, e.g. "Figures checked by finance". Shown in the caption; not part of copied text. - `size?: "inline" | "caption" | undefined` (default `"inline"`): "inline" (the default): a small chip beside a message or file name. "caption": a line under an image or file, with the note. - `className?: string | undefined` ### ai-disclosure (free) A plain notice that the person is interacting with an AI system: a first line in the thread (`variant="line"`) or a compact "AI" badge for a thread header (`variant="badge"`) that opens to the app's own explanation. Install: `npx candor-ui add ai-disclosure` `` props: - `agent?: AgentIdentity | string | undefined`: The agent, named by the app: an AgentIdentity or a plain name. Left out, the notice says "an AI system". Never model text. - `variant?: "line" | "badge" | undefined` (default `"line"`): "line" (the default) for a first line in the thread; "badge" for a compact mark in a header, e.g. ThreadHeader's. Place each where it fits. - `details?: string | undefined`: The app's own plain text about the system: who operates it, what data it uses, how to reach a person. Shown under the line, or in the badge's explanation. - `onLearnMore?: (() => void) | undefined`: Opens the app's own page or dialog about its AI use. A callback, never a URL from the model. Shows a "Learn more" button. - `className?: string | undefined` ### attachment-preview (free) A file waiting to be sent, as a chip in the composer: its name, then upload progress, an error, or its size, and a remove button. Install: `npx candor-ui add attachment-preview` `` props: - `attachment: Attachment`: The file, with progress (0–1) while uploading or an error if it failed. - `onRemove?: ((id: string) => void) | undefined`: Shows a remove button. - `className?: string | undefined` `` props: - `attachment: Attachment`: The file. `previewUrl` must be one your app serves (a thumbnail, a blob: URL); it's shown only for images. - `onOpen?: ((attachment: Attachment) => void) | undefined`: Makes the tile a button that opens the file. - `className?: string | undefined` `` props: - `attachments: Attachment[]`: The files. - `onOpen?: ((attachment: Attachment) => void) | undefined`: Makes each tile a button that opens its file. - `className?: string | undefined` ### card-registry (free) A card an agent's reply can carry. Install: `npx candor-ui add card-registry` `` props: - `name: string`: Which card to draw, from the registry. - `props: unknown`: The card's data, checked before it draws. - `summary: string`: The plain-text version, shown when the card can't be. `` props: - `cards: Record`: Your app's cards by name, made with defineCard. - `children: React.ReactNode` ### citation (free) An inline [n] that opens its source in a popover, so evidence is one step away without leaving the thread. Install: `npx candor-ui add citation` `` props: - `source?: MessageSource | undefined`: The source this marker points to; without it the marker says it's unknown. - `marker?: number | undefined`: The number to show when there's no source. `` props: - `sources: MessageSource[]`: Every source the reply used, in marker order. - `className?: string | undefined` `` props: - `source: MessageSource`: The source this marker points to; without it the marker says it's unknown. ### composer (free) Where a person writes to the agent: @ mentions attach things as references, / starts a known action, and the scope says where the ask runs. Install: `npx candor-ui add composer` `` props: - `value: string`: The text in the box. - `onChange: (value: string) => void`: Called with the new text as the person types. - `onSubmit: (value: string, references: EntityRef[]) => void`: Called on send with the text and the entities mentioned. - `onStop?: (() => void) | undefined`: Shown as Stop while a reply is streaming. - `state?: ComposerState | undefined` (default `"ready"`): ready, sending, streaming, locked (with a reason), held (typing open, sending waits, with a reason) or offline. - `scope?: ComposerScope | undefined`: Where the next message's work lands; production turns the pill to a warning. - `onScopeClick?: (() => void) | undefined`: Makes the scope pill a button, e.g. to change environment. - `mentions?: MentionOption[] | undefined` (default `[]`): What @ can insert, grouped under their headings. - `commands?: SlashCommand[] | undefined` (default `[]`): What / can run, only at the start of a message. - `references?: EntityRef[] | undefined` (default `[]`): Entities already attached, shown as chips. A chip added after the composer drew pops in; a removed one pops out. - `onReferencesChange?: ((references: EntityRef[]) => void) | undefined`: Called when a chip is added or removed. - `attachments?: Attachment[] | undefined` (default `[]`): Files attached, with upload progress or an error, as chips that pop in when added and out when removed. - `onAttach?: ((files: File[]) => void) | undefined`: Shows an attach button; called with the chosen files. - `accept?: string | undefined`: Which files the attach button's picker offers, as for `` (e.g. "image/*,.pdf"). Files pasted or dropped arrive as they are, so check types where you upload. - `onRemoveAttachment?: ((id: string) => void) | undefined`: Called when a file is removed. - `placeholder?: string | undefined`: Shown in the empty box; "Ask a question, or describe a change" by default. - `label?: string | undefined`: The accessible name of the text box; "Message" by default. - `tools?: React.ReactNode | undefined`: Your own controls in the toolbar, after the attach button: a dictation button, a model picker. - `hints?: boolean | undefined` (default `true`): The keyboard hints shown at wide widths ("↵ send · ⇧↵ new line"), naming @ and / only when `mentions` or `commands` are given. Defaults to true; false hides them. - `textareaRef?: React.Ref | undefined`: The text box, to focus it or read its selection from outside. - `sendShape?: "square" | "round" | undefined` (default `"square"`): The send button's shape: "square" (the default, rounded corners) or "round". - `className?: string | undefined` ### context-meter (free) What fills the model's context budget, as a ring in the composer that opens to a breakdown: system, instructions, Know, the thread, tools, files. Install: `npx candor-ui add context-meter` `` props: - `segments: ContextSegment[]`: What fills the context window, by kind, in tokens. - `limit: number`: The model's context window, in tokens. - `className?: string | undefined` ### dictation (Pro) Voice input for the composer: a microphone button that dictates speech to text into the message box, on the device or through your own transcribe, for the person to edit before sending. Install: `npx candor-ui add dictation` `` props: - `value: string`: The text the words go into, usually the composer's `value`. - `onChange: (value: string) => void`: Called as words arrive, usually the composer's `onChange`. - `lang?: string | undefined`: A BCP 47 language such as "en-GB". Left out, LocaleProvider's locale, else the page's `lang`, else the browser's. - `transcribe?: Transcribe | undefined`: Your own speech-to-text. With it, the browser's speech recognition isn't used; the recording goes only to this. - `allowBrowserService?: boolean | undefined`: Let the browser's own speech service hear the audio. Some browsers (Chrome among them) send it to the browser maker's servers. Off by default: without `transcribe`, dictation runs only where the browser recognises speech on the device, and is unavailable elsewhere. - `maxSeconds?: number | undefined`: Stops listening after this many seconds of listening (not counting the permission prompt); 120 by default. - `whenUnsupported?: "hide" | "explain" | undefined` (default `"hide"`): Where dictation can't run: "hide" the button (the default), or "explain" with a locked button that says why. - `disabled?: boolean | undefined` (default `false`): Off while the composer can't take input, e.g. when it's locked or a reply is streaming. - `className?: string | undefined` ### entity-chip (free) A thing in the user's system (a table, a record, a flow) as a chip with its kind's icon, that can open it. Install: `npx candor-ui add entity-chip` `` props: - `entity: EntityRef`: The thing to show: its kind, identifier and optional label. - `onOpen?: ((entity: EntityRef) => void) | undefined`: Makes the chip a button that opens the thing. - `onRemove?: ((entity: EntityRef) => void) | undefined`: Adds a remove button, e.g. in the composer. - `className?: string | undefined` `` props: - `kinds: Record`: Kind ids mapped to an icon and a noun. - `children: React.ReactNode` ### entity-disambiguation (Pro) When a name matches more than one thing ("Account" the table, the report, the record type), the agent asks which one instead of guessing. Install: `npx candor-ui add entity-disambiguation` `` props: - `term: string`: What the person typed, e.g. "Account". - `candidates: EntityCandidate[]`: The things the term could mean, with kind, API name and what sets each apart. - `onChoose: (entity: EntityRef) => void`: Called with the chosen entity. - `onNone?: (() => void) | undefined`: Shows "None of these"; called when it's picked. - `chosen?: EntityRef | null | undefined`: The settled choice, if one was made. - `className?: string | undefined` ### folded-turns (free) A run of turns folded into one line, for long agent work a reader doesn't need to see step by step: "Drafted three versions and compared them". Install: `npx candor-ui add folded-turns` `` props: - `count: number`: How many turns are inside, for the button ("Show 12 turns"). - `summary?: React.ReactNode | undefined`: What happened in them, shown on the folded line: text or your own small summary. - `defaultOpen?: boolean | undefined` (default `false`): Start open. - `open?: boolean | undefined`: Controlled open state. - `onOpenChange?: ((open: boolean) => void) | undefined`: Called when a person opens or closes it. - `header?: React.ReactNode | undefined`: Your own folded line instead of the dashed one: a card with a title, how it ended, its cost, actions. The Show/Hide button follows it, so the turns can still be opened. - `children: React.ReactNode`: The turns, usually Messages. - `className?: string | undefined` ### mcp-app-frame (Pro) Shows an MCP App, a tool's own UI, isolated in a sandbox on another origin; without a sandbox it says why instead of running it. Install: `npx candor-ui add mcp-app-frame` `` props: - `html: string`: The ui:// resource's HTML (mime text/html;profile=mcp-app). - `resourceMeta?: McpUiResourceMeta | undefined`: The resource's `_meta.ui`: csp domains, permissions, prefersBorder. - `toolInput?: Record | undefined`: The tool call's arguments, sent once the view is ready. - `toolResult?: McpToolResult | undefined`: The tool's result, sent after the input when it arrives. - `toolCancelled?: string | undefined`: Set when the tool call was cancelled; the reason is sent to the view. - `sandboxProxyUrl?: string | undefined`: Your hosted sandbox proxy page (see mcpAppSandboxProxyHtml), on another origin. - `callableTools?: readonly string[] | undefined`: Tool names the view may call through you (see appCallableTools). Default none. - `onCallTool?: ((name: string, args: Record) => Promise) | undefined`: Runs a tool the view calls, if it's in callableTools; called with its name and arguments. Without it, calls are refused. - `onMessage?: ((message: McpAppMessage) => void | Promise) | undefined`: Called when the view asks to add a message to the conversation. Without it, the request is refused. - `onOpenLink?: ((url: string) => void | Promise) | undefined`: Handle a link the view asks to open. Default: show it for the person to copy. - `theme?: "light" | "dark" | undefined`: Defaults to the page's Candor theme. - `title?: string | undefined`: Names the frame for assistive tech; "Tool app" by default. - `maxHeight?: number | undefined` (default `720`): The tallest the frame grows to, in pixels. - `hostOrigin?: string | undefined`: This app's origin; defaults to window.location.origin. - `className?: string | undefined` ### message-actions (free) Copy, retry and rate under an agent's reply. Install: `npx candor-ui add message-actions` `` props: - `text?: string | undefined`: What Copy copies; without it there's no Copy. - `onRetry?: (() => void) | undefined`: Shows Retry. - `rating?: Rating | undefined`: The current rating: up, down or none. - `onRate?: ((rating: Rating) => void) | undefined`: Shows thumbs up and down. - `meta?: React.ReactNode | undefined`: Facts after the actions, e.g. the model and cost. - `className?: string | undefined` ### message-branches (Pro) Page through versions of a reply (after a retry or an edited question): "‹ 2 / 3 ›". Install: `npx candor-ui add message-branches` `` props: - `index: number`: The version shown, from 0. - `count: number`: How many versions there are. Renders nothing below 2. - `onChange: (index: number) => void`: Called with the index of the version to show when a person pages back or forward. - `className?: string | undefined` ### message-content (free) A message's typed blocks (paragraphs, lists, code, tool calls, cards), rendered as text, never as markdown or HTML. Install: `npx candor-ui add message-content` `` props: - `blocks: MessageBlock[]`: The reply as typed blocks: paragraphs, lists, payloads, tool calls, cards, attachments. - `sources?: MessageSource[] | undefined` (default `[]`): Sources the blocks cite by marker. - `onOpenEntity?: ((entity: EntityRef) => void) | undefined`: Makes entity chips open their thing. - `onNavigate?: ((to: string) => void) | undefined`: Follows in-app links; links from a model are never rendered. - `onOpenAttachment?: ((attachment: Attachment) => void) | undefined`: Makes attachment tiles buttons that open their file. - `bareCode?: boolean | undefined`: Code and other payload blocks without their frame and title bar (Payload's `bare`). - `className?: string | undefined` `` props: - `nodes: InlineNode[]`: Inline nodes: text, strong, code, entities, citations. ### message (free) One message in a thread. Install: `npx candor-ui add message` `` props: - `message: MessageData`: The message: author, status, blocks, and optional reasoning, sources and attribution. - `onOpenEntity?: ((entity: EntityRef) => void) | undefined`: Makes entity chips open their thing. - `onNavigate?: ((to: string) => void) | undefined`: Follows in-app links. - `onOpenAttachment?: ((attachment: Attachment) => void) | undefined`: Makes attachment tiles buttons that open their file. - `onRetry?: (() => void) | undefined`: Shows Retry on a failed or finished reply. - `onContinue?: (() => void) | undefined`: Shows Continue on an interrupted reply. - `rating?: Rating | undefined`: The current rating of an agent reply. - `onRate?: ((rating: Rating) => void) | undefined`: Shows thumbs up and down under agent replies. - `reviewedBy?: { name: string; at?: string | undefined; edited?: boolean | undefined } | undefined`: A person who checked this agent reply before it was sent: "Checked by Sam", or "Edited by Sam" when they changed it. - `footer?: React.ReactNode | undefined`: More lines under an agent reply, after who checked it and above the actions row: e.g. MemoryUsed. - `actions?: false | React.ReactNode | undefined`: The row under an agent reply (copy, retry, rating). `false` hides it; a node replaces it, e.g. your own buttons. Model and cost still show, on their own line. To rebuild a message, use MessageHeader, MessageBody and MessageFooter. - `meta?: false | React.ReactNode | undefined`: The line under a person's own message: their name and when they sent it. `false` hides it; a node replaces it. - `timeFormat?: "relative" | DateStyle | undefined`: How times show: "relative" (the default, "5 minutes ago") or an absolute "time", "date" or "datetime" in the locale. - `density?: "default" | "compact" | undefined` (default `"default"`): "compact" draws the header row smaller: a 12px name in a 24px row, for dense layouts. Defaults to "default". - `bareCode?: boolean | undefined`: Code and other payload blocks without their frame (Payload's `bare`). - `className?: string | undefined` `` props: - `name: string`: The sender's displayed name. - `detail?: string | undefined`: A quieter detail after the name: an agent's specialty, a person's team. - `createdAt?: string | undefined`: When it was sent; shown as a relative time unless `timeFormat` says otherwise. - `timeFormat?: "relative" | DateStyle | undefined`: "relative" (the default) or an absolute "time", "date" or "datetime" in the locale. - `density?: "default" | "compact" | undefined` (default `"default"`): "compact": a 12px name in a 24px row. Defaults to "default" (14px in 28px). - `children?: React.ReactNode | undefined`: Anything else for the row, after the time (a badge, a menu). - `className?: string | undefined` `` props: - `message: MessageData`: The message whose reasoning and blocks to show. - `onOpenEntity?: ((entity: EntityRef) => void) | undefined`: Makes entity chips open their thing. - `onNavigate?: ((to: string) => void) | undefined`: Follows in-app links. - `onOpenAttachment?: ((attachment: Attachment) => void) | undefined`: Makes attachment tiles buttons that open their file. - `bareCode?: boolean | undefined`: Code and other payload blocks without their frame. - `className?: string | undefined` `` props: - `message: MessageData`: The message the footer belongs to. - `onRetry?: (() => void) | undefined`: Shows Retry on a failed or finished reply. - `onContinue?: (() => void) | undefined`: Shows Continue on an interrupted reply. - `rating?: Rating | undefined`: The current rating. - `onRate?: ((rating: Rating) => void) | undefined`: Shows thumbs up and down. - `reviewedBy?: { name: string; at?: string | undefined; edited?: boolean | undefined } | undefined`: A person who checked the reply before it was sent. - `footer?: React.ReactNode | undefined`: More lines after who checked it and above the actions row: e.g. MemoryUsed. - `actions?: false | React.ReactNode | undefined`: `false` hides the actions row, a node replaces it; model and cost still show. - `timeFormat?: "relative" | DateStyle | undefined`: How the reviewer's time shows: "relative" (the default) or an absolute "time", "date" or "datetime". - `className?: string | undefined` `` props: - `attribution?: MessageData["attribution"] | undefined`: The service's measured values; nothing shows when both are absent. - `className?: string | undefined` ### payload (free) A block of code or query text from the agent: a query it ran, code it wrote, a config file. Install: `npx candor-ui add payload` `` props: - `language: PayloadLanguage`: Shown as the label, e.g. json, sql, python. Never executed or highlighted as HTML. - `text: string`: The code or query, shown as text. - `title?: string | undefined`: What it is, e.g. "The query I ran". Not shown when `bare`. - `bare?: boolean | undefined` (default `false`): Just the code: no border, language label or copy button, for inside something that has them. - `highlight?: boolean | undefined`: Colour the code by its syntax. Left out, it follows the nearest `data-syntax` attribute (off by default). - `className?: string | undefined` ### permission-prompt (free) A tool call waiting for a person's go-ahead: what it will do, why it reached them, and the permission mode the run is in. Install: `npx candor-ui add permission-prompt` `` props: - `request: PermissionRequest`: The waiting request. - `mode?: string | undefined`: The run's permission mode, as the SDK names it ("default", "acceptEdits", "plan", "auto"…). Left out, it isn't shown. - `suggestions?: PermissionSuggestion[] | undefined`: "Don't ask again" rules to offer. None is ticked. - `editable?: boolean | undefined` (default `false`): Let the person edit the input as JSON before allowing it. - `onAllow: (answer: PermissionAnswer) => void`: Called with the edited input, the ticked rules or the answers. - `onDeny: () => void`: Called when the person denies it (or won't answer the questions). - `busy?: boolean | undefined` (default `false`): The answer is being sent: both buttons wait, and the waiting pulse stops. - `className?: string | undefined` ### prompt-suggestions (free) Prompts to start from. Install: `npx candor-ui add prompt-suggestions` `` props: - `suggestions: PromptSuggestion[]`: What to offer. - `onChoose: (suggestion: PromptSuggestion) => void`: Called with the chosen one; put it in the composer to edit rather than sending it. - `label?: string | undefined`: The heading above the suggestions; "Try asking" by default. - `loading?: boolean | undefined` (default `false`): Shows placeholders while suggestions load. - `variant?: "chips" | "cards" | undefined` (default `"chips"`): Compact chips, or larger cards for an empty thread. - `className?: string | undefined` ### reasoning (free) The agent's stated reasoning above its answer. Install: `npx candor-ui add reasoning` `` props: - `entries: ReasoningEntry[]`: The steps, each verified (with evidence), believed or assumed. - `thinking?: boolean | undefined` (default `false`): The agent is still thinking; opens the panel and shows progress. - `thoughtFor?: string | undefined`: How long it thought, once known, e.g. "6s". - `className?: string | undefined` ### report-reply (Pro) Flag a reply for a person to review: why, and an optional note. Install: `npx candor-ui add report-reply` `` props: - `reviewer: string`: Who sees the report, e.g. "the quality team". - `onReport: (reason: ReportReason, note: string) => void | Promise`: Called on send with the reason and the trimmed note (empty if none); the send button waits on a returned promise. - `className?: string | undefined` ### selection-actions (Pro) Select text inside a reply and act on just that part: ask a follow-up about it, have it explained, or quote it into the composer. Install: `npx candor-ui add selection-actions` `` props: - `onAction: (action: SelectionAction, text: string) => void`: Called with the action picked and the selected text. - `children: React.ReactNode` - `className?: string | undefined` ### standard-cards (Pro) The cards Candor ships, ready to register: query results, metrics, a plan (with its state: proposed, accepted or sent back), a blast radius and test results. Install: `npx candor-ui add standard-cards` ### thread-divider (free) A rule across the thread with a label in the middle: a day ("Today", "Yesterday", "5 Nov 2026") or a chapter of the conversation ("Drafting", "Review"). Install: `npx candor-ui add thread-divider` `` props: - `date?: Date | string | undefined`: A day to mark, shown as Today, Yesterday or the date in the locale. With neither this nor `label`, a plain rule. - `label?: string | undefined`: A chapter or any other label; wins over `date`. - `className?: string | undefined` ### thread-event (free) A quiet, centred line in a thread for something that happened rather than something said: "Sam joined", "Switched to the staging environment", "Run stopped by a guardrail". Install: `npx candor-ui add thread-event` `` props: - `icon?: LucideIcon | null | undefined` (default `Info`): The glyph before the text; `null` for none. Default: an info mark. - `tone?: "quiet" | "attention" | undefined` (default `"quiet"`): "quiet" (the default) or "attention", for an event a reader shouldn't miss. - `at?: string | undefined`: When it happened, shown after the text as a relative time. - `timeFormat?: "relative" | DateStyle | undefined`: "relative" (the default) or an absolute "time", "date" or "datetime" in the locale. - `align?: "center" | "start" | undefined` (default `"center"`): "center" (the default), or "start": a left-aligned line (right-aligned in RTL) with the time at its end. - `children: React.ReactNode`: What happened, in a short line. - `className?: string | undefined` ### thread-header (Pro) The bar above a thread: its title, the environment it acts on, and who is working on it right now. Install: `npx candor-ui add thread-header` `` props: - `title: string`: The thread's name. - `scope?: ComposerScope | undefined`: The environment the thread acts on, shown as a tag; production shows a warning. Without one, no tag. - `working?: AgentIdentity[] | undefined` (default `[]`): Agents currently running on this thread. - `actions?: React.ReactNode | undefined`: Buttons at the right end, e.g. share or close. - `className?: string | undefined` ### thread (free) The scrolling message column. Install: `npx candor-ui add thread` `` props: - `children?: React.ReactNode | undefined` - `empty?: React.ReactNode | undefined`: Shown before the first message. - `footer?: React.ReactNode | undefined`: Below the messages, usually the composer. - `className?: string | undefined` - `contentClassName?: string | undefined`: Classes for the message column. - `virtualize?: boolean | undefined` (default `false`): Render only the messages in or near view, for histories of hundreds of messages. Give each child a `key`. Defaults to false. - `anchor?: string | undefined`: The `id` of an element in the thread to open at, instead of the bottom: a chapter divider, or the card that needs the reader. Read once, when the messages first appear; if it isn't among them, the thread opens at the bottom. Ignored with `virtualize`, where it may not be rendered yet. - `scrollerRef?: React.Ref | undefined`: The scrolling element, for your own scroll handling. - `onDrop?: ((event: React.DragEvent) => void) | undefined`: Files or other data dropped on the thread. Dragging over it is allowed only when this is given. - `fade?: boolean | undefined` (default `true`): The soft fade at the bottom of the column. Defaults to true. ### tool-call (free) One tool call as a compact row: what it did in plain words, its status, and how long it took. Install: `npx candor-ui add tool-call` `` props: - `call: ToolCallData`: The call: tool name, plain-words title, status, input, output, duration or error. - `className?: string | undefined` `` props: - `calls: ToolCallData[]`: Several calls, summarised as a group. - `className?: string | undefined` ## Agent work What an agent proposes and does: plans, approvals, diffs, runs, receipts. ### agent-activity (Pro) Who is working right now: each agent, what it is doing in plain words, and its state in words beside the dot, so state is never colour alone. Install: `npx candor-ui add agent-activity` `` props: - `agents: AgentActivityEntry[]`: One entry per agent: who, what it's doing now, its status and your word for it. - `label?: string | undefined`: The list's accessible name. Defaults to "Agents". - `staleAfter?: number | undefined` (default `STALE_AFTER`): How long a running agent may be silent before it's no longer called running, in milliseconds. Defaults to two minutes. - `className?: string | undefined` ### approval-queue (Pro) Approval requests by what they need from the viewer. Install: `npx candor-ui add approval-queue` `` props: - `requests: ApprovalRequest[]`: Every request; the tabs sort them into needs you, waiting on others and decided. - `onOpen?: ((id: string) => void) | undefined`: Called with a request's id when its row is clicked. - `activeId?: string | undefined`: The id of the request open beside the queue, marked as current. - `className?: string | undefined` ### approval-request (Pro) A request for second-level approval: what changes, where, what it touches, whether it can be undone, and the hash that ties the decision to exactly this change. Compact for a phone or a notification. Install: `npx candor-ui add approval-request` `` props: - `request: ApprovalData`: The request: the change, where, its impact, whether it can be undone, its hash and state. - `onApprove?: ((hash: string) => void) | undefined`: Called on approve with the change hash, so the decision binds to exactly this change. - `onReject?: ((hash: string, note?: string) => void) | undefined`: Called on reject with the change hash, and the rejecter's note when `rejectNote` is on and they wrote one. - `rejectNote?: boolean | undefined` (default `false`): Reject first opens a box for an optional note saying why, then asks to confirm. Off by default. - `onWithdraw?: (() => void) | undefined`: Shown to the requester while pending. - `onRetry?: (() => void) | undefined`: Shows Try again when the decision failed to record; called when it's clicked. - `change?: React.ReactNode | undefined`: The diff or canonical change, shown on demand. - `maxChips?: number | undefined` (default `5`): How many affected components show as chips before the rest fold away. Defaults to 5. - `density?: "default" | "compact" | undefined` (default `"default"`): "compact" for a narrow column, a phone or a notification: the title, the values or summary, where, how many things it touches, the hash, expiry and what happens if nobody answers. A change that can't be undone or that changes production offers only `onOpen` there, never Approve. - `onOpen?: (() => void) | undefined`: Compact only: opens the full request (a page, a sheet). Required to decide a change that can't be undone. - `onApproveEdited?: ((hash: string, input: Record) => void) | undefined`: Lets the person deciding edit the request's `input` before approving (full density only). Called with the edited change's hash and the edited input; an edit that changes nothing approves through `onApprove` as usual. Your server recomputes the hash from the input it receives and refuses the approval if it differs. - `hashOf?: ((input: Record) => string | Promise) | undefined` (default `changeHash`): Works out an edited change's hash. Defaults to changeHash: the sha256 of the input's canonical JSON. Use your server's own. - `className?: string | undefined` `` props: - `decision: Decision`: The question, facts, what continues, the two choices and the state. - `onChoose?: ((choiceId: string) => void) | undefined`: Called with the chosen answer's id. - `locked?: string | undefined`: Why the viewer can't answer, if they can't; shown on both buttons. - `className?: string | undefined` ### blast-radius (Pro) What a plan step can reach in the environment, grouped by kind of thing. Install: `npx candor-ui add blast-radius` `` props: - `step: string`: The plan step's title, shown as the heading. - `scope: BlastRadiusScope`: What the step can reach, or why that couldn't be measured. - `className?: string | undefined` ### checkpoint-list (Pro) Restore points in a run, one per turn, with what each one holds and where the person is now. Install: `npx candor-ui add checkpoint-list` `` props: - `checkpoints: Checkpoint[]`: The checkpoints in the order to show them; newest first is usual. - `currentId?: string | undefined`: The checkpoint the work is at now. It's marked, and has no Restore. - `onRestore?: ((id: string) => void) | undefined`: Called with a checkpoint's id when the person picks Restore. Without it, there are no Restore buttons. - `note?: string | null | undefined`: What checkpoints don't capture, in the app's words. Defaults to shell commands and changes outside the agent; null hides it. - `className?: string | undefined` ### clarifying-questions (Pro) The agent's questions before it plans (the first of two turns). Install: `npx candor-ui add clarifying-questions` `` props: - `questions: ClarifyingQuestion[]`: The agent's questions, asked one at a time in this order. - `onSubmit: (answers: ClarifyingAnswer[]) => void`: Called with every answer once the last question is answered. - `onSkip?: (() => void) | undefined`: Let the agent decide the rest itself. - `submitting?: boolean | undefined` (default `false`): Disables Send and shows "Sending" while the answers go to the agent. - `during?: boolean | undefined` (default `false`): The agent asks while it works, not before it plans. - `className?: string | undefined` ### file-list (Pro) The files the work produced: each with its type, size and where it stands ("Checked", "Not yet checked"), Open for the ones the reader can show, and Download, with a menu when it comes in several formats. Install: `npx candor-ui add file-list` `` props: - `files: Deliverable[]`: The files, in order; a file's `group` puts it under that heading, groups in the order first seen. - `onOpen?: ((id: string) => void) | undefined`: Adds Open to readable files; called with the file's id. - `onDownload?: ((id: string, format?: string) => void) | undefined`: Adds Download; called with the file's id and the chosen format's id (undefined with no formats). - `label?: string | undefined`: The list's accessible name. Defaults to "Files". - `empty?: React.ReactNode | undefined`: Shown when there are no files. Defaults to "No files yet." - `headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined` (default `3`): The level of the group headings, to fit the page's outline. Defaults to 3. - `className?: string | undefined` ### guardrail-notice (Pro) One line saying a guardrail stopped something: what was stopped, and which rule stopped it. Install: `npx candor-ui add guardrail-notice` `` props: - `stopped: string`: What didn't happen, e.g. "Deleting a field from a record". A full stop is added unless it already ends with punctuation. - `rule: string`: Why, e.g. "Deletes in production need a second person's sign-off". A full stop is added unless it already ends with punctuation. - `action?: { label: string; onClick: () => void } | undefined`: The one thing the person can do about it, e.g. "Ask an Admin", as a button. - `className?: string | undefined` ### hold-to-confirm (Pro) A button a person holds down before a risky step runs: the pointer, or Space or Enter, kept down for `holdMs` (1.2 seconds unless the app says otherwise). Install: `npx candor-ui add hold-to-confirm` `` props: - `label: string`: The step, as a verb: "Delete 3 rows", "Send to 240 people". - `reason: React.ReactNode`: What the step does and whether it can be undone, in the app's words. Shown under the button and read with it. - `holdMs?: number | undefined` (default `1200`): How long the hold lasts, in milliseconds. 1200 unless the app says otherwise. - `onConfirm: () => void`: Called once, when the hold has lasted `holdMs`. - `locked?: string | undefined`: Why the viewer can't take this step at all. The button stays visible and says so, and no hold starts. - `variant?: "default" | "destructive" | undefined` (default `"default"`): "destructive" for removal, "default" for a serious change that isn't one. - `className?: string | undefined` ### log-stream (Pro) A run's live log. Install: `npx candor-ui add log-stream` `` props: - `items: LogItem[]`: Log lines and gaps, oldest first. - `stepId?: string | undefined`: Show only lines from this plan step (gaps always show). - `live?: boolean | undefined` (default `false`): Marks the log as live and announces new lines to screen readers. Defaults to false. - `className?: string | undefined` ### metadata-diff (Pro) The change as files: one tab per file, each named by the thing it is (a field, a layout) as well as its path, with a unified diff that highlights the exact words that changed inside a line. Install: `npx candor-ui add metadata-diff` `` props: - `files: FileDiff[]`: The changed files, one tab each. - `className?: string | undefined` ### plan (Pro) An agent's plan. Install: `npx candor-ui add plan` `` props: - `title: string`: What the plan does, in a few words. - `steps: PlanStep[]`: The steps, in order. - `mode: PlanMode`: Proposed (waiting for a decision), accepted (the live run), or sent back for changes. - `onAccept?: ((skipped: string[], autonomy: string | undefined) => void) | undefined`: Accept the proposed plan, with the ids of any steps the person dropped and, with `autonomy`, the id of the option they picked (undefined without `autonomy`). - `autonomy?: PlanAutonomyOption[] | undefined`: What accepting can allow, in order. The person picks one before Accept is available; nothing is picked for them. Leave it out and accepting says nothing about autonomy, as before. - `onRevise?: (() => void) | undefined`: Send the proposed plan back for changes. - `acceptLocked?: string | undefined`: Why the viewer can't accept, if they can't. - `activeStepId?: string | undefined`: The step shown as selected. - `onSelectStep?: ((id: string) => void) | undefined`: Makes each step a button that selects it. - `density?: "default" | "compact" | undefined` (default `"default"`): "compact" for inside a thread: tighter, with a step's summary shown only while it's live. Defaults to "default". - `actions?: React.ReactNode | undefined`: Buttons under the steps, such as Pause and Stop; beside Accept when proposed. - `className?: string | undefined` ### restore-dialog (Pro) Restores a checkpoint's code, conversation or both, says what a restore doesn't undo, and shows what the app checked afterwards, never "Restored" without a check. Install: `npx candor-ui add restore-dialog` `` props: - `checkpoint: Pick`: The checkpoint to restore. What it captured decides which choices are available. - `onRestore: (target: RestoreTarget) => Promise`: Restore what the person chose, then check the result against the checkpoint and report it. A rejection is shown as an error. - `commandsRun?: string[] | undefined`: Shell commands the agent ran after this checkpoint, as text. Left out, the dialog says it isn't recorded; [] says none ran. - `outsideChanges?: string[] | undefined`: Changes made outside the agent since the checkpoint, when the app recorded them ("Ana edited README.md"). - `externalEffects?: string[] | undefined`: Effects that left the workspace since the checkpoint, when the app recorded them ("Deployed to preview"). - `locked?: Partial> | undefined`: Choices the app doesn't allow here, with why ("Only the session owner can rewind the conversation."). - `open?: boolean | undefined`: Whether the dialog is open, when the app controls it. - `onOpenChange?: ((open: boolean) => void) | undefined`: Called when the dialog opens or closes. - `trigger?: React.ReactElement | undefined`: The control that opens the dialog, when the app doesn't control `open`. `` props: - `result: RestoreOutcome`: The app's report: what it checked after restoring, and any error. - `className?: string | undefined` ### result-card (Pro) A finished piece of work, handed over: the answer first, in a few lines, then the receipt (what it cost, how long it took, what checked it) and the files to open or download, then your actions (Accept, Ask for changes). Install: `npx candor-ui add result-card` `` props: - `title: string`: What it is, as the heading: "Result 1", "Pricing review". - `answer: string | MessageBlock[]`: The answer, first: markdown text (read into safe blocks) or blocks. - `status?: { label: string; tone?: "default" | "attention" | "success" | undefined } | undefined`: Where it stands, in words, with a tone: `{ label: "Checked", tone: "success" }`. - `receipt?: ReceiptLine[] | undefined`: What it cost, how long it took, what checked it: your values, as given. - `files?: Deliverable[] | undefined`: The files it produced. - `onOpenFile?: ((id: string) => void) | undefined`: Adds Open to readable files. - `onDownloadFile?: ((id: string, format?: string) => void) | undefined`: Adds Download to files; called with the file's id and format. - `actions?: React.ReactNode | undefined`: Buttons at the foot: Accept, Ask for changes. - `sources?: MessageSource[] | undefined`: Sources the answer cites by marker. - `onOpenEntity?: ((entity: EntityRef) => void) | undefined`: Makes entity chips in the answer open their thing. - `className?: string | undefined` ### result-table (Pro) Query rows as a typed, sortable table. Install: `npx candor-ui add result-table` `` props: - `table: ResultTableData`: The query's columns, rows and total match count. - `title?: string | undefined`: The heading. Defaults to "Results". - `className?: string | undefined` ### review-canvas (Pro) The governed review surface (Candor's ReviewCanvas): the plan on one side; select a step and its log, diff, blast radius and reasoning appear on the other. Install: `npx candor-ui add review-canvas` `` props: - `title: string`: The plan's title. - `steps: PlanStep[]`: The plan's steps; the first running, waiting or failed one is selected to start. - `logs: LogItem[]`: The run's log, filtered to the selected step. - `diffs?: Record | undefined` (default `{}`): File diffs per step id. A step without any says it changes no metadata. - `reach?: Record | undefined` (default `{}`): Blast radius per step id. A step without one says reach isn't measured. - `reasoning?: Record | undefined` (default `{}`): The agent's reasoning per step id. A step without any says none was recorded. - `approval?: ApprovalData | undefined`: The approval request, shown under the evidence. - `onApprove?: ((hash: string) => void) | undefined`: Called on approve with the change hash. - `onReject?: ((hash: string) => void) | undefined`: Called on reject with the change hash. - `live?: boolean | undefined` (default `false`): Shows the log as live while the selected step is running. Defaults to false. - `className?: string | undefined` ### review-ladder (Pro) How much a person reviews before agents act: the ladder from Advise to Full delegation. Install: `npx candor-ui add review-ladder` `` props: - `value: ReviewLevel`: The current review level, R1 (Advise) to R5 (Full delegation). - `onChange?: ((level: ReviewLevel) => void) | undefined`: Makes the rungs choosable; called with the level picked. - `locked?: Partial> | undefined` (default `{}`): Reasons a level can't be chosen. - `className?: string | undefined` ### run-heartbeat (Pro) A run's state that never claims it's alive when nothing has been heard: "No update since 10:42" past a threshold, a host that's offline, or what it needs from the person. Install: `npx candor-ui add run-heartbeat` `` props: - `status: RunStatus`: The run's status as the service last reported it. - `lastHeardAt?: Date | string | undefined`: When the app last heard anything from the run: an event, a log line, a heartbeat. - `hostOffline?: HostOffline | undefined`: Set when the machine or worker running it can't be reached. Shown ahead of everything but a finished run. - `needs?: string | undefined`: What the run needs from the person, in plain words. Set, or with status "waiting", it shows as needing you. - `label?: string | undefined`: Your word for the status ("Making"), used while the run is live or finished. - `staleAfter?: number | undefined` (default `STALE_AFTER`): How long a running run may be silent before it's no longer called running, in milliseconds. Defaults to two minutes. - `onRespond?: (() => void) | undefined`: Called when the person picks Respond on a run that needs them. Without it, there's no button. - `compact?: boolean | undefined` (default `false`): One line, for lists: no hint and no button. - `className?: string | undefined` ### run-recovery (Pro) A run that stopped. Install: `npx candor-ui add run-recovery` `` props: - `title: string`: What the run was doing. - `steps: PlanStep[]`: Every step of the run, in order. - `failedStepId: string`: The step it stopped at. - `reason: string`: What went wrong at that step, in plain words. - `loop?: { times: number } | undefined`: Set when the run was stopped for repeating itself. - `onRetryFromStep?: ((id: string) => void) | undefined`: Retry from the failed step; earlier finished steps are kept. Without it, there's no retry button. - `onSkip?: ((id: string) => void) | undefined`: Skip the failed step and go on with the next one. Without it, there's no skip button. - `skipNote?: string | undefined`: What skipping means for this run, shown beside the actions. Defaults to saying the step's work won't be done. - `onStop?: (() => void) | undefined`: Stop the run where it is. Without it, there's no stop button. - `confirm?: { retry?: string | undefined; skip?: string | undefined } | undefined`: Ask before a retry or skip that changes something: what it will do, in plain words, shown with a Confirm button. Leave one out to act at once. - `className?: string | undefined` ### run-tree (Pro) Who is doing what: the orchestrator and the specialists it handed work to, as a tree. Install: `npx candor-ui add run-tree` `` props: - `root: RunNode`: The orchestrator, with the agents it handed work to as children. - `onSelect?: ((id: string) => void) | undefined`: Makes nodes selectable; called with the node's id. - `activeId?: string | undefined`: The id of the selected node. - `className?: string | undefined` ### ship-review (Pro) The last look before a change reaches production: what ships, each check it must pass (validation, tests, approval), and how to undo it. Install: `npx candor-ui add ship-review` `` props: - `environment: string`: The production environment's name, e.g. "Shop". - `components: { entity: EntityRef; change: "create" | "update" | "delete" }[]`: What ships, and whether each is new, changed or deleted. - `checks: ShipCheck[]`: The checks it must pass before it can ship. - `rollback: Rollback`: How to undo it, or why it can't be undone. - `window?: string | undefined`: When it may ship (review level R4). - `onShip?: (() => void) | undefined`: Ship it. Without it, there's no ship button. - `shipping?: boolean | undefined` (default `false`): Shipping is under way. - `onRequestChanges?: ((note?: string) => void) | undefined`: Send it back instead of shipping, with an optional note on what to change. Without it, there's no button. - `locked?: string | undefined`: Why neither action can be used right now, e.g. the agent is still replying. - `className?: string | undefined` ### steer-composer (Pro) Send a message into a run while it works, and see whether the agent has picked it up yet, never shown as read until the service says so. Install: `npx candor-ui add steer-composer` `` props: - `run: { status: RunStatus; lastHeardAt?: Date | string | undefined; hostOffline?: HostOffline | undefined }`: The run being steered: its status, when it was last heard from, and whether its host is offline. - `messages: SteerMessage[]`: Messages already sent, oldest first, each with where it is. - `onSend: (text: string) => void`: Called with the person's words. Add the message to `messages` (as "sending" or "queued") to show it. - `onRetry?: ((id: string) => void) | undefined`: Called with a failed message's id when the person picks Retry. Without it, there's no Retry. - `onWithdraw?: ((id: string) => void) | undefined`: Called with a queued message's id to take it back before the agent reads it. Without it, there's no Withdraw. - `agentName?: string | undefined`: The agent's name, from your app, used in "Build agent hasn't picked it up yet". - `pickupNote?: string | null | undefined`: When your agent reads new messages, in your words. Defaults to "between steps"; null hides it. - `staleAfter?: number | undefined` (default `STALE_AFTER`): How long a running run may be silent before it's called quiet, in milliseconds. Defaults to two minutes. - `placeholder?: string | undefined` - `className?: string | undefined` ### task-tray (Pro) Work running in the background, as one pill: how many are running and how many need you. Install: `npx candor-ui add task-tray` `` props: - `tasks: BackgroundTask[]`: The background tasks; with none, the tray renders nothing. - `onOpenTask?: ((id: string) => void) | undefined`: Called with a task's id when it's clicked in the list. - `staleAfter?: number | undefined` (default `STALE_AFTER`): How long a running task may be silent before it's no longer called running, in milliseconds. Defaults to two minutes. - `className?: string | undefined` ### test-results (Pro) A test run that leads with what failed. Install: `npx candor-ui add test-results` `` props: - `run: TestRun`: The test run: its status, cases and, once measured, coverage against what's required. - `className?: string | undefined` ### undo-window (Pro) An action just taken ("Deleted 3 rows"), with Undo for as long as the app says it can be undone: `until` (when the server said the window closes) or `seconds` (the window the server granted, counted from when this appears). Install: `npx candor-ui add undo-window` `` props: - `action: string`: What was done, in the app's words, past tense: "Deleted 3 rows", "Sent to 240 people". - `detail?: React.ReactNode | undefined`: More about it: which rows, where they went. - `until?: string | undefined`: When the window closes, as an ISO timestamp from the server. Used over `seconds` when both are given. - `seconds?: number | undefined`: How many seconds the server granted, counted from the render where it first arrives (a value that arrives after mount starts the window then). Not a default: pass what the server said. - `onUndo: () => Promise`: Undoes the action. Pending until it settles; a rejection's message is shown as the reason it couldn't. - `onClose?: (() => void) | undefined`: Called once, when the window closes without an undo. - `cannotUndo?: string | undefined`: Why the action can't be undone, shown when no window is given: "Sent email can't be recalled." - `className?: string | undefined` ## Templates Complete app sections built from the blocks: an agent ops console, an approvals inbox, a support copilot. Each for the Vercel AI SDK and the Claude Agent SDK. ### agent-ops-console (Premium) An app section for running one agent: an overview of today's runs, spend and failures; runs with their log, trace, receipt and retry, skip or stop; a monthly budget the agent stops at; admin-only settings for its tools, model and versioned instructions; and a chat that drives runs. The agent routes enforce the settings and the budget. Install: `npx candor-ui add agent-ops-console` `` props: - `children: React.ReactNode` `` props: - `children: React.ReactNode` `` props: - `chat: OpsChatState`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the page works with either. ### agent-ops-console-claude (Premium) An app section for running one agent: an overview of today's runs, spend and failures; runs with their log, trace, receipt and retry, skip or stop; a monthly budget the agent stops at; admin-only settings for its tools, model and versioned instructions; and a chat that drives runs. The agent routes enforce the settings and the budget. Install: `npx candor-ui add agent-ops-console-claude` `` props: - `children: React.ReactNode` `` props: - `children: React.ReactNode` `` props: - `chat: OpsChatState`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the page works with either. ### approvals-inbox (Premium) One place where people decide what agents asked to do: an inbox of requests from several agents, each with its blast radius, diff and rollback, a hash-bound decision, two different approvers for production, a history of every decision, and an agent that can only apply what's approved. Install: `npx candor-ui add approvals-inbox` `` props: - `chat: InboxChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the page works with either. `` props: - `params: Promise<{ id: string }>`: The route’s params from the framework: the request id, e.g. "CR-002". `` props: - `active: Place`: The place in the sidebar this page belongs to, marked as the current page. - `children: React.ReactNode` ### approvals-inbox-claude (Premium) One place where people decide what agents asked to do: an inbox of requests from several agents, each with its blast radius, diff and rollback, a hash-bound decision, two different approvers for production, a history of every decision, and an agent that can only apply what's approved. Install: `npx candor-ui add approvals-inbox-claude` `` props: - `chat: InboxChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the page works with either. `` props: - `params: Promise<{ id: string }>`: The route’s params from the framework: the request id, e.g. "CR-002". `` props: - `active: Place`: The place in the sidebar this page belongs to, marked as the current page. - `children: React.ReactNode` ### project-workspace (Premium) A workspace where each project is a conversation with an agent team: a rail of projects grouped by what needs you, the thread, and a panel with the project's overview, plan, files and history. The agent plans, works and hands over files, but it stops for the person at the spending limit and on any decision it asks for, and the receipt shows only what was recorded. Install: `npx candor-ui add project-workspace` `` props: - `projectId: string | null`: The open project, e.g. "P-1"; without one, the first project that needs you (or the newest) opens. - `chat: WorkspaceChat` - `defaultWidth?: number | undefined`: The width to lay out for before the frame is measured (the server, tests); AppLayout's `defaultWidth`. ### project-workspace-claude (Premium) A workspace where each project is a conversation with an agent team: a rail of projects grouped by what needs you, the thread, and a panel with the project's overview, plan, files and history. The agent plans, works and hands over files, but it stops for the person at the spending limit and on any decision it asks for, and the receipt shows only what was recorded. Install: `npx candor-ui add project-workspace-claude` `` props: - `projectId: string | null`: The open project, e.g. "P-1"; without one, the first project that needs you (or the newest) opens. - `chat: WorkspaceChat` - `defaultWidth?: number | undefined`: The width to lay out for before the frame is measured (the server, tests); AppLayout's `defaultWidth`. ### support-copilot (Premium) A support desk where an agent drafts answers from the help docs, with citations, and a person approves, edits or rejects every draft before the customer sees it. The agent hands threads to a person when it should, and reviewers' decisions feed a quality view. Install: `npx candor-ui add support-copilot` `` props: - `active?: Place | undefined`: The place in the sidebar this page belongs to, marked as the current page. None on a thread. - `title: string`: The page's title, in its header. - `description?: React.ReactNode | undefined`: A line under the title. - `breadcrumb?: Crumb[] | undefined`: Where the page sits, e.g. Queue › T-1042. - `actions?: React.ReactNode | undefined`: Buttons at the right of the header. - `tabs?: PageTab[] | undefined`: Tabs under the header, each with an optional count. - `activeTab?: string | undefined`: The id of the tab that's showing. - `onTabChange?: ((id: string) => void) | undefined`: Called with a tab's id when it's chosen. - `panel?: React.ReactNode | undefined`: A side panel beside the page, e.g. the copilot's chat. - `panelOpen?: boolean | undefined`: Whether the side panel is open. - `onPanelOpenChange?: ((open: boolean) => void) | undefined`: Called when the side panel opens or closes. - `panelLabel?: string | undefined`: The side panel's name, for screen readers and its resize handle. - `children: React.ReactNode` `` props: - `id: string`: The thread to show, e.g. "T-1042". - `chat: CopilotChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the screen works with either. `` props: - `params: Promise<{ id: string }>`: The route’s params from the framework: the thread id, e.g. "T-1042". `` props: - `line: Line`: One line of the thread as sent: from the customer, the copilot (with who checked it), a person on the team, or the system. - `customerLabel?: string | undefined`: What to call the customer instead of their name, e.g. "You" on the customer’s own page. `` props: - `card: HandoffCardData`: The handoff as the copilot sent it; the thread’s live handoff replaces it once the same handoff moves on. - `onAccept?: (() => void) | undefined`: Lets a person take the thread while the handoff is pending; called when they do. ### support-copilot-claude (Premium) A support desk where an agent drafts answers from the help docs, with citations, and a person approves, edits or rejects every draft before the customer sees it. The agent hands threads to a person when it should, and reviewers' decisions feed a quality view. Install: `npx candor-ui add support-copilot-claude` `` props: - `active?: Place | undefined`: The place in the sidebar this page belongs to, marked as the current page. None on a thread. - `title: string`: The page's title, in its header. - `description?: React.ReactNode | undefined`: A line under the title. - `breadcrumb?: Crumb[] | undefined`: Where the page sits, e.g. Queue › T-1042. - `actions?: React.ReactNode | undefined`: Buttons at the right of the header. - `tabs?: PageTab[] | undefined`: Tabs under the header, each with an optional count. - `activeTab?: string | undefined`: The id of the tab that's showing. - `onTabChange?: ((id: string) => void) | undefined`: Called with a tab's id when it's chosen. - `panel?: React.ReactNode | undefined`: A side panel beside the page, e.g. the copilot's chat. - `panelOpen?: boolean | undefined`: Whether the side panel is open. - `onPanelOpenChange?: ((open: boolean) => void) | undefined`: Called when the side panel opens or closes. - `panelLabel?: string | undefined`: The side panel's name, for screen readers and its resize handle. - `children: React.ReactNode` `` props: - `id: string`: The thread to show, e.g. "T-1042". - `chat: CopilotChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the screen works with either. `` props: - `params: Promise<{ id: string }>`: The route’s params from the framework: the thread id, e.g. "T-1042". `` props: - `line: Line`: One line of the thread as sent: from the customer, the copilot (with who checked it), a person on the team, or the system. - `customerLabel?: string | undefined`: What to call the customer instead of their name, e.g. "You" on the customer’s own page. `` props: - `card: HandoffCardData`: The handoff as the copilot sent it; the thread’s live handoff replaces it once the same handoff moves on. - `onAccept?: (() => void) | undefined`: Lets a person take the thread while the handoff is pending; called when they do. ## Full-stack blocks Working features to start from: a page, its agent routes and a store, each for the Vercel AI SDK and the Claude Agent SDK. ### agent-admin (Premium) An admin page for one agent: which tools it may use and which ask first, its model and effort, versioned instructions, and a monthly spend limit. The agent routes enforce every setting. Install: `npx candor-ui add agent-admin` `` props: - `chat: ReleaseChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `settingsHref: string`: Where the settings page lives, linked from the chat so an admin can change what the agent may do. ### agent-admin-claude (Premium) An admin page for one agent: which tools it may use and which ask first, its model and effort, versioned instructions, and a monthly spend limit. The agent routes enforce every setting. Install: `npx candor-ui add agent-admin-claude` `` props: - `chat: ReleaseChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `settingsHref: string`: Where the settings page lives, linked from the chat so an admin can change what the agent may do. ### approval-gated-change (Premium) An agent proposes a settings change and shows what it touches; a different person approves that exact change in a queue before it applies. Install: `npx candor-ui add approval-gated-change` `` props: - `chat: ChangeChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `queueHref: string`: Where the approval queue lives, linked from the chat so people can decide on what the agent asked for. ### approval-gated-change-claude (Premium) An agent proposes a settings change and shows what it touches; a different person approves that exact change in a queue before it applies. Install: `npx candor-ui add approval-gated-change-claude` `` props: - `chat: ChangeChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `queueHref: string`: Where the approval queue lives, linked from the chat so people can decide on what the agent asked for. ### approve-from-anywhere (Premium) A run pauses at a write and emails the approver an id, not a link; they open a compact approval page, decide against the change's hash (editing it first if they need to), and the run resumes, even after a server restart. Install: `npx candor-ui add approve-from-anywhere` `` props: - `viewer?: string | undefined` - `onChange?: (() => void) | undefined` `` props: - `chat: RolloutChat` ### approve-from-anywhere-claude (Premium) A run pauses at a write and emails the approver an id, not a link; they open a compact approval page, decide against the change's hash (editing it first if they need to), and the run resumes, even after a server restart. Install: `npx candor-ui add approve-from-anywhere-claude` `` props: - `viewer?: string | undefined` - `onChange?: (() => void) | undefined` `` props: - `chat: RolloutChat` ### audit-data-controls (Premium) An audit log of everything the agent and people did, with export, retention and delete. The agent can search the log and prepare an export; deleting data or changing retention needs the person's go-ahead and their typed confirmation. Install: `npx candor-ui add audit-data-controls` `` props: - `chat: DataChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `dataHref: string`: Where the data controls page lives, linked from the chat. ### audit-data-controls-claude (Premium) An audit log of everything the agent and people did, with export, retention and delete. The agent can search the log and prepare an export; deleting data or changing retention needs the person's go-ahead and their typed confirmation. Install: `npx candor-ui add audit-data-controls-claude` `` props: - `chat: DataChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `dataHref: string`: Where the data controls page lives, linked from the chat. ### cost-guard (Premium) Before a run the agent estimates its cost from recorded runs, or says it can't; the person approves a budget; spend is recorded from the usage the SDK reports, and the run stops on the server when it reaches the budget and says why. Install: `npx candor-ui add cost-guard` `` props: - `chat: CostChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The spend API route the page reads usage and the budget from, e.g. "/cost-guard/api/spend". ### cost-guard-claude (Premium) Before a run the agent estimates its cost from recorded runs, or says it can't; the person approves a budget; spend is recorded from the usage the SDK reports, and the run stops on the server when it reaches the budget and says why. Install: `npx candor-ui add cost-guard-claude` `` props: - `chat: CostChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The spend API route the page reads usage and the budget from, e.g. "/cost-guard/api/spend". ### eval-dashboard (Premium) Each version of an agent runs a fixed suite of cases checked in code; an agent reads and compares the runs and explains regressions from recorded results, and a version goes to production only after approval, refused when its latest run fails a case production passes. Install: `npx candor-ui add eval-dashboard` `` props: - `before: RunLabel` - `after: RunLabel` - `note: string` - `summary: ComparisonRow[]` - `cases: CaseRow[]` - `caseHref?: ((caseId: string) => string) | undefined` - `only?: CaseChange[] | undefined` `` props: - `detail: CaseDetailData` `` props: - `chat: EvalDashChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The runs API route the dashboard reads, e.g. "/eval-dashboard/api/runs". - `compareHref: string`: The page that compares two runs case by case, e.g. "/eval-dashboard/compare". ### eval-dashboard-claude (Premium) Each version of an agent runs a fixed suite of cases checked in code; an agent reads and compares the runs and explains regressions from recorded results, and a version goes to production only after approval, refused when its latest run fails a case production passes. Install: `npx candor-ui add eval-dashboard-claude` `` props: - `before: RunLabel` - `after: RunLabel` - `note: string` - `summary: ComparisonRow[]` - `cases: CaseRow[]` - `caseHref?: ((caseId: string) => string) | undefined` - `only?: CaseChange[] | undefined` `` props: - `detail: CaseDetailData` `` props: - `chat: EvalDashChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The runs API route the dashboard reads, e.g. "/eval-dashboard/api/runs". - `compareHref: string`: The page that compares two runs case by case, e.g. "/eval-dashboard/compare". ### eval-review-loop (Premium) People grade a support agent's replies, recorded checks score them, and an agent summarises the failures and proposes an instructions change that applies, as a new version, only after approval. Install: `npx candor-ui add eval-review-loop` `` props: - `chat: EvalChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The evals API route the scores are read from, e.g. "/eval-review-loop/api/evals". - `reviewHref: string`: Where people grade replies, linked when some aren’t graded yet. ### eval-review-loop-claude (Premium) People grade a support agent's replies, recorded checks score them, and an agent summarises the failures and proposes an instructions change that applies, as a new version, only after approval. Install: `npx candor-ui add eval-review-loop-claude` `` props: - `chat: EvalChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The evals API route the scores are read from, e.g. "/eval-review-loop/api/evals". - `reviewHref: string`: Where people grade replies, linked when some aren’t graded yet. ### human-handoff (Premium) A support agent answers a customer and hands the thread to a person when it should; the agent stops replying, and a person claims it in an inbox, answers, and can hand it back. Install: `npx candor-ui add human-handoff` `` props: - `card: HandoffCardData`: The handoff as the agent sent it; the live thread’s handoff replaces it once the same handoff moves on. - `onAccept?: (() => void) | undefined`: Lets a person take the handoff while it’s pending; called when they do. `` props: - `chat: SupportChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `threadId: string`: The customer thread this chat belongs to. - `threadApi: string`: The thread API route, polled for who owns the thread and what people wrote, e.g. "/human-handoff/api/thread". - `inboxHref: string`: Where the team’s handoff inbox lives, linked for the person who picks it up. ### human-handoff-claude (Premium) A support agent answers a customer and hands the thread to a person when it should; the agent stops replying, and a person claims it in an inbox, answers, and can hand it back. Install: `npx candor-ui add human-handoff-claude` `` props: - `card: HandoffCardData`: The handoff as the agent sent it; the live thread’s handoff replaces it once the same handoff moves on. - `onAccept?: (() => void) | undefined`: Lets a person take the handoff while it’s pending; called when they do. `` props: - `chat: SupportChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `threadId: string`: The customer thread this chat belongs to. - `threadApi: string`: The thread API route, polled for who owns the thread and what people wrote, e.g. "/human-handoff/api/thread". - `inboxHref: string`: Where the team’s handoff inbox lives, linked for the person who picks it up. ### knowledge-base (Premium) An agent answers only from published help articles, citing each article and version, says it doesn't know when nothing matches and records the question as a gap, and drafts an article change that publishes, as a new version, only after approval; people edit articles and see the gaps on their own page. Install: `npx candor-ui add knowledge-base` `` props: - `a: ArticleSummary` `` props: - `chat: KbChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The data route the articles and gaps are read from, e.g. "/knowledge-base/api/kb". - `articlesHref: string`: Where people read and edit the articles. ### knowledge-base-claude (Premium) An agent answers only from published help articles, citing each article and version, says it doesn't know when nothing matches and records the question as a gap, and drafts an article change that publishes, as a new version, only after approval; people edit articles and see the gaps on their own page. Install: `npx candor-ui add knowledge-base-claude` `` props: - `a: ArticleSummary` `` props: - `chat: KbChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `api: string`: The data route the articles and gaps are read from, e.g. "/knowledge-base/api/kb". - `articlesHref: string`: Where people read and edit the articles. ### plan-build-review (Premium) An agent asks what it needs to know, proposes a plan the person accepts or sends back, carries out the steps with a live log, asking before any step that changes something, and ends with a ship review the person accepts or sends back. Install: `npx candor-ui add plan-build-review` `` props: - `chat: BuildChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `workApi: string`: The work API route, polled for the plan, the build and the review, e.g. "/plan-build-review/api/work". ### plan-build-review-claude (Premium) An agent asks what it needs to know, proposes a plan the person accepts or sends back, carries out the steps with a live log, asking before any step that changes something, and ends with a ship review the person accepts or sends back. Install: `npx candor-ui add plan-build-review-claude` `` props: - `chat: BuildChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `workApi: string`: The work API route, polled for the plan, the build and the review, e.g. "/plan-build-review/api/work". ### run-console (Premium) An agent starts and steers runs from the chat; a console lists every run with its log, trace and receipt, and when a step fails the person chooses retry, skip or stop, allowing any retry that changes something. Install: `npx candor-ui add run-console` `` props: - `chat: RunChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `runsApi: string`: The runs API route, polled so a stopped-run card knows where its run is now, e.g. "/run-console/api/runs". - `consoleHref: string`: Where the run console lives, linked from the chat. ### run-console-claude (Premium) An agent starts and steers runs from the chat; a console lists every run with its log, trace and receipt, and when a step fails the person chooses retry, skip or stop, allowing any retry that changes something. Install: `npx candor-ui add run-console-claude` `` props: - `chat: RunChat`: The chat state from useCandorChat (AI SDK) or useClaudeAgent (Claude Agent SDK); the block works with either. - `runsApi: string`: The runs API route, polled so a stopped-run card knows where its run is now, e.g. "/run-console/api/runs". - `consoleHref: string`: Where the run console lives, linked from the chat. ## Adapters Map an agent SDK's messages onto Candor's data: the Vercel AI SDK, the Claude Agent SDK and AG-UI. ### ag-ui (free) Turns AG-UI events into Candor messages, waiting approvals and usage, with AG-UI 1.0's shared state and activities. Install: `npx candor-ui add ag-ui` ### ai-sdk (free) Vercel AI SDK (v7) UI messages to Candor messages: text, reasoning, tool calls, sources and data cards. Install: `npx candor-ui add ai-sdk` ### claude-agent-sdk (free) Turns Claude Agent SDK events into Candor messages, waiting approvals (and the agent's questions), usage and sources, and a person's answer back into the SDK's result. Install: `npx candor-ui add claude-agent-sdk` ### claude-agent-server (free) The server half of the Claude Agent SDK adapter: stream a run to useClaudeAgent, keep its permission requests in a store your own route can answer, and let a browser re-attach to a run after a reload. Install: `npx candor-ui add claude-agent-server` ### use-ag-ui (free) Wires an AG-UI agent to Candor: messages for /, props for , and the interrupts waiting on a person. Install: `npx candor-ui add use-ag-ui` ### use-candor-chat (free) Wires a `useChat()` result to Candor: messages for /, props for , and the tool calls waiting on a person. Install: `npx candor-ui add use-candor-chat` ### use-claude-agent (free) Wires a Claude Agent SDK server route to Candor: messages for /, props for , and the tool calls waiting on a person, re-attaching to a run after a reload. Install: `npx candor-ui add use-claude-agent` ## Agents Who the agents are: rosters, profiles, handoffs. ### agent-roster (Pro) Every agent on the team: role, model, whether it's on, and two weeks of runs. Install: `npx candor-ui add agent-roster` `` props: - `agents: AgentConfig[]`: Every agent on the team, with its role, model, state and recent runs. - `models: ModelOption[]`: The models agents can use, for naming each agent's model. - `activeId?: string | undefined`: The agent shown as selected. - `onSelect?: ((id: string) => void) | undefined`: Called with the agent id when a card is clicked. - `className?: string | undefined` ### instructions-editor (Pro) An agent's standing instructions, with variables like {{workspace.name}} that are filled in per run. Install: `npx candor-ui add instructions-editor` `` props: - `value: string`: The instructions text, with {{variables}} as written. - `onChange: (value: string) => void`: Called with the new text on each edit or variable insert. - `variables: InstructionVariable[]`: The variables a run fills in; any other {{name}} is flagged as unknown. - `maxLength?: number | undefined` (default `8000`): Most characters allowed, shown as a count. Defaults to 8000. - `className?: string | undefined` ### mcp-connect (Pro) Consent to connect an MCP server: where it runs and who runs it, what it says it can do (its tools, by name and description), the permissions it asks for, and how to disconnect later. Install: `npx candor-ui add mcp-connect` `` props: - `server: McpServerInfo`: The server: its name, where it runs and who runs it, as your app knows them. - `tools?: McpServerTool[] | undefined`: The tools it lists. Leave out when it hasn't listed them; `[]` when it lists none. - `scopes?: McpScope[] | undefined`: The permissions it asks for. Leave out when it hasn't said; `[]` when it asks for none. - `disconnect: string`: How to disconnect later, e.g. "Settings › Connections › Linear › Disconnect. Its access stops at once." - `acknowledgement?: string | undefined`: A sentence the person ticks themselves before connecting. Optional. - `title?: string | undefined`: The heading. Defaults to "Connect {name}?". - `onConnect: (scopes: string[]) => void`: Called with the ids of the permissions the person ticked, in the order given. - `onCancel: () => void`: Called when the person cancels. - `busy?: boolean | undefined` (default `false`): Disables Connect and says "Connecting" while the connection is made. - `error?: string | undefined`: Why the last attempt failed, said above the buttons. - `toolLimit?: number | undefined` (default `6`): How many tools to show before "Show all". - `className?: string | undefined` ### model-settings (Pro) Which model an agent uses and how hard it thinks. Install: `npx candor-ui add model-settings` `` props: - `value: ModelSettingsValue`: The settings as they are now. - `onChange: (value: ModelSettingsValue) => void`: Called with the whole new value on every change. - `models: ModelOption[]`: Every model the app offers, from any vendor. - `locked?: string | undefined`: Why the viewer can't change these settings, e.g. "Only admins can change the model." Shown, and every control is locked. - `className?: string | undefined` ### permission-mode (Pro) The agent's permission mode, with what each mode lets it do written out, and a way to change it. Install: `npx candor-ui add permission-mode` `` props: - `mode?: string | undefined`: The mode the agent last reported. Undefined while it hasn't said. - `modes?: PermissionModeOption[] | undefined` (default `builtIn.map((id) => ({ id }))`): The modes to offer, in order. Defaults to the six SDK modes. - `onChange?: ((mode: string) => void) | undefined`: Asks for a change. Show the new mode once the agent reports it (`mode`). - `pending?: boolean | undefined` (default `false`): A change is on its way. - `error?: string | undefined`: Why the last change failed, if it did. Pass "" for no reason. - `locked?: string | undefined`: Why the mode can't be changed at all here: a policy, a role. - `variant?: "list" | "compact" | undefined` (default `"list"`): "list" shows every mode with its consequences; "compact" is a button that opens the list, for a toolbar. - `className?: string | undefined` ### tool-permissions (Pro) What each tool an agent may call is allowed to do: always, ask first, or never. Install: `npx candor-ui add tool-permissions` `` props: - `tools: ToolSetting[]`: Every tool the agent may call, with its effect, current permission and any options policy rules out. - `onChange: (id: string, permission: ToolPermission) => void`: Called with the tool id and the chosen permission. - `className?: string | undefined` ## App shell The app around the agent: layout, sidebar, command menu, sessions, notices. ### account-state (Pro) A whole-page stop for a signed-in person the app can't show anything to yet: no account, removed from one, email not verified, an invite to accept. Install: `npx candor-ui add account-state` `` props: - `brand: React.ReactNode`: The product's logo or name, shown above the card. - `title: string`: What's wrong, as the heading, e.g. "You don't have an account yet". - `detail?: React.ReactNode | undefined`: More on the situation and what to do, under the title. - `actions: { label: string; onClick: () => void; locked?: string | undefined }[]`: The next steps, the first one primary; `locked` keeps one listed but unusable, with the reason on it. - `email?: string | undefined`: Who is signed in; with `onSignOut`, printed under the card with a Sign out link. - `onSignOut?: (() => void) | undefined`: Called when the person chooses Sign out. - `steps?: SetupStep[] | undefined`: What's left before the app can work, as a checklist in the card (a setup gate). - `children?: React.ReactNode | undefined`: Your own controls in the card, under the detail and above the steps, such as a choice for the current step. - `className?: string | undefined` ### app-layout (Pro) The app frame: sidebar, main column, and an optional side panel the person can resize by dragging (or with the arrow keys on the divider). Install: `npx candor-ui add app-layout` `` props: - `sidebar: React.ReactNode`: The left rail (an AppSidebar); a sheet behind a menu button when narrow. - `top?: React.ReactNode | undefined`: A strip above the main column (an OrgBand). - `children: React.ReactNode` - `panel?: React.ReactNode | undefined`: The side panel's content, shown right of the main column when `panelOpen`. - `panelOpen?: boolean | undefined` (default `false`): Whether the side panel is showing. Defaults to false. - `onPanelOpenChange?: ((open: boolean) => void) | undefined`: Called when the panel opens or closes, including when a narrow frame closes it. - `panelLabel?: string | undefined`: The panel's accessible name, also used for the resize handle. Defaults to "Details". - `minPanel?: number | undefined` (default `320`): The narrowest the panel can be dragged, in pixels. Defaults to 320. - `maxPanel?: number | undefined` (default `720`): The widest the panel can be dragged, in pixels. Defaults to 720. - `defaultPanel?: number | undefined` (default `400`): The panel's starting width, in pixels, and its fixed width when it isn't resizable. Defaults to 400. - `resizable?: boolean | undefined` (default `true`): Whether the person can drag (or arrow-key) the panel's width between `minPanel` and `maxPanel`. Defaults to true. - `sidebarAt?: number | undefined` (default `768`): Frame width in pixels below which the sidebar becomes a sheet. Defaults to 768. - `panelAt?: number | undefined` (default `1100`): Frame width in pixels below which the panel becomes a sheet from the right. Defaults to 1100. - `defaultWidth?: number | undefined` (default `0`): The frame width to lay out for until it can be measured: on the server, and in test environments like jsdom that measure everything as 0. Defaults to 0, the narrow layout (sidebar and panel as sheets). - `navOpen?: boolean | undefined`: Whether the sidebar sheet is open, when narrow. Give it to control the sheet yourself; leave it out and AppLayout keeps its own state. - `onNavOpenChange?: ((open: boolean) => void) | undefined`: Called when the sidebar sheet opens or closes: from the menu button, Escape, a click outside, or the frame growing wide enough for the rail. - `navButton?: boolean | undefined` (default `true`): Shows the built-in menu button that opens the sidebar sheet when narrow. Defaults to true; with false, open the sheet from your own button through `navOpen`. - `className?: string | undefined` ### app-sidebar (Pro) The left rail: the brand, a new-thread button, the main places (threads, inbox, approvals…), the thread list, and the signed-in person at the foot. Install: `npx candor-ui add app-sidebar` `` props: - `brand: React.ReactNode`: The product's logo or name, at the top. - `nav: NavItem[]`: The main places, each with an icon and an optional count. - `activeNav?: string | undefined`: The id of the current place, marked as the current page. - `onNavigate?: ((id: string) => void) | undefined`: Called with a place's id when it's chosen. For a place with an `href`, a plain click calls this instead of following the link (for an app's own router); other clicks open the link as usual. - `onNewThread?: (() => void) | undefined`: Shows a new-thread button by the brand; called when it's pressed. - `user: { name: string; email: string; role?: string | undefined }`: The signed-in person, at the foot; the role shows in place of the email when given. - `usage?: { label: string; used: number } | undefined`: e.g. "62% of this month’s agent hours". - `onSignOut?: (() => void) | undefined`: Adds Sign out to the person menu; called when it's chosen. - `onProfile?: (() => void) | undefined`: Adds Profile to the person menu; called when it's chosen. - `onShortcuts?: (() => void) | undefined`: Adds Keyboard shortcuts to the person menu; called when it's chosen. - `search?: React.ReactNode | undefined`: Above the places; usually a CommandTrigger. - `children?: React.ReactNode | undefined`: Usually a SessionList. - `help?: { href?: string | undefined; onOpen?: (() => void) | undefined; label?: string | undefined } | undefined`: Where people get help, in the same place on every page (WCAG 3.2.6): a link (`href`) or your own handler (`onOpen`), at the foot above the person menu. `label` defaults to "Help". - `className?: string | undefined` ### artifact-panel (Pro) A document or file to read beside the work, for a SidePanel tab or a full-width view. Install: `npx candor-ui add artifact-panel` `` props: - `artifact: Artifact`: What to show: a document (`text` or `blocks`) or a file. - `onDownload?: ((id: string, format?: string) => void) | undefined`: Called with the artifact's id and the chosen format's id (undefined with no formats). - `fullWidth?: boolean | undefined` (default `false`): Whether it's showing full width; sets a reading width and the toggle's words. Defaults to false. - `onFullWidthChange?: ((fullWidth: boolean) => void) | undefined`: Adds the Open full width / Back to the panel button; called with the new state. - `sources?: MessageSource[] | undefined`: Sources the document cites by marker. - `onOpenEntity?: ((entity: EntityRef) => void) | undefined`: Makes entity chips in the document open their thing. - `headingLevel?: 1 | 2 | 3 | 4 | undefined` (default `2`): The level of the title's heading, to fit the page's outline. Defaults to 2. - `className?: string | undefined` ### command-palette (Pro) Search or jump (⌘K): pages, threads, places and actions from one box, with the service's own results alongside. Install: `npx candor-ui add command-palette` `` props: - `open: boolean`: Whether the palette is showing. - `onOpenChange: (open: boolean) => void`: Called when the palette opens or closes, including after an item is chosen. - `groups: PaletteGroup[]`: The items, under their headings; local groups filter as the person types. - `onQueryChange?: ((query: string) => void) | undefined`: Called as the query changes, to fetch remote groups. - `searching?: boolean | undefined` (default `false`): Remote results are on the way; shows a spinner and "Searching…". Defaults to false. - `searchError?: string | undefined`: Why the remote search failed, shown in place of "No results". - `placeholder?: string | undefined`: Shown in the empty search box. Defaults to "Search or jump to…". - `filter?: ((value: string, search: string, keywords?: string[]) => number) | undefined`: How local items match the query, passed to cmdk: `(value, search, keywords) => score`, 0 hiding the item. `keywords` holds the item's label, detail and keywords; `value` holds ids, so match on `keywords`. `matchEveryWord` is a strict "every word, any order" matcher. Defaults to cmdk's fuzzy match. - `onCloseAutoFocus?: ((event: Event) => void) | undefined`: Called as the palette closes, just before focus returns to the element that had it when the palette opened. Call `event.preventDefault()` to put focus somewhere else yourself. `` props: - `onClick: () => void`: Called when the button is pressed, usually to open the palette. - `label?: string | undefined`: The button's text. Defaults to "Search or jump". - `combo?: string | undefined` (default `"mod+k"`): The shortcut printed on the button, e.g. "mod+k" (the default). Printed, not bound. - `className?: string | undefined` ### environment-band (Pro) A slim strip naming the account and the environment in scope, in the environment's own colour. Install: `npx candor-ui add environment-band` `` props: - `account: string`: The account's name, shown before the environment on wider screens. - `environment: Environment`: The environment in scope; its hue colours the strip, and production turns it to a warning. - `environments?: Environment[] | undefined`: The environments to switch between; with `onSelect`, the name becomes a menu. - `onSelect?: ((environment: Environment) => void) | undefined`: Called with the environment chosen from the menu. - `onReconnect?: (() => void) | undefined`: Shows Reconnect when the connection is expired or missing; called when it's pressed. - `className?: string | undefined` `` props: - `environment: Pick`: The environment whose hue colours the dot; without a hue, the first chart colour. - `className?: string | undefined` ### inbox (Pro) Every agent thread that has something for you, by what it needs: approvals and questions waiting on you first, then failures, then work that finished. Install: `npx candor-ui add inbox` `` props: - `items: InboxItem[]`: The threads that have something for you; sorted by whether they need you, then kind, then newest. - `environments?: Environment[] | undefined` (default `[]`): The environments items belong to; with more than one, filter chips appear. - `onOpen?: ((id: string) => void) | undefined`: Called with an item's id when it's opened. - `className?: string | undefined` ### notification-center (Pro) Everything that happened while you were away, behind a bell. Install: `npx candor-ui add notification-center` `` props: - `notices: Notice[]`: The notices, unread first and then newest; only unread ones count on the bell. - `onOpen?: ((id: string) => void) | undefined`: Called with a notice's id when it's opened; the app marks it read. A notice with `action.href` also follows its link. - `onMarkAllRead?: (() => void) | undefined`: Shows "Mark all read" while there are unread notices; called when it's pressed. - `className?: string | undefined` ### page-header (Pro) The top of every page that isn't a thread: where you are (breadcrumb), what the page is, what you can do here (actions), and its views (tabs). Install: `npx candor-ui add page-header` `` props: - `title: string`: What the page is, as its heading. - `description?: React.ReactNode | undefined`: A line under the title saying what the page is for. - `breadcrumb?: Crumb[] | undefined`: Where the page sits, from the top; a crumb with onClick is a link back. - `actions?: React.ReactNode | undefined`: Buttons for what you can do here, right of the title. - `tabs?: PageTab[] | undefined`: Views of the page, shown under the title; a count shows only when given. - `activeTab?: string | undefined`: The id of the current view, marked with aria-current. - `onTabChange?: ((id: string) => void) | undefined`: Called with a view's id when its tab is chosen. - `className?: string | undefined` ### page-state (Pro) What a page shows instead of its content: nothing here yet (empty), nothing matches the filters (no-match), something broke (error), or it can't be shown to you (unavailable). Install: `npx candor-ui add page-state` `` props: - `kind: PageStateKind`: empty, no-match, error or unavailable; sets the icon, and an error is announced. - `title: string`: What's going on, in the product's words. - `detail?: React.ReactNode | undefined`: More on why, or what to do, under the title. - `action?: { label: string; onClick: () => void } | undefined`: The one thing to do next. - `secondary?: { label: string; onClick: () => void } | undefined`: A quieter second option, e.g. clear filters. - `requestId?: string | undefined`: For errors: the id support needs. - `Icon?: LucideIcon | undefined`: Replaces the kind's icon. - `className?: string | undefined` `` props: - `variant?: "list" | "detail" | undefined` (default `"list"`): The shape to sketch: rows of a list (the default) or one item's detail. - `label?: string | undefined`: What's loading, announced to screen readers. Defaults to "Loading". - `className?: string | undefined` ### service-notice (Pro) A notice about the service itself, above the composer: a usage limit, a model that's down, a trial running out. Install: `npx candor-ui add service-notice` `` props: - `kind: Kind`: limit (a usage limit), unavailable (the service or model is down) or trial (a trial running out); sets the icon and tone. - `title: string`: What's happening, e.g. "You've reached this month's agent hours". - `detail?: string | undefined`: What you can do meanwhile, under the title. - `until?: string | undefined`: When the limit resets, the retry happens, or the trial ends. - `action?: { label: string; onClick: () => void } | undefined`: One thing to do about it, e.g. upgrade or switch model. - `onDismiss?: (() => void) | undefined`: Shows a dismiss button; called when it's pressed. - `className?: string | undefined` ### session-expired (Pro) The sign-in ran out while the app was open. Install: `npx candor-ui add session-expired` `` props: - `open: boolean`: Whether the dialog is showing. It can't be dismissed; only signing in or out closes it. - `email: string`: Who was signed in, so a different person doesn't carry on by mistake. - `kept?: string | undefined`: What the app kept, e.g. "Your unsent message is kept." Omit if nothing is. - `signingIn?: boolean | undefined` (default `false`): A sign-in is under way; the button waits and can't be pressed again. Defaults to false. - `failed?: string | undefined`: Why the last sign-in attempt failed. - `onSignIn: () => void`: Called when the person chooses to sign in again (or try again after a failure). - `onSignOut?: (() => void) | undefined`: Shows "Not you? Sign out"; called when it's pressed. ### session-list (Pro) Threads, newest first, grouped by day, with pinned threads on top. Install: `npx candor-ui add session-list` `` props: - `sessions: Session[]`: The threads; pinned ones first, the rest grouped by day, newest first. - `activeId?: string | undefined`: The id of the open thread, marked as the current page. - `groupBy?: ((session: Session) => string) | undefined`: Your own groups instead of pinned and days: returns a session's group heading. Pinned sessions aren't lifted out; return a "Pinned" group yourself if you want one. Newest first within each group. - `groupOrder?: string[] | undefined`: The order of `groupBy`'s headings; headings not listed follow, in the order first seen. - `showStatus?: boolean | undefined` (default `false`): Prints each session's status (or its `statusLabel`) in words on a second line, with the dot. Defaults to false. - `staleAfter?: number | undefined` (default `STALE_AFTER`): How long a running session may be silent before it's no longer shown as running, in milliseconds. Defaults to two minutes. - `virtualize?: boolean | undefined` (default `false`): Render only the rows in or near view, for lists of hundreds of sessions. Defaults to false. - `onOpen?: ((id: string) => void) | undefined`: Called with a thread's id when it's chosen. For a session with an `href`, a plain click calls this instead of following the link (for an app's own router); other clicks (new tab, new window) open the link as usual. - `onRename?: ((id: string, title: string) => void) | undefined`: Allows renaming in place; called with the id and new title when the edit is committed. - `onPin?: ((id: string, pinned: boolean) => void) | undefined`: Adds Pin or Unpin to a thread's menu; called with the id and whether it should now be pinned. - `onDelete?: ((id: string) => void) | undefined`: Adds Delete to a thread's menu; called with the id when it's chosen, without a confirmation. - `className?: string | undefined` ### settings-layout (Pro) Settings: grouped sections down the side and the open one beside them. Install: `npx candor-ui add settings-layout` `` props: - `groups: SettingsGroup[]`: The sections, under their group labels; locked ones stay listed with the reason. - `active: string`: The id of the open section. - `onSelect: (id: string) => void`: Called with a section's id when it's chosen; never for a locked one. - `title?: string | undefined`: The accessible name of the section list. Defaults to "Settings". - `children: React.ReactNode` - `className?: string | undefined` `` props: - `title: string`: The section's heading. - `description?: React.ReactNode | undefined`: A line under the heading saying what the section controls. - `children: React.ReactNode` - `className?: string | undefined` ### shortcuts-dialog (Pro) Every keyboard shortcut, grouped by where it works, printed for this platform (⌘ on a Mac, Ctrl elsewhere). Install: `npx candor-ui add shortcuts-dialog` `` props: - `open: boolean`: Whether the dialog is showing. - `onOpenChange: (open: boolean) => void`: Called when the dialog opens or closes. - `groups: ShortcutGroup[]`: The bound shortcuts, under headings for where they work. ### side-panel (Pro) The panel beside the thread: one tab per open item (a diff, an approval, a document), each closable. Install: `npx candor-ui add side-panel` `` props: - `tabs: PanelTab[]`: The open items, one tab each, with their content. - `activeId?: string | undefined`: The id of the tab showing; without one (or an unknown id), the first tab. - `onActivate?: ((id: string) => void) | undefined`: Called with a tab's id when it's chosen. - `onClose?: ((id: string) => void) | undefined`: Shows a close button on each tab, and lets Delete close the focused tab; called with the tab's id. - `actions?: React.ReactNode | undefined`: Buttons at the end of the tab row (hide the panel, open full width), kept out of the tab list's arrow keys. - `keepTabs?: boolean | undefined` (default `false`): Keeps tabs that aren't showing mounted, so each keeps its state and scroll position. Defaults to false: only the showing tab is rendered. - `className?: string | undefined` ### toast (Pro) Short notices in the corner: polite for successes, assertive for errors, which stay until dismissed. Install: `npx candor-ui add toast` `` props: - `offset?: number | string | undefined`: Space to keep clear below the toasts, such as a composer's height: a number in px or a CSS length. - `className?: string | undefined` ## Team People and access: members, invites, roles. ### access-request (Pro) Ask for a role you don't have on an environment. Install: `npx candor-ui add access-request` `` props: - `environments: Environment[]`: The environments a role can be asked for on. - `roles: Role[]`: Every role, so the one you hold can be named. - `requestable: string[]`: Role ids that can be asked for. - `current: Record`: The viewer's role id per environment id. - `deciders: Record`: Who decides, per environment id. - `note?: string | undefined`: The app's rule, e.g. "Raising a role always needs approval." - `sent?: SentAccessRequest | null | undefined`: The request already sent; set, the form gives way to a pending note. null/undefined means none sent. - `onSend: (environmentId: string, roleId: string, reason: string) => void`: Called on send with the environment id, role id and the reason given. - `onWithdraw?: (() => void) | undefined`: Shows Withdraw on a pending request; called when it's clicked. - `className?: string | undefined` ### account-create (Pro) Create your company's account. Install: `npx candor-ui add account-create` `` props: - `email: string`: The signed-in person's email, shown at the top. - `verified: boolean`: Whether that email is verified; until it is, Create is locked with the reason. - `pendingInvites?: number | undefined` (default `0`): How many invites are waiting for this person; above 0, says creating an account supersedes them. Defaults to 0. - `ownerNote?: React.ReactNode | undefined`: What being the owner means here, e.g. "Admin everywhere; ownership can’t be handed over yet." - `onCreate: (name: string) => void`: Called on submit with the trimmed company name. - `onSeeInvites?: (() => void) | undefined`: Shows a link to the waiting invites; called when it's clicked. - `busy?: boolean | undefined` (default `false`): Disables Create while the account is being made. - `error?: string | undefined`: Shown under the name field, e.g. when the name is taken. - `className?: string | undefined` ### audit-log (Pro) The account's audit log. Install: `npx candor-ui add audit-log` `` props: - `events: AuditEvent[]`: The rows, in any order; the newest shows first. - `resolve: (id: string) => string | undefined`: Turns a principal or target id into a display name, when known. - `actions?: Record | undefined`: Labels and groups for your app's own actions, by code: `{ "connection.created": { label: "connected", group: "data" } }`. Also overrides a known action's label. - `className?: string | undefined` ### consent-ceremony (Pro) Consent that names exactly what flows where (Candor's CeremonySurface): each flow as what → where → how long it's kept, an acknowledgement the person ticks themselves, and how to take it back. Install: `npx candor-ui add consent-ceremony` `` props: - `title: string`: The heading, e.g. "Let agents read your workspace". - `flows: DataFlow[]`: Each thing read: what it is, where it goes and how long it's kept. - `notFlowing?: string[] | undefined`: What does not leave, said plainly. - `revoke: string`: How to revoke later. - `acknowledgement: string`: The sentence the person ticks themselves before granting. - `grantLabel?: string | undefined`: The grant button's label. Defaults to "Allow". - `onGrant: () => void`: Called when the person grants, after ticking the acknowledgement. - `onCancel?: (() => void) | undefined`: Shows Not now; called when it's clicked. - `busy?: boolean | undefined` (default `false`): Disables the grant button while consent is being recorded. - `className?: string | undefined` ### invite-chooser (Pro) Shown at sign-in when more than one account has invited you. Install: `npx candor-ui add invite-chooser` `` props: - `invites: IncomingInvite[]`: The invites waiting for this person, one per account. - `onJoin: (id: string) => void`: Called with the chosen invite's id when the person joins. - `onCreateOwn?: (() => void) | undefined`: Shows a link to create their own account instead; called when it's clicked. - `busy?: boolean | undefined` (default `false`): Disables Join while it's being recorded. - `className?: string | undefined` ### invite-members (Pro) Invite people by pasting any list of emails. Install: `npx candor-ui add invite-members` `` props: - `environments: Environment[]`: Environments the inviter may invite to. - `grants: string`: The role label the invite grants, e.g. "Editor". - `rule?: string | undefined`: The app's rule, e.g. "An Admin can raise roles once they’ve joined." - `footnote?: string | undefined`: How invites work, from the app, e.g. "Invites expire in 7 days." - `existing?: string[] | undefined` (default `[]`): Emails already in the account. - `onInvite: (emails: string[], environmentIds: string[]) => void`: Called on send with the valid new emails and the ticked environment ids. - `busy?: boolean | undefined` (default `false`): Disables Send while the invites are going out. - `className?: string | undefined` ### members-table (Pro) Members, their role on each environment, and invites still pending. Install: `npx candor-ui add members-table` `` props: - `members: Member[]`: The account's members, one row each. - `invites?: Invite[] | undefined` (default `[]`): Invites sent; pending ones are listed under the members. - `environments: Environment[]`: The environments, one role column each. - `roles: Role[]`: The roles a member can hold, lowest first. - `ownerRole?: string | undefined`: The role id shown for the owner on every environment, if the owner has one implicitly. - `viewer: Viewer`: Who's looking: marks their row as "(you)", and only an owner can remove members. - `lockedCell?: ((member: Member, environment: Environment) => string | undefined) | undefined`: Why the viewer can't change this cell, or nothing if they can. - `pending?: Record> | undefined` (default `{}`): Role changes waiting for approval: member id → environment id → requested role id (null = remove). - `onSetRole?: ((memberId: string, environmentId: string, roleId: string | null) => void) | undefined`: Makes role cells editable; called with the member id, environment id and new role id (null = no role). - `onRemove?: ((memberId: string) => void) | undefined`: Gives the owner a Remove action per member; called with the member id. - `onRevokeInvite?: ((inviteId: string) => void) | undefined`: Shows Revoke on pending invites; called with the invite id. - `className?: string | undefined` ### profile-settings (Pro) Who you are in the app: your name, your email (shown, but changed through your sign-in provider, which the field says), your time zone for schedules and timestamps, and your theme. Install: `npx candor-ui add profile-settings` `` props: - `profile: Profile`: The saved profile; the form starts from it and Save enables once it differs. - `timeZones: string[]`: IANA time zones offered, e.g. "Europe/London". - `emailManagedBy: string`: Where the email is changed, e.g. "Your company’s Okta". - `emailVerified: boolean`: Marks the email as verified. - `onSave: (p: Profile) => void | Promise`: Called on save with the edited profile; "Saved" shows once it resolves. - `className?: string | undefined` ### setup-checklist (Pro) What's left before the first useful answer: connect an environment, let the agents read it, invite the team. Install: `npx candor-ui add setup-checklist` `` props: - `title: string`: The heading, also the checklist's accessible name. - `steps: SetupStep[]`: The steps in order, each with its status and action. - `bare?: boolean | undefined` (default `false`): No border or heading, only the progress and steps, for inside another card (AccountState's `steps`). Defaults to false. - `className?: string | undefined` ### sign-in (Pro) Sign in without a password: your company's SSO, or a one-time code sent to your email. Install: `npx candor-ui add sign-in` `` props: - `brand?: React.ReactNode | undefined`: Your logo or name, shown above the form. - `onSso?: (() => void) | undefined`: Shows the SSO button; called when it's clicked. - `onSendCode: (email: string) => void | Promise`: Called with the email when a code is asked for; the code screen shows next. - `onVerifyCode: (email: string, code: string) => void | Promise`: Called with the email and the six-digit code typed. - `busy?: boolean | undefined` (default `false`): Disables the buttons and shows a spinner while a request is in flight. - `error?: string | undefined`: Shown under the field it concerns. - `className?: string | undefined` ### step-walker (Pro) A guided walk (Candor's StepWalker): the stages across the top, the current one as a focus card below. Install: `npx candor-ui add step-walker` `` props: - `stages: string[]`: Stage names, in order. - `current: number`: Index of the current stage, from 0; earlier ones show as done. - `onGoTo?: ((index: number) => void) | undefined`: Lets finished stages be revisited; called with the stage's index. - `children: React.ReactNode` - `className?: string | undefined` ### terms-consent (Pro) The AI disclosure and terms, asked once per terms version. Install: `npx candor-ui add terms-consent` `` props: - `version: string`: e.g. "2026-11". - `points: string[]`: What's AI and what people decide, one sentence each. - `documents: { label: string; href: string }[]`: The terms documents, linked and opened in a new tab. - `changed?: string | undefined`: Set when this replaces a version the person agreed to. - `onAgree: (version: string) => void`: Called with the terms version when the person agrees. - `busy?: boolean | undefined` (default `false`): Disables Agree while the agreement is being recorded. - `className?: string | undefined` ## Knowledge What the agent knows: documents, diagrams, freshness. ### confidence-mark (Pro) How sure the system is, with what it rests on. Install: `npx candor-ui add confidence-mark` `` props: - `value: Confidence`: How sure: high, medium, low or unknown. - `basis: string`: What the confidence rests on, e.g. "3 sources agree", shown on hover. - `className?: string | undefined` ### diagram (Pro) A diagram an agent wrote as Mermaid (a data model, a flow, a sequence), rendered in strict mode in the theme's colours. Install: `npx candor-ui add diagram` `` props: - `source: string`: The Mermaid source. - `title: string`: Heading above the diagram, also its accessible name. - `caption?: string | undefined`: A line under the title saying what the diagram shows. - `className?: string | undefined` ### freshness-stamp (Pro) How old a piece of knowledge is (Candor's FreshnessStamp). Install: `npx candor-ui add freshness-stamp` `` props: - `readAt: string | null`: When it was last read (ISO date). null means it never was, shown as "Never read". - `everyHours?: number | undefined`: Expected re-read interval; overdue past 1.5× this. - `verb?: string | undefined`: The word before the time, e.g. "Synced" or "Checked". - `className?: string | undefined` ### knowledge-sources (Pro) Where the agents' knowledge comes from, grouped by door: the environment itself, sampled data, files and links people shared, answers they gave. Install: `npx candor-ui add knowledge-sources` `` props: - `sources: KnowSource[]`: Every source, grouped by where it came from, each with when it was last read and any error. - `onAdd?: (() => void) | undefined`: Shows an Add button; called when it's clicked. - `onReread?: ((id: string) => void) | undefined`: Shows a read-again button on each source not already being read; called with its id. - `className?: string | undefined` ### memory-manager (Pro) What agents remember about this account, one line each, with who taught it and when. Install: `npx candor-ui add memory-manager` `` props: - `memories: Memory[]`: What's remembered, with who taught it (a person or an agent) and when. - `onAdd?: ((text: string) => void) | undefined`: Shows a box to add a memory; called with its text. - `onDelete?: ((id: string) => void) | undefined`: Shows Delete on each memory; called with its id. - `onConfirm?: ((id: string) => void) | undefined`: Turn an inferred memory into one the viewer stands behind. - `history?: { chats?: number | undefined } | undefined`: Agents also learn from past chats, which can't be listed: says so, with how many chats if known. - `mode?: MemoryModeValue | undefined`: Whether memory is on, paused or off (see MemoryMode). Paused and off are said above the list. - `className?: string | undefined` ### memory-mode (Pro) Whether agents use memory: on, paused or off, with what each does to the memories already kept. Install: `npx candor-ui add memory-mode` `` props: - `mode?: MemoryModeValue | undefined`: The mode the app last reported. Undefined while it hasn't said. - `whenOff: "kept" | "deleted"`: What turning memory off does to existing memories in your app: they're "kept", or "deleted" (asks first). - `count?: number | undefined`: How many memories are kept now, if known. Shown on paused and off, and in the delete question. - `onChange?: ((mode: MemoryModeValue) => void) | undefined`: Asks for a change. Show the new mode once the app reports it (`mode`). - `pending?: boolean | undefined` (default `false`): A change is on its way. - `error?: string | undefined`: Why the last change failed, if it did. Pass "" for no reason. - `locked?: string | undefined`: Why memory can't be changed here: a policy, a role. - `className?: string | undefined` ### memory-used (Pro) The line under a reply that says what it remembered: "Used 2 memories", which opens them, each with who taught it and when. Install: `npx candor-ui add memory-used` `` props: - `memories: Memory[]`: The memories this reply used, as the app recorded them. - `forgotten?: number | undefined` (default `0`): How many memories it used that have since been forgotten (their words are gone). - `fromHistory?: boolean | undefined` (default `false`): It also drew on past chats, which can't be listed. - `onOpen?: ((id: string) => void) | undefined`: Makes each memory a button that opens it, e.g. in MemoryManager; called with its id. - `onManage?: (() => void) | undefined`: Shows "Manage memory" at the foot of the list. - `className?: string | undefined` ### prose-diff (Pro) An agent's rewrite of a document (a knowledge page, a process description), shown word by word against the original. Install: `npx candor-ui add prose-diff` `` props: - `original: string`: The text before the rewrite. - `revised: string`: The agent's rewrite. - `onResolve?: ((text: string) => void) | undefined`: Called with the final text when every change has a decision. - `readOnly?: boolean | undefined` (default `false`): Show the changes without accept and reject: the header counts them, and `onResolve` is never called. - `className?: string | undefined` ### provenance-trace (Pro) Live provenance (Candor's ProvenanceOverlay). Install: `npx candor-ui add provenance-trace` `` props: - `claims: Claim[]`: The answer's claims, each with the ids of the passages it rests on. - `evidence: RetrievedPassage[]`: The passages the claims point to. - `className?: string | undefined` ### raci-chip (Pro) Who's responsible, accountable, consulted or informed, as a compact chip. Install: `npx candor-ui add raci-chip` `` props: - `people: RaciAssignment[]`: Who holds which role; shown Accountable first, then Responsible, Consulted, Informed. - `className?: string | undefined` ### retrieval-inspector (Pro) The passages behind an answer, in the order the retriever ranked them. Install: `npx candor-ui add retrieval-inspector` `` props: - `passages: RetrievedPassage[]`: The retrieved passages, in rank order, each marked cited or not. - `sources: KnowSource[]`: The sources the passages come from, looked up by id for name and freshness. - `verb?: string | undefined`: The word before each passage's date, for what `readAt` records: "Reviewed", "Published", "Synced". Defaults to FreshnessStamp's "Read". - `className?: string | undefined` ### source-ingest (Pro) Add knowledge: drop files, paste a link, or paste text (meeting notes, a process description). Install: `npx candor-ui add source-ingest` `` props: - `onFiles: (files: File[]) => void`: Called with the files a person dropped or chose. - `onLink: (url: string) => void`: Called with a pasted link when it's added. - `onText: (title: string, text: string) => void`: Called with the title and body of pasted text when it's added. - `accept?: string | undefined` (default `".pdf,.docx,.md,.txt,.csv,.xlsx"`): File types the picker offers, as in the input accept attribute. - `className?: string | undefined` ### version-history (Pro) Live, draft and past versions of something editable (an agent's settings, a knowledge page), newest first, with who changed it and why. Install: `npx candor-ui add version-history` `` props: - `versions: Version[]`: Every version: live, draft or past, with who changed it, when and why. - `activeId?: string | undefined`: The version being viewed, highlighted. - `onSelect?: ((id: string) => void) | undefined`: Makes each version's name a button; called with its id. - `onPublish?: ((id: string) => void) | undefined`: Shows Publish on the draft; called with its id. - `onRestore?: ((id: string) => void) | undefined`: Shows Restore on past versions; called with the version's id to copy into a new draft. - `className?: string | undefined` ## Operations Running agents: traces, usage, health. ### run-estimate (Pro) What a run is likely to take before it starts: cost, time and (when it makes them) API calls, as ranges with what they're based on. Install: `npx candor-ui add run-estimate` `` props: - `title: string`: What the run will do, as a heading. - `estimate: Estimate`: Cost, time and API-call ranges with what they're based on, or unknown with the reason. - `apiRemaining?: number | undefined`: Calls left today against the API's allowance, when known. - `apiLabel?: string | undefined`: What the calls are, e.g. "CRM API calls". Defaults to "API calls". - `onStart?: (() => void) | undefined`: Shows a Start button; called when it's clicked. - `onCancel?: (() => void) | undefined`: Shows a Cancel button; called when it's clicked. - `startLocked?: string | undefined`: Why Start can't be used yet. Without one, Start is enabled. - `className?: string | undefined` ### run-log (Pro) Every agent run, one line each, newest first: status, what it was, who ran it, where, when, how long and what it cost. Install: `npx candor-ui add run-log` `` props: - `runs: RunLogEntry[]`: The runs to list; shown newest first. - `onOpen?: ((id: string) => void) | undefined`: Makes each run's name a button; called with the run's id. - `className?: string | undefined` ### run-receipt (Pro) What one run cost and where it went: per model (input, output and cached tokens, cost), tool calls, and any other figures the app measures. Install: `npx candor-ui add run-receipt` `` props: - `receipt: RunReceiptData`: The run's measured usage. A model without a cost counts as not measured. - `className?: string | undefined` ### spend-breakdown (Pro) AI spend over time, split by model, agent or feature. Install: `npx candor-ui add spend-breakdown` `` props: - `periods: string[]`: The time periods along the x-axis, e.g. months, oldest first. - `by: Partial>`: Rows per split; each row's values align with `periods` (null when that period isn't known). - `splits?: SpendSplit[] | undefined`: Which splits to offer, in order, e.g. without one that has a single row. Defaults to every split in `by`. With one, there's no switch. - `totalText?: string | undefined`: The total as your server wrote it ("about $1,240"), shown instead of summing the known values. - `className?: string | undefined` ### trace-viewer (Pro) One run as a timeline: each span (agent step, model call, tool, external call, a wait for a person) as a bar on a shared clock, nested under its parent. Install: `npx candor-ui add trace-viewer` `` props: - `spans: TraceSpan[]`: The run's spans, each with its parent, start and duration in ms from the run's start; no duration means still running. - `total: number`: ms; the run's length so far. - `className?: string | undefined` ### usage-meters (Pro) What's used against each limit: seats, an environment's daily API allowance, agent work. Install: `npx candor-ui add usage-meters` `` props: - `usages: Usage[]`: One meter per limit: what's used, the limit (null when there is none), the unit and when it resets. - `className?: string | undefined` ## Evals Judging agent output: scorecards, failure clusters, review queues. ### eval-scorecard (Pro) An eval run against its baseline: overall pass rate, then each criterion's rate, its change from the baseline, and a regression flag where it fell by more than the threshold. Install: `npx candor-ui add eval-scorecard` `` props: - `title: string`: The run's name, shown over the overall pass rate. - `criteria: Criterion[]`: Each criterion's passed and failed counts and its baseline pass rate (0–1, null when there is none). - `threshold?: number | undefined` (default `0.05`): A drop larger than this (0–1) counts as a regression. - `unit?: string | undefined`: What each counted item is, plural, as in "12 of 14 checks passed". Defaults to "checks". - `criterionLabel?: string | undefined`: The heading over the criteria column. Defaults to "Criterion". - `baselineLabel?: string | undefined`: What the comparison is against, as in "vs baseline" and `No ${baselineLabel}`. Defaults to "baseline". - `className?: string | undefined` ### failure-clusters (Pro) Failing runs grouped by what went wrong, largest first, each with its share of failures, how it moved since last period, and a few real examples. Install: `npx candor-ui add failure-clusters` `` props: - `clusters: FailureClusterInput[]`: Failure groups, each with its count, change since the comparison and example runs. Shown largest first. A `delta` of null (nothing to compare with) is shown as unknown. - `title?: string | undefined`: The heading. Defaults to "Why runs failed". - `unit?: string | undefined`: What the total counts, plural, as in "12 failures". Defaults to "failures". - `since?: string | undefined`: What the change is measured against, read after "more than" and "fewer than", as in "production's run". Defaults to "last period". - `className?: string | undefined` ### quality-trend (Pro) Scores over time (judge scores on live threads, by default), with what changed alongside: a model switch, an instructions edit, a new tool. Install: `npx candor-ui add quality-trend` `` props: - `title?: string | undefined`: The chart's title. Defaults to "Answer quality". - `subtitle?: string | undefined`: The line under the title. Defaults to "Judge score, daily". - `seriesLabel?: string | undefined`: What the line measures, for the legend and the data table. Defaults to "Judge score". - `gapNote?: ((days: number) => string) | undefined`: What to say about days with no score, given how many there are. Defaults to "3 days weren’t sampled." - `points: QualityPoint[]`: One judge score per day (0–1, null when not sampled), with any change made that day. - `className?: string | undefined` ### review-queue (Pro) Grade real agent answers one at a time, from the keyboard: P pass, F fail, J/K next and previous. Install: `npx candor-ui add review-queue` `` props: - `items: ReviewItem[]`: Answers to grade; it opens on the first one without a grade. - `onGrade: (id: string, grade: "pass" | "fail", note?: string) => void`: Called with the item's id, the grade, and the reviewer's note if they wrote one. - `className?: string | undefined` ## Admin Settings and controls: permissions, schedules, data controls. ### channel-setup (Pro) Where agents can reach the team outside the app, one row per channel: its status, where it posts, and when an agent may post without asking. Install: `npx candor-ui add channel-setup` `` props: - `channels: Channel[]`: One row per channel, with its status, where it posts and when agents may post. - `onConnect?: ((id: string) => void) | undefined`: Shows Connect, or Reconnect on a broken channel; called with the channel id. - `onReplies?: ((id: string, r: Channel["replies"]) => void) | undefined`: Shows the when-agents-post choice on connected channels; called with the channel id and the new setting. - `className?: string | undefined` ### data-controls (Pro) Control over the account's data: facts about how it's used (from the service), an export, deleting thread history, and deleting the account. Install: `npx candor-ui add data-controls` `` props: - `account: string`: The account's name; destructive steps ask for it typed exactly. - `statements: string[]`: How data is used, one sentence each, e.g. "Never used to train models". - `exportState: ExportState`: Where the export is: idle, preparing, ready to download, or failed. - `onExport: () => void`: Start an export. - `onDeleteHistory?: (() => void) | undefined`: Delete all thread history. Without it, the row isn't shown. - `onDeleteAccount?: (() => void) | undefined`: Delete the account. Without it, the row isn't shown. - `deleteAccountLocked?: string | undefined`: Why the viewer can't delete the account (non-owners). - `deleteHistoryLocked?: string | undefined`: Why the viewer can't delete thread history, e.g. "Only owners can delete data." The row shows, locked. - `exportLocked?: string | undefined`: Why the viewer can't export, e.g. "Only admins can export." - `whatDeleteRemoves: string[]`: What deleting the account removes, from the service. - `exportIncludes: string`: What the export contains, from the service. - `historyNote: string`: What deleting history removes and keeps, from the service. - `className?: string | undefined` ### data-region (Pro) Where the account's data lives and is processed, service by service. Install: `npx candor-ui add data-region` `` props: - `region: RegionInfo`: The region's name, a line of detail, and where each service runs. - `onlyOption?: boolean | undefined` (default `true`): Says this is the only region offered today. Defaults to true. - `className?: string | undefined` ### data-retention (Pro) How long each kind of data is kept, and what happens after. Install: `npx candor-ui add data-retention` `` props: - `rows: RetentionRow[]`: One row per kind of data: how long it's kept and what happens after. - `version: string`: The policy's version, shown in the header. - `changedAt: string`: When the policy last changed, as an ISO date. - `className?: string | undefined` ### device-sessions (Pro) Everywhere you're signed in, with how each session signed in (browser, device code, or a token from the environment), where, and when it was last used. Install: `npx candor-ui add device-sessions` `` props: - `sessions: DeviceSession[]`: Every signed-in session, including the current one. - `onSignOut?: ((id: string) => void) | undefined`: Shows Sign out on each other session; called with its id. - `onSignOutOthers?: (() => void) | undefined`: Shows a button to sign out every session but this one, when there are others. - `className?: string | undefined` ### email-layout (Pro) The shell every transactional email uses: brand, title, body, one next step, and why you got it, rendered to HTML that survives email clients. Install: `npx candor-ui add email-layout` `` props: - `notice: EmailNotice`: What the email says: preheader, title, body, next step, ids and why it was sent. - `brand: string`: The product name shown at the top. - `colors?: EmailColors | undefined` (default `defaultEmailColors`): Fixed hex colours to match your brand. Defaults to the default theme's light values. - `strings?: Partial | undefined`: The email's fixed words, e.g. `{ nextRun: "Ensuite, lancez :" }`. Passed directly: emails render outside any LocaleProvider. - `lang?: string | undefined` (default `"en"`): The email's language, for ``. `` props: - `notice: EmailNotice`: What the email says. - `brand: string`: The product name shown at the top. - `colors?: EmailColors | undefined` (default `defaultEmailColors`): Fixed hex colours; defaults to the default theme's light values. - `strings?: Partial | undefined`: The email's fixed words. - `headingLevel?: 2 | 3 | 4 | undefined` (default `3`): The heading level of the email's title on your page. Default 3. - `label?: string | undefined`: The preview's accessible name. Default: "Email preview: " and the title. - `className?: string | undefined` ### notification-preferences (Pro) What reaches you, and where: one row per kind of event, one column per channel. Install: `npx candor-ui add notification-preferences` `` props: - `events: NoticeEvent[]`: The kinds of event, one row each. - `channels: NoticeChannel[]`: The channels, one column each. - `value: NoticePrefs`: Which cells are on, by event id and channel; a missing cell is off. - `onChange: (eventId: string, channel: NoticeChannel, on: boolean) => void`: Called with the event id, channel and new state when a cell is toggled. - `locked?: Record>> | undefined` (default `{}`): Reasons a cell can't be changed, by event id and channel. - `className?: string | undefined` ### role-matrix (Pro) What each role can do, as a matrix. Install: `npx candor-ui add role-matrix` `` props: - `columns: RoleColumn[]`: The roles, one column each. - `rows: RoleRow[]`: One capability per row, with a cell per role id; a missing cell reads as no. - `className?: string | undefined` ### schedule-list (Pro) Recurring agent jobs (a morning health check, a weekly hygiene report): when they run in plain words, when they run next, a strip of recent outcomes, and pause/resume. Install: `npx candor-ui add schedule-list` `` props: - `schedules: Schedule[]`: The recurring jobs, with their schedule, next run and recent outcomes. - `onToggle?: ((id: string, paused: boolean) => void) | undefined`: Shows pause/resume; called with the job id and whether it should now be paused. - `className?: string | undefined` ### sso-setup (Pro) Single sign-on through the account's identity provider. Install: `npx candor-ui add sso-setup` `` props: - `state: SsoState`: Where setup stands: not set, verifying the domain, or active. - `onStart?: (() => void) | undefined`: Opens the identity provider's admin portal. - `onCheck?: (() => void) | undefined`: Shows Check now while the domain is verifying. - `onEnforce?: ((on: boolean) => void) | undefined`: Shows the Require SSO checkbox when active; called with the new setting. - `enforceLocked?: string | undefined`: Why this person can't change Require SSO, e.g. only the owner can. Unset means they can. - `label?: string | undefined`: The section's accessible name; set it when two are on one page. - `className?: string | undefined` ## Billing Plans, usage and invoices. ### downgrade-impact (Pro) What moving to a smaller plan takes away, before you confirm: the features you lose (and what happens to anything that used them), the new monthly total, and when it takes effect. Install: `npx candor-ui add downgrade-impact` `` props: - `from: PlanTier`: The current plan. - `to: PlanTier`: The smaller plan being moved to. - `seats: number`: Seats on the account, for the old and new monthly totals. - `losses: { feature: string; consequence: string }[]`: What goes, and what happens to things that depended on it. - `effectiveAt: string`: When the new plan takes effect, as an ISO date. - `onConfirm: () => void`: Called on confirm, which stays locked until the losses are acknowledged. - `onCancel?: (() => void) | undefined`: Shows a button to keep the current plan; called when it's clicked. - `className?: string | undefined` ### plan-picker (Pro) Choose a plan and seats. Install: `npx candor-ui add plan-picker` `` props: - `plans: PlanTier[]`: The plans to choose from, one card each. - `current?: PlanTier["id"] | undefined`: The account's plan, marked Current and selected at first. Undefined means no plan yet. - `seats?: number | undefined` (default `1`): The starting seat count. Defaults to 1, and never below minSeats. - `minSeats?: number | undefined` (default `1`): Seats can't go below members already in the account. - `terms?: string | undefined`: What every plan includes and how billing works, e.g. "No trial: billing starts when you choose a plan." - `onChoose: (plan: PlanTier["id"], seats: number) => void`: Called with the chosen plan and seat count; nothing is charged before this. - `className?: string | undefined` ### subscription-status (Pro) Where the subscription stands: plan, seats paid against seats used, the card on file, and when it renews or ends. Install: `npx candor-ui add subscription-status` `` props: - `sub: Subscription`: The subscription: status, seats, period end, card and any billing issue. - `plan: PlanTier`: The subscribed plan, for its name and per-seat price. - `onManage?: (() => void) | undefined`: Opens Stripe's customer portal. - `onKeep?: (() => void) | undefined`: Undo a pending cancellation. - `retention?: string | undefined`: What's kept after access ends, from the service's retention policy. Omitted when unknown. - `label?: string | undefined`: The section's accessible name; set it when two are on one page. - `className?: string | undefined` ## Collaboration Working alongside other people and agents. ### away-digest (Pro) What happened since you were last here, in the order you'd act on it: waiting on you, failed, finished. Install: `npx candor-ui add away-digest` `` props: - `since: string`: When the person was last here (ISO date), shown as a relative time. - `items: DigestItem[]`: What happened since, grouped by kind: waiting, failed, finished. - `onOpen?: ((id: string) => void) | undefined`: Called with an item's id when a person opens it. - `className?: string | undefined` ### handoff-card (Pro) A run passed from one person to another while it's in flight: who from, who to, the run and where it is, the note, and what does and doesn't transfer. Install: `npx candor-ui add handoff-card` `` props: - `run: string`: The run or thread being handed over. - `status: RunStatus`: Where the run is now. - `from: string`: Who hands it over. - `to: string`: Who it goes to: a person or a team. - `note?: string | undefined`: The sender's note for the recipient. - `at: string`: When it was handed over (ISO). - `moves: string[]`: What transfers, as the service defines it. - `stays: string[]`: What doesn't. - `state: "pending" | "accepted" | "declined"`: Whether the recipient has taken it over yet. - `pendingNote?: string | undefined`: What happens while it waits, in place of "Stays with until accepts." E.g. "The agent has stopped replying; it waits for Support." - `onAccept?: (() => void) | undefined`: Take it over. Without it, there's no button. - `onDecline?: (() => void) | undefined`: Turn it down. Without it, there's no button. - `className?: string | undefined` ### share-thread (Pro) Share a thread: who can open it, and where the shared copy ends (so later messages aren't shared by accident). Install: `npx candor-ui add share-thread` `` props: - `audiences: ShareAudience[]`: The first audience means "not shared". - `initial?: string | undefined`: The audience selected when it opens. Defaults to the first, not shared. - `messageCount: number`: How many messages the thread has; the share point can be set anywhere up to it. - `onShare: (audienceId: string, upTo: number) => void`: Called with the chosen audience and the last message number to share (1-based). The first audience's id means stop sharing. - `className?: string | undefined` ## Data Tables and records. ### attributes-rail (Pro) A record's key/value facts as a definition list: label left, value right, hairline-separated. Install: `npx candor-ui add attributes-rail` `` props: - `items: { label: string; value: React.ReactNode | null }[]`: The facts, in order. A null, undefined or empty value shows as "Not known". - `className?: string | undefined` ### column-mapper (Pro) Match file columns to the object's fields. Install: `npx candor-ui add column-mapper` `` props: - `columns: ImportColumn[]`: The file's columns, with sample values. - `fields: TargetField[]`: The fields a column can map to; required ones are marked and checked. - `mapping: ColumnMapping[]`: The current match for each column, and who made it: exact name, the model (with confidence) or you. - `onChange: (mapping: ColumnMapping[]) => void`: Called with the whole new mapping when a person changes a column's field. - `className?: string | undefined` ### data-import (Pro) Drop a spreadsheet, then see exactly what was read: rows, columns with sample values, and any rows that couldn't be read and why. Install: `npx candor-ui add data-import` `` props: - `read: ImportRead | null`: What was read from the file. null shows the drop zone. - `onFile: (file: File) => void`: Called with the file a person dropped or chose. - `reading?: boolean | undefined` (default `false`): The file is being read; the drop zone says so and the button is disabled. - `accept?: string | undefined` (default `".csv,.xlsx,.xls,.tsv"`): File types the picker offers, as in the input accept attribute. - `className?: string | undefined` ### data-table (Pro) Rows of records: search, sort, filter chips, column settings, selection and pages. Install: `npx candor-ui add data-table` `` props: - `columns: Column[]`: The columns: header, how to read and show a row's value, and whether it's hidden until turned on. - `rows: Row[]`: The loaded records. Search, sort and paging work on these in the browser. - `rowId: (row: Row) => string`: A stable id for a row, used for keys and selection. - `title?: string | undefined`: Heading over the table, also its accessible name. Defaults to "Records" for the name, with no heading shown. - `loading?: boolean | undefined` (default `false`): Rows are being fetched; shows skeleton rows instead of the empty message. - `searchable?: boolean | undefined` (default `true`): Shows a search box that matches any column's value. - `filters?: FilterChip[] | undefined` (default `[]`): Filters already applied, shown as removable chips. - `onRemoveFilter?: ((id: string) => void) | undefined`: Called with a filter's id when its chip is removed. - `onClearFilters?: (() => void) | undefined`: Called when a person clears all filters. - `selectable?: boolean | undefined` (default `false`): Adds a checkbox to each row and a select-all for the page. - `selected?: Set | undefined`: Ids of selected rows, when you control selection. Without it the table keeps its own. - `onSelectedChange?: ((ids: Set) => void) | undefined`: Called with the new set of selected ids when a person selects or clears rows. - `onRowClick?: ((row: Row) => void) | undefined`: Called with the row a person clicks; rows look clickable when set. - `pageSize?: number | undefined` (default `10`): Rows per page. - `empty?: string | undefined`: Shown when there are no rows at all (not when a search or filter matches nothing). - `actions?: ((selected: Set) => React.ReactNode) | undefined`: Shown in the header when rows are selected, e.g. bulk actions. - `className?: string | undefined` ### filter-chips (Pro) Active filters as removable chips, with a clear-all. Install: `npx candor-ui add filter-chips` `` props: - `filters: FilterChip[]`: The active filters, each shown as label: value. - `onRemove: (id: string) => void`: Called with a filter's id when its chip is removed. - `onClear?: (() => void) | undefined`: Shows Clear all; called when it's clicked. - `className?: string | undefined` ### import-review (Pro) Check rows before they land: how many are ready, which need fixing and why, grouped by kind of problem. Install: `npx candor-ui add import-review` `` props: - `total: number`: How many rows the file has. - `issues: ImportIssue[]`: Problems found, one per row and field, with a suggested fix where there is one. - `target: string`: Where rows go, e.g. "Customers in Shop staging". - `onFix: (fixes: ImportIssue[]) => void`: Called with the issues whose suggested fixes a person accepted, one row or a whole group. - `onLoad: (skipRows: number[]) => void`: Called on Load with the row numbers to leave out; empty unless the person chose to skip rows with problems. - `loading?: boolean | undefined` (default `false`): Rows are being loaded; the Load button is disabled. - `className?: string | undefined` ### tree (Pro) A hierarchy (objects → fields, a flow's elements, a knowledge base's sections) with the keyboard behaviour of a tree: ↑↓ move, → opens or steps in, ← closes or steps out, Home/End jump, Enter selects. Install: `npx candor-ui add tree` `` props: - `nodes: TreeNode[]`: The top-level nodes, each with its children. - `selectedId?: string | undefined`: The selected node's id, highlighted and focused first. - `onSelect?: ((node: TreeNode) => void) | undefined`: Called with the node a person clicks or presses Enter on. - `defaultOpen?: string[] | undefined` (default `[]`): Ids of nodes open on first render. - `label?: string | undefined`: The tree's accessible name. - `className?: string | undefined` ## Charts Charts with accessible colours. ### bar-chart (Pro) Columns by category, grouped or stacked. Install: `npx candor-ui add bar-chart` `` props: - `title: string`: What the chart shows, above it. - `subtitle?: string | undefined`: A line under the title, e.g. the period or unit. - `categories: string[]`: The column labels along the x axis. - `series: Series[]`: One value per category per series; null draws a dashed stub. - `stacked?: boolean | undefined` (default `false`): Stacks series in one column instead of grouping them side by side. - `format?: ValueFormat | undefined` (default `"number"`): How values are written: number, percent (0–1), currency (USD) or duration (seconds). Defaults to number. - `state?: ChartState | undefined`: Loading, empty, partial or error. Defaults to ready. - `height?: number | undefined`: The plot's height in pixels. Defaults to 220. - `className?: string | undefined` ### bullet-bar (Pro) Actual against a target in one row (coverage against the 75% production needs, adoption against a goal). Install: `npx candor-ui add bullet-bar` `` props: - `label: string`: What's measured, e.g. "Test coverage". - `actual: number | null`: The measured value. null means not measured, and says so. - `target: number`: The goal, drawn as a tick. - `max: number`: The value at the bar's right end. - `bands?: number[] | undefined`: Thresholds from worst to best, e.g. [0.6, 0.75] on a 0–1 scale, or [0.1, 0.05] for an error rate. The worst end is shaded darkest. - `format?: ValueFormat | undefined` (default `"number"`): How values are written: number, percent (0–1), currency (USD) or duration (seconds). Defaults to number. - `higherIsBetter?: boolean | undefined` (default `true`): Whether meeting the target means at or above it. Set false when lower is better, e.g. error rate. Defaults to true. - `className?: string | undefined` ### chart-frame (Pro) The chassis every chart sits in (Candor's ChartFrame, the honesty chokepoint): title, legend, a chart/table toggle, and the states a chart can be in. Install: `npx candor-ui add chart-frame` `` props: - `title: string`: What the chart shows, above it. - `subtitle?: string | undefined`: A line under the title, e.g. the period or unit. - `state?: ChartState | undefined` (default `{ kind: "ready" }`): Loading, empty (with why), partial (with what's missing) or error. Defaults to ready. - `legend?: LegendItem[] | undefined`: Series names and colours; shown only when there are two or more. - `table?: TableView | undefined`: Every value as rows, behind a chart/table toggle. Without it there's no toggle. - `height?: number | undefined` (default `220`): The plot's height in pixels. Defaults to 220. - `refreshing?: boolean | undefined` (default `false`): Keeps the previous render at reduced opacity while new data loads. - `defaultWidth?: number | undefined`: The width to draw at until the frame can be measured: on the server, and in test environments like jsdom that measure everything as 0. Left out, it comes from ChartSizeProvider, else 0 (the plot waits for a measurement). - `children: (size: { width: number; height: number }) => React.ReactNode`: Renders the plot at the measured width. - `className?: string | undefined` `` props: - `defaultWidth: number`: The width, in pixels, charts draw at until they can measure themselves. - `children: React.ReactNode` ### donut-chart (Pro) Parts of a whole. Install: `npx candor-ui add donut-chart` `` props: - `title: string`: What the chart shows, above it. - `subtitle?: string | undefined`: A line under the title, e.g. the period or unit. - `parts: DonutPart[]`: The parts of the whole; past six, the smallest fold into Other. - `format?: ValueFormat | undefined` (default `"number"`): How values are written: number, percent (0–1), currency (USD) or duration (seconds). Defaults to number. - `totalLabel?: string | undefined`: The word under the total in the middle. Defaults to "Total". - `state?: ChartState | undefined`: Loading, empty, partial or error. Parts that sum to zero show as empty. - `className?: string | undefined` ### heatmap (Pro) Intensity over a grid (field fill rate by object, runs by hour and day). Install: `npx candor-ui add heatmap` `` props: - `title: string`: What the chart shows, above it. - `subtitle?: string | undefined`: A line under the title, e.g. the period or unit. - `rows: string[]`: The row labels, top to bottom. - `columns: string[]`: The column labels, left to right. - `values: (number | null)[][]`: values[row][column]; null = no data. - `format?: ValueFormat | undefined` (default `"number"`): How values are written: number, percent (0–1), currency (USD) or duration (seconds). Defaults to number. - `state?: ChartState | undefined`: Loading, empty, partial or error. Defaults to partial when any cell is null, else ready. - `className?: string | undefined` ### line-chart (Pro) Change over time. Install: `npx candor-ui add line-chart` `` props: - `title: string`: What the chart shows, above it. - `subtitle?: string | undefined`: A line under the title, e.g. the period or unit. - `x: string[]`: The labels along the x axis, one per point. - `series: Series[]`: One value per x label per series; null leaves a gap. - `area?: boolean | undefined` (default `false`): Fills under each line with a light wash. - `format?: ValueFormat | undefined` (default `"number"`): How values are written: number, percent (0–1), currency (USD) or duration (seconds). Defaults to number. - `zeroBased?: boolean | undefined` (default `false`): Starts the y axis at zero instead of fitting it to the data; areas always start at zero. - `state?: ChartState | undefined`: Loading, empty, partial or error. Defaults to ready. - `height?: number | undefined`: The plot's height in pixels. Defaults to 220. - `className?: string | undefined` ### scale (Pro) Chart scales and tick helpers shared by Candor's charts. Install: `npx candor-ui add scale` ### sparkline (Pro) A word-sized trend. Install: `npx candor-ui add sparkline` `` props: - `values: (number | null)[]`: The points in order; null leaves a gap. Fewer than two numbers shows "Not enough data". - `width?: number | undefined` (default `80`): In pixels. Defaults to 80. - `height?: number | undefined` (default `24`): In pixels. Defaults to 24. - `label: string`: What the trend is, read by assistive tech. - `className?: string | undefined` ## Reports Readable summaries of work. ### comparison-view (Pro) Before and after, numerically: each measure's two values and the change, coloured by whether that change is good for it. Install: `npx candor-ui add comparison-view` `` props: - `before: string`: Heading of the before column, e.g. "Last quarter". - `after: string`: Heading of the after column, e.g. "This quarter". - `rows: ComparisonRow[]`: One row per measure: its two values (null when not measured), format, and which direction is good. - `className?: string | undefined` ### finding (Pro) One finding with its evidence attached (Candor's NarrativeBlock): severity as icon and word (never colour alone), what was found, the evidence it rests on, and what to do next when there's a clear step. Install: `npx candor-ui add finding` `` props: - `finding: FindingData`: The finding: severity, title, what was found, its evidence and the next step if there is one. - `headingLevel?: 2 | 3 | 4 | 5 | undefined` (default `3`): The title's heading level. Defaults to 3, under a ReportSection's h2. - `className?: string | undefined` ### insight-ledger (Pro) The executive summary, in the three states it can honestly be in: not run yet; partial (some sections couldn't be computed, named); or ready, with counts by severity and the few findings that matter most. Install: `npx candor-ui add insight-ledger` `` props: - `state: "not-run" | "partial" | "ready"`: not-run before the checks have run; partial when some sections couldn't be computed (listed in `notComputed`); ready otherwise. - `headline?: string | undefined`: One or two sentences, from the report's own findings. - `findings?: Finding[] | undefined` (default `[]`): The report's findings; counted by severity, and the three most severe are shown. - `notComputed?: { section: string; reason: string }[] | undefined` (default `[]`): Sections that couldn't be computed, and why. - `className?: string | undefined` ### report-sheet (Pro) The paged chassis of a report (release readiness, configuration audit): a cover with what it covers and when its data was read, numbered sections, an export bar, and a provenance footer saying who or what generated it from which sources. Install: `npx candor-ui add report-sheet` `` props: - `title: string`: The report's name, as the cover heading. - `scope: string`: e.g. "Shop production". - `period?: string | undefined`: The time span the report covers, shown after the scope, e.g. "March 2026". - `generatedAt: string`: When the report was generated (ISO timestamp), shown in the footer. - `generatedBy: string`: Who or what generated it, a person or an agent, named in the footer. - `dataReadAt: string | null`: When the underlying data was read (ISO timestamp); null shows that it's unknown. - `onExport?: ((format: "pdf" | "csv" | "md") => void) | undefined`: Shows PDF, CSV and Markdown export buttons; called with the chosen format. - `children: React.ReactNode` - `className?: string | undefined` `` props: - `number: number`: The section's number, shown zero-padded above the title. - `title: string`: The section heading. - `lede?: string | undefined`: A sentence under the heading saying what the section shows. - `children: React.ReactNode` - `className?: string | undefined` ### stat-card (Pro) One metric: label, value, change against a named period, and a small trend. Install: `npx candor-ui add stat-card` `` props: - `kpi: Kpi`: The metric: label, value (null when not computed, with why), format, delta against a named period, and trend. - `className?: string | undefined` `` props: - `kpis: Kpi[]`: The metrics, one card each, keyed by label. - `className?: string | undefined` ### subscore-card (Pro) Weighted subscores behind an overall score. Install: `npx candor-ui add subscore-card` `` props: - `title: string`: What the overall score measures, shown above the total. - `subscores: Subscore[]`: The parts of the score, each with weight, score and max; a null score is left out of the total and says what it needs. - `className?: string | undefined` ## Building blocks Small pieces every screen uses: locked controls, status dots, step lists, relative times. ### copy-field (free) A value a person copies somewhere else (a callback URL, a scope list). Install: `npx candor-ui add copy-field` `` props: - `label: string`: What the value is, shown above it. - `value: string`: The text that is shown and copied. - `className?: string | undefined` ### degraded-panel (free) Something couldn't be done. Install: `npx candor-ui add degraded-panel` `` props: - `reason: React.ReactNode`: What went wrong, in a sentence. - `missing?: React.ReactNode | undefined`: What the person won't see because of it. - `onRetry?: (() => void) | undefined`: Shows a Try again button that calls this. - `retrying?: boolean | undefined` (default `false`): Shows the retry as in progress. - `variant?: "block" | "inline" | undefined` (default `"block"`): A boxed panel, or one line inside other content. - `className?: string | undefined` ### locale (free) The interface's words, language and direction. Install: `npx candor-ui add locale` `` props: - `locale?: string | undefined`: A BCP 47 tag such as "en-GB", "fr" or "ar-EG", for dates, numbers and plural forms. Left out, the browser's own is used once the page has hydrated. - `dir?: TextDirection | undefined`: Text direction. Left out, it follows the locale: "rtl" for Arabic, Hebrew, Persian, Urdu and the like. Set `dir` on `` too, so the page's own layout flips with Candor's. - `timeZone?: string | undefined`: An IANA time zone such as "Europe/Paris". With `locale`, server and browser format dates the same way, so absolute times render on the server too. - `strings?: StringOverrides | undefined`: Overrides by component name, e.g. `{ thread: { jumpToLatest: "…" } }`; any left out stay English. Nested providers merge. - `children: React.ReactNode` ### locked (free) The honest-state rule: a control that cannot be used says why. Install: `npx candor-ui add locked` `` props: - `reason?: string | null | undefined`: Why the control can't be used. Without one, the control renders as normal. - `inline?: boolean | undefined` (default `false`): Print the reason under the control instead of in a tooltip. - `children: Lockable` - `className?: string | undefined` ### relative-time (free) A time as people say it ("5 minutes ago"), with the exact time on hover, safe to render on the server. Install: `npx candor-ui add relative-time` `` props: - `date: Date | string`: When it happened. Shown as "5 minutes ago", with the exact time on hover. - `bare?: boolean | undefined` (default `false`): Drop "ago" and "in", for tight spaces: "5 minutes". - `format?: "relative" | DateStyle | undefined` (default `"relative"`): "relative" (the default), or an absolute "date", "datetime" or "time" in the locale. - `className?: string | undefined` ### status-dot (free) How many times the status reached done or failed from an unfinished one while the dot was on screen; zero when it mounted finished, so nothing moves for a change the reader never saw. Install: `npx candor-ui add status-dot` `` props: - `status: RunStatus`: Which status to show; running and waiting pulse. - `showLabel?: boolean | undefined` (default `false`): Print the status name next to the dot. - `label?: string | undefined`: Words to use instead of the status name. - `className?: string | undefined` ### step-list (free) How many times `status` has reached succeeded or failed from an unfinished status while this component was on screen. Install: `npx candor-ui add step-list` `` props: - `steps: Step[]`: The steps in order, each with a status, and optional detail and meta. - `className?: string | undefined` `` props: - `status: RunStatus`: The step's status, which picks its mark. ### streaming-text (free) Text that is still arriving. Install: `npx candor-ui add streaming-text` `` props: - `text: string`: The text so far. - `streaming?: boolean | undefined` (default `false`): Show a caret while more is arriving; announced once when it stops. - `className?: string | undefined` `` props: - `children: React.ReactNode` - `className?: string | undefined` ### surface (free) Candor's card: a plain, muted, bordered or floating surface, so no screen hand-rolls its own. Install: `npx candor-ui add surface` ### terms (free) The app's words for its own concepts, so components read like the product: one app says "org", another "project" or "workspace". Install: `npx candor-ui add terms` `` props: - `terms: Partial`: The words to use; any left out fall back to the ones above. - `children: React.ReactNode` ### type-to-confirm (Pro) A step that can't be undone, confirmed by typing a name: "Type prod-eu to confirm." The action stays locked, and says why, until the text matches exactly (spaces at either end don't count). Install: `npx candor-ui add type-to-confirm` `` props: - `phrase: string`: What the person types: an account, a project, an environment's name. - `action: string`: The action's label, as a verb: "Delete the account". - `onConfirm: () => void`: Called once the text matches and the action is pressed (or Enter is pressed in the box). - `onCancel?: (() => void) | undefined`: Shows Cancel, and is called when it's pressed or Escape is pressed in the box. - `children?: React.ReactNode | undefined`: What the step does and what it can't take back, in the app's words. Shown above the box. - `prompt?: React.ReactNode | undefined`: The box's label, in place of "Type {phrase} to confirm.". - `mismatch?: string | undefined`: Why the action is locked while the text doesn't match, in place of "Type {phrase} exactly.". - `matchCase?: boolean | undefined` (default `true`): Whether "PROD-EU" matches "prod-eu". On by default: the name is typed exactly. - `busy?: boolean | undefined` (default `false`): The step is running: the action shows it and can't be pressed again. - `locked?: string | undefined`: Why the viewer can't take this step at all, whatever they type. - `tone?: "destructive" | "default" | undefined` (default `"destructive"`): "destructive" (the default) for removal, "default" for a change that's serious but not a removal. - `className?: string | undefined` ## Primitives The shadcn/ui primitives Candor's components are built on. ### avatar (Pro) shadcn's avatar in Candor's theme. Install: `npx candor-ui add avatar` `` props: - `size?: "default" | "sm" | "lg" | undefined` (default `"default"`): 32px by default; sm is 24px, lg 40px. ### badge (Pro) shadcn's badge in Candor's theme. Install: `npx candor-ui add badge` `` props: - `asChild?: boolean | undefined`: Renders its child element with the badge's styles instead of a span. ### button (free) shadcn's button in Candor's theme, with a locked state for (dimmed, and says why). Install: `npx candor-ui add button` `