<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Candor UI changelog</title>
    <link>https://candor.themethodic.com/changelog</link>
    <description>What changed in each Candor UI release, newest first.</description>
    <language>en-GB</language>
    <lastBuildDate>Fri, 13 Nov 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://candor.themethodic.com/changelog.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Candor UI 5.2.0</title>
      <link>https://candor.themethodic.com/changelog#5-2-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#5-2-0</guid>
      <pubDate>Fri, 13 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 3.2.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 5.2.0. Nothing a 5.1 app passes stops working; code that reads one of the widened prop types (listed below) may need &lt;code&gt;?? undefined&lt;/code&gt;. The fixes 5.1's streams and reviews found: a Thread that stays at the newest message (Storywrite's A-61), names from the app that read the right way round, and links your router follows in the nav. One Pro item is new (&lt;code&gt;use-focus-within&lt;/code&gt;), so the kit has 408 items: 74 free and 377 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@3 update --to 5.2.0&lt;/code&gt; takes a 5.1 project to 5.2.0, with no codemod. If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 5.2.0, which carries the free fixes to &lt;code&gt;Thread&lt;/code&gt;, &lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;place()&lt;/code&gt;. The changes a 5.1 app sees, each with what to do:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Thread (free) stays at the newest message while its content lays out&lt;/strong&gt; (KIT-295). Storywrite's A-61: &amp;quot;a Thread opened at its newest end stops following when its content grows just after the first draw&amp;quot;, about 57 px short of the bottom in about 1 open in 4 in Chromium. In 5.1 any fall in &lt;code&gt;scrollTop&lt;/code&gt; of more than 2 px unpinned the thread, and the browser's scroll anchoring makes one when content above the view changes size. In 5.2 the thread turns scroll anchoring off on its scroller while it follows (&lt;code&gt;overflow-anchor: none&lt;/code&gt;), and back on once the reader scrolls up, so their place is kept. A fall in &lt;code&gt;scrollTop&lt;/code&gt; counts as layout only up to how much the content's height, the view's height and the newest message's place changed since the last scroll or resize; the thread stays pinned and goes back to the bottom. Any larger fall is a scroll and unpins, while an agent streams too, whatever made it: a wheel, a touch, a key, the scrollbar, find in page, a screen reader, or your app through &lt;code&gt;scrollerRef&lt;/code&gt;, as in 5.1. &amp;quot;Jump to latest&amp;quot; shows whenever the view is short of the bottom, not only once the reader has scrolled up. Nothing to do.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The Pro items' &lt;code&gt;…Locked&lt;/code&gt; props and &lt;code&gt;locked&lt;/code&gt; maps, and Inbox's and ApprovalQueue's &lt;code&gt;defaultActiveId&lt;/code&gt;, accept &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; (KIT-282, KIT-291), as &lt;code&gt;locked&lt;/code&gt; does since 5.1. For a &lt;code&gt;…Locked&lt;/code&gt; prop or a &lt;code&gt;locked&lt;/code&gt; value, &lt;code&gt;null&lt;/code&gt; or left out is unlocked. For &lt;code&gt;defaultActiveId&lt;/code&gt;, only &lt;code&gt;null&lt;/code&gt; means &amp;quot;the list keeps the open row, with none at first&amp;quot;; left out, the list keeps no open row and marks none, as in 5.1. Code that passes them is unchanged. Code that reads one of these types into a &lt;code&gt;string | undefined&lt;/code&gt; (&lt;code&gt;ComponentProps&amp;lt;typeof Plan&amp;gt;[&amp;quot;acceptLocked&amp;quot;]&lt;/code&gt;) fails the type check: add &lt;code&gt;?? undefined&lt;/code&gt;. The props: - RunEstimate's &lt;code&gt;startLocked&lt;/code&gt;; PlanGate's &lt;code&gt;upgradeLocked&lt;/code&gt;; DataControls' &lt;code&gt;deleteAccountLocked&lt;/code&gt;, &lt;code&gt;deleteHistoryLocked&lt;/code&gt; and &lt;code&gt;exportLocked&lt;/code&gt;; SsoSetup's &lt;code&gt;enforceLocked&lt;/code&gt;; AgentScreen's &lt;code&gt;takeOverLocked&lt;/code&gt;; Plan's &lt;code&gt;acceptLocked&lt;/code&gt;. - AccountState's &lt;code&gt;actions[].locked&lt;/code&gt;. - The values of the &lt;code&gt;locked&lt;/code&gt; maps on ArtifactToolbar, RestoreDialog, ReviewLadder and NotificationPreferences. - Inbox's and ApprovalQueue's &lt;code&gt;defaultActiveId&lt;/code&gt;. Their &lt;code&gt;selected&lt;/code&gt; behaves as in 5.1.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ApprovalQueue's (Pro) requester tile&lt;/strong&gt; draws the name's first letter upper-cased, as a whole character, through the new &lt;code&gt;initialOf&lt;/code&gt; in &lt;code&gt;initials&lt;/code&gt; (KIT-285): an emoji or an Adlam letter is no longer cut in half, and a name that starts lower-case shows its capital. The tile still holds one letter.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ScopeBreadcrumb (Pro)&lt;/strong&gt;: a linked crumb opened with Ctrl, Cmd, Shift or Alt, or the middle button, follows the link and doesn't call &lt;code&gt;onChange&lt;/code&gt;, as ScopeSwitcher's option does since 5.1 (KIT-269). A plain click calls &lt;code&gt;onChange&lt;/code&gt;, as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AppSidebar, NavRail and TabBar (Pro) draw their in-app places through the app's link&lt;/strong&gt; (&lt;code&gt;LinkProvider&lt;/code&gt;, or &lt;code&gt;CandorProvider&lt;/code&gt;'s &lt;code&gt;link&lt;/code&gt;), so your router's link handles them (KIT-268). With none set each draws the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; it drew in 5.1. A plain click with &lt;code&gt;onNavigate&lt;/code&gt; given calls it and the link doesn't navigate, as in 5.1; without &lt;code&gt;onNavigate&lt;/code&gt;, your link navigates.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Translators: these keys are new. Until you translate them, each says its English words.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;calendar.gridName&lt;/code&gt; (&amp;quot;{label}, {month}&amp;quot;), Calendar's grid name, which 5.1 joined with a typed &amp;quot;, &amp;quot; (KIT-271). The keys it read in 5.1 are still read, as its placeholders.&lt;/li&gt;&lt;li&gt;&lt;code&gt;themeSetting.using&lt;/code&gt; (&amp;quot;Using {theme}&amp;quot;): with &lt;code&gt;choices&lt;/code&gt;, a stored theme that isn't among them leaves the trigger reading &amp;quot;Choose a theme&amp;quot;, and its description names the theme in force (KIT-292).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some DOM your own CSS or tests may match has changed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Names from the app drawn inside Candor's words&lt;/strong&gt; have their direction controls marked, listed below; where the text read the same, it still does. DetailsList's row label is in a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt; inside its &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt;; ScoreRing's &lt;code&gt;delta.vs&lt;/code&gt;, &lt;code&gt;projection.basis&lt;/code&gt; and &lt;code&gt;basis&lt;/code&gt; and StatCard's &lt;code&gt;delta.vs&lt;/code&gt; are each in a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Thread (free)&lt;/strong&gt;: while it follows the newest message, its scroller has &lt;code&gt;overflow-anchor: none&lt;/code&gt; as an inline style, which overrides an &lt;code&gt;overflow-anchor&lt;/code&gt; your CSS sets there; it has none while the reader is scrolled up.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ThemeSetting (Pro)&lt;/strong&gt;: with a stored theme outside &lt;code&gt;choices&lt;/code&gt;, the trigger has &lt;code&gt;aria-describedby&lt;/code&gt; pointing at a hidden element with the &lt;code&gt;themeSetting.using&lt;/code&gt; words.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ColumnMapper (Pro)&lt;/strong&gt;: the gap after a field's icon is a layout gap, not a typed space, so the text has no leading space (KIT-274).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Corrected in the 5.1.0 notes&lt;/h3&gt;&lt;p&gt;The 5.1.0 section below is left as it was released.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;locked&lt;/code&gt; accepts &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; on every &lt;code&gt;locked&lt;/code&gt; prop, not on every item: in 5.1.0 the &lt;code&gt;…Locked&lt;/code&gt; props (&lt;code&gt;acceptLocked&lt;/code&gt;, &lt;code&gt;startLocked&lt;/code&gt;, &lt;code&gt;upgradeLocked&lt;/code&gt; …), AccountState's &lt;code&gt;actions[].locked&lt;/code&gt; and the record-typed &lt;code&gt;locked&lt;/code&gt; maps still take &lt;code&gt;string | undefined&lt;/code&gt; (KIT-282). 5.2 widens them, listed above.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The widened types break code that reads a prop's type&lt;/strong&gt;, not only the six data types: &lt;code&gt;ComponentProps&amp;lt;typeof ConfirmButton&amp;gt;[&amp;quot;locked&amp;quot;]&lt;/code&gt; read into a &lt;code&gt;string | undefined&lt;/code&gt; needs &lt;code&gt;?? undefined&lt;/code&gt;, and Tree's two-parameter &lt;code&gt;onSelect&lt;/code&gt; fails where a wrapper types it as &lt;code&gt;(id: string) =&amp;gt; void&lt;/code&gt; through &lt;code&gt;ComponentProps&amp;lt;typeof Tree&amp;gt;&lt;/code&gt; (KIT-283).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; under the app's &lt;code&gt;TooltipProvider&lt;/code&gt;&lt;/strong&gt; opens its reason after the app's &lt;code&gt;delay&lt;/code&gt; on hover, where 5.0's own provider gave none; only moving between locked controls inside the delay group skips it (KIT-289).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;use-focus-within&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;useFocusWithin&lt;/code&gt; and its &lt;code&gt;FocusWithin&lt;/code&gt; type (KIT-276). It tracks whether focus is inside an element, so an item moves focus only when focus is in it, or on its control that was just removed, and announces otherwise; a target held for the next render is dropped once the person moves focus out. Focus already inside when it mounts (a control's &lt;code&gt;autoFocus&lt;/code&gt;) counts. NeedsYouLine, ModelKey, DriftChange, EnvironmentConnect and IntegrationConnect use it in place of their own checks; NeedsYouLine now keeps focus for any control in the line, not only Retry.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;Names from the app, a model or another person (KIT-266, KIT-267, KIT-277, KIT-284): drawn inside Candor's words or in an accessible name, their direction controls are neutralised, so a name can't turn the sentence round it. Message (free): the author's and agent's names in its &lt;code&gt;aria-label&lt;/code&gt;. Shell and agents: DockWindow's title (Float, Go to window, Bring back, Move and the floating line), MembersTable's environments in &lt;code&gt;roleOn&lt;/code&gt;. Data, reports, charts and evals: Tree, ReconcileTable, DataTable (its stacked name, &lt;code&gt;agentPending&lt;/code&gt; and &lt;code&gt;agentInputs&lt;/code&gt;), RunEstimate, EvalScorecard, SubscoreCard, ScoreRing, StatCard, ReportSheet, DetailsList, BoardCard, ReorderableList, ColumnMapper, DataImport, ImportReview, and the select hint of BarChart, LineChart, DonutChart and Heatmap. Work, collaboration, knowledge, admin and billing: ApprovalRequest, Plan, ShipReview, RunRecovery, ExtractionReview, InlineSuggestion, CodeListing, CodeEditor, CompareSlider, DocumentViewer, DocumentProgressQueue, AgentScreen, EnvironmentPromotion, HoldToConfirm, Proposal, RestoreDialog, RunHeartbeat, SteerComposer, UndoWindow, WorkflowEditor, AccessRequest, CommentThread, Escalation, HandoffCard, Presence, RaciChips, Diagram, ConfidenceMark, KnowledgeSources, MemoryManager, MemoryMode, MemoryUsed, ApiKeys, DataControls, DeviceSessions, ScheduleList, Webhooks, EnvironmentConnect, IntegrationConnect, SsoSetup, SetupChecklist, StepUpDialog, ProfileSettings, PlanGate, PlanPicker, DowngradeImpact and SubscriptionStatus.&lt;/p&gt;&lt;p&gt;The rest, by item:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Dialog, DropdownMenu, AlertDialog, MaskedInput, FloatLabelInput, Command and TabsList merge your ref with their own through &lt;code&gt;useMergedRefs&lt;/code&gt;, as Tabs does since 5.1: an object ref and a callback ref both get the element, and a new callback ref takes over from the old one, where TabsList kept the first ref an app passed (KIT-265).&lt;/li&gt;&lt;li&gt;RunEstimate and ScheduleEditor read the clock after they mount, never while they render, so a Next 16 prerender with &lt;code&gt;cacheComponents&lt;/code&gt; no longer fails on an unstable value (KIT-298). The server's HTML has no time left on RunEstimate and no next runs on ScheduleEditor; both appear once the page has mounted, before it paints, as RunEstimate's time left and ScheduleEditor's runs already did after hydration.&lt;/li&gt;&lt;li&gt;SheetContent: a sheet opened from another gives the outer sheet's width back when it closes, where 5.1 removed &lt;code&gt;--cd-sheet-width&lt;/code&gt; and the push drawing fell back to &lt;code&gt;min(75vw, 24rem)&lt;/code&gt; (KIT-290).&lt;/li&gt;&lt;li&gt;The Premium templates' server stores type no &amp;quot; · &amp;quot; into the labels they build: the approvals inbox names the customer in a refund's title, and the support copilot's store returns the parts its pages join with the locale's separator (KIT-275).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 5.2.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Thread stays at the newest message while its content lays out, and &amp;quot;Jump to latest&amp;quot; shows whenever the view is short of the bottom (KIT-295, above).&lt;/li&gt;&lt;li&gt;Message marks the direction controls in the names in its &lt;code&gt;aria-label&lt;/code&gt; (KIT-277).&lt;/li&gt;&lt;li&gt;&lt;code&gt;place()&lt;/code&gt; (&lt;code&gt;locale&lt;/code&gt;) reads only a placeholder the nodes hold themselves, so a translation holding &lt;code&gt;{constructor}&lt;/code&gt; or &lt;code&gt;{toString}&lt;/code&gt; draws it as written, where 5.1 drew a function and threw (KIT-286).&lt;/li&gt;&lt;li&gt;&lt;code&gt;mcpInputView&lt;/code&gt; and &lt;code&gt;mcpInputResponses&lt;/code&gt; (&lt;code&gt;mcp-input&lt;/code&gt;) fill a placeholder in their words only from the values they were given, so a translation holding &lt;code&gt;{constructor}&lt;/code&gt; or &lt;code&gt;{toString}&lt;/code&gt; draws it as written, where 5.1 drew a function's source (KIT-297).&lt;/li&gt;&lt;li&gt;&lt;code&gt;Locked&lt;/code&gt;'s doc says when its reason opens: under the app's &lt;code&gt;TooltipProvider&lt;/code&gt;, on hover after that provider's delay; with none, at once; on a press, at once (KIT-289).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Nothing to do.&lt;/p&gt;&lt;h3&gt;CLI 3.2.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; says when &lt;code&gt;package.json&lt;/code&gt; lists a package below an updated item's new range, with the command to install it, and leaves &lt;code&gt;package.json&lt;/code&gt; as it is (&amp;quot;lucide-react has ^1.60.0 in package.json; thread 5.2.0 needs ^1.67.0. Run &lt;code&gt;npm install lucide-react@^1.67.0&lt;/code&gt;.&amp;quot;). A package inside or above the range gets no line, and one that two items name is named once, at the higher range. A &lt;code&gt;workspace:&lt;/code&gt; or &lt;code&gt;file:&lt;/code&gt; specifier is named as not compared (CLI-45).&lt;/li&gt;&lt;li&gt;Every command &lt;code&gt;migrate&lt;/code&gt; and &lt;code&gt;theme&lt;/code&gt; print, and the &lt;code&gt;theme&lt;/code&gt; usage line, names &lt;code&gt;npx candor-ui@3&lt;/code&gt;: &lt;code&gt;migrate&lt;/code&gt;'s &amp;quot;Not run&amp;quot; line, usage, &lt;code&gt;strings-keys&lt;/code&gt;' line on a spread and its pointers to &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt;; &lt;code&gt;theme check&lt;/code&gt;'s fix for a renamed token, its file and motion hints and its pointers to &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;init&lt;/code&gt;; &lt;code&gt;theme apply&lt;/code&gt;'s and &lt;code&gt;theme from&lt;/code&gt;'s lines, so a project with &lt;code&gt;candor-ui@2&lt;/code&gt; installed doesn't run CLI 2 (CLI-43).&lt;/li&gt;&lt;li&gt;The new string keys &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;migrate strings-keys&lt;/code&gt; list count a key renamed inside a namespace as moved, not new (CLI-46).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The docs MCP's &lt;code&gt;theme_check&lt;/code&gt; names &lt;code&gt;npx candor-ui@3 migrate tokens&lt;/code&gt; for a renamed token (CLI-43).&lt;/li&gt;&lt;li&gt;SubscoreCard's doc names &lt;code&gt;FindingData&lt;/code&gt; (KIT-272). DocumentViewer's example shows &lt;code&gt;defaultSelected&lt;/code&gt; and RestoreDialog's shows &lt;code&gt;defaultOpen&lt;/code&gt; (KIT-273). Thread's &lt;code&gt;scrollerRef&lt;/code&gt; doc says scrolling it up stops the thread following.&lt;/li&gt;&lt;li&gt;The upgrade page's 4.0 command names &lt;code&gt;npx candor-ui@2 update --to 4.0.0&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For maintainers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;release:check&lt;/code&gt; runs an upgrade check from 5.0.0 and from 5.1.0 to this version, on the 5.x fixture (&lt;code&gt;tests/upgrade/5.0&lt;/code&gt; and its &lt;code&gt;also&lt;/code&gt;), and runs &lt;code&gt;migrate&lt;/code&gt; only when a breaking entry is crossed (CLI-44). The 4.5 and 5.x steps run within 5.x; at another major one step fails and says where to add that major's upgrade steps.&lt;/li&gt;&lt;li&gt;&lt;code&gt;check:motion&lt;/code&gt;: the calm/none rule needs &lt;code&gt;[data-motion=&amp;quot;calm&amp;quot;]&lt;/code&gt; and &lt;code&gt;[data-motion=&amp;quot;none&amp;quot;]&lt;/code&gt;, and their descendants, in a &lt;code&gt;:not(…)&lt;/code&gt;, each compared whole (MOT-66); a negated container query doesn't allow a loop (MOT-67); an &lt;code&gt;@ease&lt;/code&gt; value it can't read fails on either line (MOT-68); a loop needs its running state on every selector of a list.&lt;/li&gt;&lt;li&gt;&lt;code&gt;layers.mjs&lt;/code&gt; fails for an engine named in &lt;code&gt;CANDOR_LAYER_BROWSERS&lt;/code&gt; or &lt;code&gt;--browsers&lt;/code&gt; that doesn't start; one of the default three that won't start here is still skipped with a line, and on CI any fails (KIT-287).&lt;/li&gt;&lt;li&gt;&lt;code&gt;candorItemsOf&lt;/code&gt; (&lt;code&gt;scripts/page-items.mjs&lt;/code&gt;) reads imports from the syntax tree, so a path in a comment or a string isn't listed (KIT-288).&lt;/li&gt;&lt;li&gt;A kit test checks that every &lt;code&gt;data-slot&lt;/code&gt; an item draws is in the token manifest (KIT-280).&lt;/li&gt;&lt;li&gt;&lt;code&gt;tests/browser/thread-follow.mjs&lt;/code&gt; opens a thread 20 times in Chromium with A-61's late change and checks each ends at the bottom, and that PageUp with focus on &lt;code&gt;body&lt;/code&gt;, a text fragment (find in page's scroll) and &lt;code&gt;scrollIntoView&lt;/code&gt; unpin it, with no streaming and while a token arrives every 30 ms; &lt;code&gt;npm run test:browser&lt;/code&gt; runs it after the hosted demos.&lt;/li&gt;&lt;li&gt;The OrgSmith pack's &lt;code&gt;package.json&lt;/code&gt; and a committed &lt;code&gt;package-lock.json&lt;/code&gt; list the packages its Candor items import, and &lt;code&gt;npm run candor&lt;/code&gt; puts both files back after &lt;code&gt;add&lt;/code&gt;, so a later &lt;code&gt;npm install&lt;/code&gt; keeps them (ARCH-39).&lt;/li&gt;&lt;li&gt;The short real-time sleeps left in the tests wait on fake timers (HK-9), and tests that type a bidi control use a &lt;code&gt;\u&lt;/code&gt; escape (HK-10).&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 5.1.0</title>
      <link>https://candor.themethodic.com/changelog#5-1-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#5-1-0</guid>
      <pubDate>Fri, 13 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 3.1.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 5.1.0; nothing breaks a 5.0 project. The fixes 5.0 held back so its breaks could be read on their own: focus that stays put, links your router follows, locked controls that say why, and text that isn't joined in code. Six Pro items are new (&lt;code&gt;link&lt;/code&gt;, &lt;code&gt;merge-refs&lt;/code&gt;, &lt;code&gt;use-settle&lt;/code&gt;, &lt;code&gt;live-rows&lt;/code&gt;, &lt;code&gt;email-heading&lt;/code&gt; and &lt;code&gt;user-message-actions&lt;/code&gt;), so the kit has 407 items: 74 free and 376 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@3 update --to 5.1.0&lt;/code&gt; takes a 5.0 project to 5.1.0, with no codemod. If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 5.1.0, which carries the free fixes to &lt;code&gt;Locked&lt;/code&gt;, &lt;code&gt;Tooltip&lt;/code&gt;, &lt;code&gt;ToolCall&lt;/code&gt;, &lt;code&gt;Composer&lt;/code&gt; and &lt;code&gt;Progress&lt;/code&gt;. The changes a 5.0 app sees, each with what to do:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Inbox and ApprovalQueue (Pro) keep their own selection&lt;/strong&gt; when you pass &lt;code&gt;onSelectedChange&lt;/code&gt; without &lt;code&gt;selected&lt;/code&gt;: a ticked item shows ticked, and the callback is still called. In 5.0 the tick never showed. Pass &lt;code&gt;selected&lt;/code&gt; to hold the selection yourself: once you have passed it, the list keeps none of its own, so clearing it to &lt;code&gt;undefined&lt;/code&gt; draws none, as in 5.0.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ConfirmButton (Pro) stays armed for 6 seconds by default&lt;/strong&gt; in English (4 in 5.0): left out, &lt;code&gt;armedFor&lt;/code&gt; is long enough to hear the armed announcement at a slow screen-reader rate and then press again, in whole seconds and never under 4, and the announcement says how long. Pass &lt;code&gt;armedFor={4000}&lt;/code&gt; to keep 5.0's window; a test that waited 4 seconds for it to disarm waits for the new window or sets &lt;code&gt;armedFor&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Six data types' &lt;code&gt;locked&lt;/code&gt; field accepts &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;string | null | undefined&lt;/code&gt;): &lt;code&gt;PaletteItem&lt;/code&gt;, &lt;code&gt;ScopeLevel&lt;/code&gt;, &lt;code&gt;SettingsItem&lt;/code&gt;, &lt;code&gt;DashboardTileView&lt;/code&gt;, &lt;code&gt;PermissionModeOption&lt;/code&gt; and &lt;code&gt;PlanAutonomyOption&lt;/code&gt;. Code that builds them is unchanged; code that reads one into a &lt;code&gt;string | undefined&lt;/code&gt; variable fails the type check: add &lt;code&gt;?? undefined&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inside a &lt;code&gt;HeadingScope&lt;/code&gt;, some headings sit one level below it&lt;/strong&gt;, as 5.0's rule says, where 5.0 ignored the scope: the loading, empty and error heading of Inbox, SessionList, NotificationCenter, AgentRoster, ApprovalQueue, TraceViewer, EvalScorecard, MembersTable, AuditLog and ResultTable; A2uiSurface's model headings; EmailPreview's title; and AccessRequest's title, a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; in 5.0, which is a heading inside a scope or with its new &lt;code&gt;headingLevel&lt;/code&gt;. Outside a scope each draws what it drew in 5.0 (&lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;; A2uiSurface's levels; EmailPreview's &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;; AccessRequest's &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;). A test that found one of them by level inside a scope looks one below the scope, or passes &lt;code&gt;headingLevel&lt;/code&gt;; a test that found AccessRequest's title as text inside a scope finds it by role &lt;code&gt;heading&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A stacked Carousel (Pro) changes slide on a finger or pen swipe only:&lt;/strong&gt; a mouse drag over a slide selects its text. The slide change a person makes is announced (&amp;quot;2 of 3&amp;quot;, &lt;code&gt;carousel.slideOf&lt;/code&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Translators: these keys are new. Until you translate them, each says its English words.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;graphView.putBack&lt;/code&gt;; &lt;code&gt;modelKey.saving&lt;/code&gt;; &lt;code&gt;dockWindow.goToWindow&lt;/code&gt; and &lt;code&gt;goToWindowTitle&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;board.unplaced&lt;/code&gt; (one and other) and &lt;code&gt;board.columns&lt;/code&gt;; &lt;code&gt;dataTable.sortCleared&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;usageMeters.amount&lt;/code&gt;, &lt;code&gt;usedOfLimit&lt;/code&gt;, &lt;code&gt;limitAfter&lt;/code&gt;, &lt;code&gt;unitAfter&lt;/code&gt; and &lt;code&gt;withPending&lt;/code&gt;. The keys UsageMeters read in 5.0 are still read.&lt;/li&gt;&lt;li&gt;&lt;code&gt;runTree.readoutStatus&lt;/code&gt; and &lt;code&gt;readoutJoin&lt;/code&gt;. &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;after&lt;/code&gt; and &lt;code&gt;verdictNote&lt;/code&gt; are still read, as their placeholders.&lt;/li&gt;&lt;li&gt;The Premium templates' strings that held &amp;quot; · &amp;quot; (&lt;code&gt;agentOpsConsole.topLine&lt;/code&gt; and &lt;code&gt;topLineStopped&lt;/code&gt;, &lt;code&gt;approvalsInbox.owner&lt;/code&gt;, &lt;code&gt;member&lt;/code&gt;, &lt;code&gt;ruleHeading&lt;/code&gt;, &lt;code&gt;waitingLine&lt;/code&gt; and &lt;code&gt;requestDescription&lt;/code&gt;, &lt;code&gt;supportCopilot.threadCustomerLine&lt;/code&gt; and &lt;code&gt;draftCardHeader&lt;/code&gt;) take &lt;code&gt;{separator}&lt;/code&gt;, the locale's separator, in its place; &lt;code&gt;agentOpsConsole.startedBy&lt;/code&gt; and &lt;code&gt;approvalsInbox.appliedBy&lt;/code&gt; no longer hold it, since the template joins them. An override that kept its own &amp;quot; · &amp;quot; in &lt;code&gt;startedBy&lt;/code&gt; or &lt;code&gt;appliedBy&lt;/code&gt; shows it twice: take it out.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some DOM your own CSS or tests may match has changed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;FilterChips (Pro)&lt;/strong&gt;: a chip's label and its value are each in their own &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Board (Pro)&lt;/strong&gt;: the scrolling region keeps the board's &lt;code&gt;label&lt;/code&gt; and the group of columns inside it is named &amp;quot;Columns of {label}&amp;quot;; the region's description says how many cards are in no column.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;EmailPreview (Pro)&lt;/strong&gt;: the title carries &lt;code&gt;data-slot=&amp;quot;email-heading&amp;quot;&lt;/code&gt;, drawn by the new &lt;code&gt;email-heading&lt;/code&gt; part.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SheetContent (Pro)&lt;/strong&gt; carries &lt;code&gt;data-edge&lt;/code&gt; (&lt;code&gt;top&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;bottom&lt;/code&gt; or &lt;code&gt;left&lt;/code&gt;, flipped for RTL).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CardDeck (Pro)&lt;/strong&gt;: the hint is clipped while hidden, not &lt;code&gt;invisible&lt;/code&gt;, so a screen reader's browse mode finds it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inbox and ApprovalQueue (Pro)&lt;/strong&gt;: the rows' list carries &lt;code&gt;data-slot=&amp;quot;live-rows&amp;quot;&lt;/code&gt;, drawn by the new &lt;code&gt;live-rows&lt;/code&gt; part.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A stacked Carousel (Pro)&lt;/strong&gt;: the slides' row is &lt;code&gt;aria-live=&amp;quot;off&amp;quot;&lt;/code&gt; (&lt;code&gt;&amp;quot;polite&amp;quot;&lt;/code&gt; in 5.0), and &lt;code&gt;CarouselStatus&lt;/code&gt; has no &lt;code&gt;aria-live&lt;/code&gt;, since the carousel says a slide change the person makes once itself, through Candor's announcer. A test that asserted either live region checks the status's text, or the announcement, instead. A sliding carousel's are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ToolCall and SearchTrace&lt;/strong&gt;: a row that finishes with nothing to show while focus is on it keeps its locked button until focus leaves; then it is text, as in 5.0.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Corrected in the 5.0 upgrade notes&lt;/h3&gt;&lt;p&gt;&lt;code&gt;scripts/breaking.json&lt;/code&gt;'s 5.0.0 entries, the [Upgrading to 5.0](https://candor.themethodic.com/upgrading-to-5) page and what &lt;code&gt;update&lt;/code&gt; prints going to 5.1.0 or later say these now. &lt;code&gt;update --to 5.0.0&lt;/code&gt; reads the 5.0.0 snapshot, frozen as released, so it prints the old text; the page says so. The 5.0.0 section below is left as it was released.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;heading-default&lt;/code&gt;&lt;/strong&gt; (CLI-36): the free PermissionPrompt draws &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; by default since 5.0 and reads no &lt;code&gt;HeadingScope&lt;/code&gt;: pass &lt;code&gt;headingLevel={3}&lt;/code&gt; to keep 4.x's &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;. &lt;code&gt;HeadingScope&lt;/code&gt; is named as Pro.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;strings-separator&lt;/code&gt;&lt;/strong&gt; (CLI-34): &lt;code&gt;Formatter&lt;/code&gt; has two new members, &lt;code&gt;separator&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt;, so an object you build as a &lt;code&gt;Formatter&lt;/code&gt; yourself (a test double for &lt;code&gt;useFormat&lt;/code&gt;) fails the type check until it adds them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;locked-not-disabled&lt;/code&gt;&lt;/strong&gt; (CLI-40): the reasons the waiting controls give are 50 new &lt;code&gt;locked…&lt;/code&gt; keys, on 31 items, which a translated app says in English until it translates them; the entry lists them. &lt;code&gt;strings-sentences&lt;/code&gt;' list of new keys adds &lt;code&gt;clarifyingQuestions.before&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-active-id-nav&lt;/code&gt;&lt;/strong&gt; (CLI-35): its search finds SettingsLayout's &lt;code&gt;active=&lt;/code&gt; too.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The migration lines&lt;/strong&gt; of the ten entries with a codemod name &lt;code&gt;npx candor-ui@3 migrate&lt;/code&gt;, as the codemod lines do, so a project with &lt;code&gt;candor-ui@2&lt;/code&gt; installed doesn't run CLI 2 (CLI-37).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;link&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;LinkProvider&lt;/code&gt;, &lt;code&gt;useLink&lt;/code&gt;, &lt;code&gt;LinkRender&lt;/code&gt; and &lt;code&gt;LinkRenderProps&lt;/code&gt;. Set how Candor's items draw an address in the app (a Next or TanStack &lt;code&gt;Link&lt;/code&gt;) once, or through &lt;code&gt;CandorProvider&lt;/code&gt;'s new &lt;code&gt;link&lt;/code&gt; prop, and SessionList, ScopeBreadcrumb, ScopeSwitcher, PersonMenu (Help), NotificationCenter, NeedsYouLine, ScoreRing, PortfolioCard, DetailsList and BoardCard draw their in-app links with your router. With none set each draws the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; it drew in 5.0. Downloads and links to other sites stay &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;merge-refs&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;mergeRefs&lt;/code&gt; and &lt;code&gt;useMergedRefs&lt;/code&gt;, one callback ref from an app's ref and an item's own. Tabs uses it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;use-settle&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;useSettle&lt;/code&gt;, which calls back once a value has stopped changing for a set time. PlanPicker and ScheduleEditor use it, with their 5.0 timings.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;live-rows&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;LiveRows&lt;/code&gt;, the rows of a list whose data changes under the person, as Inbox and ApprovalQueue draw them (both now draw through it; the rows' list gains &lt;code&gt;data-slot=&amp;quot;live-rows&amp;quot;&lt;/code&gt;, listed below).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;email-heading&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;EmailHeading&lt;/code&gt;, EmailPreview's title at the level the page's &lt;code&gt;HeadingScope&lt;/code&gt; gives it; a client part, so &lt;code&gt;EmailPreview&lt;/code&gt;, &lt;code&gt;EmailLayout&lt;/code&gt; and &lt;code&gt;renderEmail&lt;/code&gt; stay free of &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;user-message-actions&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;UserMessageActions&lt;/code&gt;, Copy and Edit and send again on the person's own message, placed in Message's &lt;code&gt;meta&lt;/code&gt;. Edit hands the app the message's words through &lt;code&gt;onEdit&lt;/code&gt;; what the person sends is a new message, and this one stays in the thread, so the app keeps the versions. Copy appears when &lt;code&gt;text&lt;/code&gt; is given, and Edit when both &lt;code&gt;text&lt;/code&gt; and &lt;code&gt;onEdit&lt;/code&gt; are.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;New, additive props (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;ThemeSetting&lt;/strong&gt;: &lt;code&gt;choices&lt;/code&gt;, the looks to offer, all four by default; &lt;code&gt;choices={[&amp;quot;system&amp;quot;, &amp;quot;light&amp;quot;, &amp;quot;dark&amp;quot;]}&lt;/code&gt; leaves out High contrast. A stored value outside the list shows as nothing chosen.&lt;/li&gt;&lt;li&gt;&lt;code&gt;defaultActiveId&lt;/code&gt; on SessionList, SidePanel, AppSidebar, TabBar, NavRail, AgentRoster, Inbox, ApprovalQueue, Plan, RunTree, VersionHistory, GraphView and Tree; &lt;code&gt;defaultSelected&lt;/code&gt; on DataTable, DocumentViewer and the four charts; &lt;code&gt;defaultOpen&lt;/code&gt; on RestoreDialog and ReportReply (KIT-236). Where the item had no state of its own, it keeps one only when the default is given; an item given neither draws as in 5.0, except Inbox and ApprovalQueue, listed above. An app that holds the selection itself, with &lt;code&gt;undefined&lt;/code&gt; as none, sees none when it clears it. A chart's &lt;code&gt;defaultSelected&lt;/code&gt; and Tree's &lt;code&gt;defaultActiveId&lt;/code&gt; take &lt;code&gt;null&lt;/code&gt; to keep the selection with none at first. DataTable keeps its own selection without &lt;code&gt;onSelectedChange&lt;/code&gt;, as in 5.0; with &lt;code&gt;onSelectedChange&lt;/code&gt; and no &lt;code&gt;selected&lt;/code&gt;, pass &lt;code&gt;defaultSelected&lt;/code&gt; (an empty &lt;code&gt;Set&lt;/code&gt; for none) to have it tick the rows a person selects.&lt;/li&gt;&lt;li&gt;Inbox takes &lt;code&gt;activeId&lt;/code&gt; and marks the item open beside it (KIT-234).&lt;/li&gt;&lt;li&gt;AccessRequest takes &lt;code&gt;headingLevel&lt;/code&gt; (KIT-252). &lt;code&gt;useHeadingScope()&lt;/code&gt;, from &lt;code&gt;heading-scope&lt;/code&gt;, gives the nearest &lt;code&gt;HeadingScope&lt;/code&gt;'s level, or &lt;code&gt;undefined&lt;/code&gt; outside one.&lt;/li&gt;&lt;li&gt;DataTable: a column with &lt;code&gt;sortable: false&lt;/code&gt; has no sort button, no &lt;code&gt;aria-sort&lt;/code&gt; and no place in the stacked sort control (KIT-221).&lt;/li&gt;&lt;li&gt;Tree's &lt;code&gt;onSelect&lt;/code&gt; passes the node as its second argument, as the tree drew it, loaded children included; &lt;code&gt;onSelect={(id) =&amp;gt; …}&lt;/code&gt; still type-checks (KIT-239).&lt;/li&gt;&lt;li&gt;TypedText takes &lt;code&gt;render&lt;/code&gt;, which wins over &lt;code&gt;as&lt;/code&gt; (KIT-238).&lt;/li&gt;&lt;li&gt;DateRangeField takes &lt;code&gt;name&lt;/code&gt; (hidden inputs &lt;code&gt;{name}.from&lt;/code&gt; and &lt;code&gt;{name}.to&lt;/code&gt;) and &lt;code&gt;error&lt;/code&gt;, as DateField does (KIT-190).&lt;/li&gt;&lt;li&gt;&lt;code&gt;navRailTabs&lt;/code&gt; takes the rail's &lt;code&gt;pinned&lt;/code&gt; places, so &lt;code&gt;more&lt;/code&gt; counts a pinned place left off the bar (KIT-167).&lt;/li&gt;&lt;li&gt;&lt;code&gt;locked&lt;/code&gt; accepts &lt;code&gt;null&lt;/code&gt; on every item, free ones (Slider) included; &lt;code&gt;null&lt;/code&gt; or left out is unlocked (KIT-189, KIT-237).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Focus that stays put (KIT-174, KIT-175, KIT-201, KIT-245, and others). An item moves focus only when focus is inside it, or on the control the person just used; a hold, a count or a check that arrives while the person is elsewhere is announced instead. EnvironmentConnect, IntegrationConnect, DriftChange, NeedsYouLine and ModelKey follow it. SessionList keeps focus on a row pinned in a virtualised list; SplitView keeps it when it narrows with the detail open; Toast passes on the key press after a swipe-dismiss; DataTable's stacked detail closes with focus back on the card's button; FilterChips' Clear all keeps focus in the bar (DataTable's search box); WorkflowEditor's keyboard Move ends, announced as put back, when focus goes nowhere; DockWindow's note in place has &amp;quot;Go to window&amp;quot;, the keyboard's way to the floating window.&lt;/p&gt;&lt;p&gt;Locked controls: ResultButton and ProgressButton show the reason on a tap or click, as other locked controls do (KIT-177). DataTable's column picker, FilterBar's Add button and CheckpointList's Restore keep their own alignment when nothing locks them (KIT-241). PermissionMode gives its busy reason once (KIT-210). The gallery's Save draft is locked with a reason, not &lt;code&gt;disabled&lt;/code&gt; (KIT-242).&lt;/p&gt;&lt;p&gt;Names from the app, a model or another person (KIT-187, KIT-255): drawn inside Candor's words or in an accessible name, their direction controls are neutralised and they are isolated in their own &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;: ThreadHeader, ModelPicker, FlipCard, Calendar, AiContentLabel, CopilotPanel, PersonMenu, ScopeSwitcher, AgentRoster, McpConnect, Inbox, ApprovalQueue, FilterChips, DataImport, ColumnMapper, CheckpointList, DocumentProgressQueue, ExtractionReview, CommentThread, AssigneePicker, MembersTable, TestResults, DriftChange and RunTree. PersonMenu's row form draws its initial through &lt;code&gt;initialsOf&lt;/code&gt; (KIT-219).&lt;/p&gt;&lt;p&gt;Text not joined in code: IntegrationConnect and EnvironmentConnect type no spaces round the separator (KIT-240); SsoSetup and InviteChooser join lists as the locale does (&amp;quot;Editor and Viewer&amp;quot;, KIT-249); UsageMeters' value text and RunTree's screen-reader sentence are keys with placeholders, numbers in the locale's digits (KIT-254, KIT-259); the Premium templates draw the locale's separator, not a typed &amp;quot; · &amp;quot; (KIT-256).&lt;/p&gt;&lt;p&gt;The rest, by item:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ModelKey says &amp;quot;Verified with {provider}, saving…&amp;quot; between a passed check and &lt;code&gt;stored&lt;/code&gt;, and its key field is a new password to the browser (&lt;code&gt;autoComplete=&amp;quot;new-password&amp;quot;&lt;/code&gt;) (KIT-160, KIT-191).&lt;/li&gt;&lt;li&gt;ScopeSwitcher: a linked option opened in a new tab or window doesn't call &lt;code&gt;onChange&lt;/code&gt;; a plain click calls it and follows the link (KIT-166). AppLayout's &lt;code&gt;hideHeader=&amp;quot;on-scroll&amp;quot;&lt;/code&gt; doc says any scroll inside &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; hides the banner (KIT-168).&lt;/li&gt;&lt;li&gt;Board says how many cards are in no column, and its region and group have different names (KIT-158, KIT-183).&lt;/li&gt;&lt;li&gt;DataTable: hiding the sorted column clears the sort in both forms and says so (KIT-200).&lt;/li&gt;&lt;li&gt;ColumnMapper: a suggestion with no confidence reads &amp;quot;Suggested&amp;quot; alone, with no percentage and no warning colour; the percentage is in the locale's digits (KIT-244).&lt;/li&gt;&lt;li&gt;RunScrubber's drag preview names the event under the pointer and stays inside the track (KIT-165). ChartFrame: a nested frame's caption no longer moves the plot while busy (KIT-185).&lt;/li&gt;&lt;li&gt;ToolCall draws no line counts for a negative or non-finite count, rather than &amp;quot;+0&amp;quot; (KIT-159). Composer's locked, empty box draws a focus ring of its own (KIT-247).&lt;/li&gt;&lt;li&gt;SliderStops reads a controlled value that is none of its stops (KIT-162); SearchInput drops a pending search when the app changes its value (KIT-163); DateField round-trips years under 1000 and reads Adlam digits (KIT-164); DrawerSwipeArea passes a tap on an icon to its button (KIT-178); FloatLabelInput lowers its label on &lt;code&gt;form.reset()&lt;/code&gt; (KIT-182); DialogBody pins the header and footer inside a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; (KIT-186); ConfirmField calls &lt;code&gt;onMatchChange(false)&lt;/code&gt; when it goes while a match stands (KIT-198); Tabs' refs are stable (KIT-215).&lt;/li&gt;&lt;li&gt;GraphView puts a node back where it was when it is let go far from every place, and says so; it scrolls when a pointer drag nears its edge; an arrow key pressed during the settle ends it, so the node moves from where it is drawn (KIT-197, KIT-222, MOT-53).&lt;/li&gt;&lt;li&gt;EnvironmentList clears &amp;quot;Disconnected&amp;quot; when the environment comes back (KIT-161). IntegrationConnect's doc says a &lt;code&gt;hold&lt;/code&gt; passed once connected is ignored (KIT-211). ScheduleEditor announces a change back to its first rule (KIT-184).&lt;/li&gt;&lt;li&gt;ProvenanceTrace's lines and LogStream's live dot carry their motion chain on the element that moves, so their own timings and a brand's values reach them (MOT-54, MOT-55). BarChart's plot carries &lt;code&gt;data-plot-dir=&amp;quot;ltr&amp;quot;&lt;/code&gt;, as LineChart's does (MOT-58).&lt;/li&gt;&lt;li&gt;The Premium templates compile under the React Compiler (ARCH-38).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 5.1.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Locked&lt;/code&gt; passes every key but Enter and Space (and ArrowUp and ArrowDown on a popup's trigger) to the control's own &lt;code&gt;onKeyDown&lt;/code&gt;, so a locked inline TypeToConfirm can still be cancelled with Escape (KIT-176).&lt;/li&gt;&lt;li&gt;&lt;code&gt;Locked&lt;/code&gt; under the app's &lt;code&gt;TooltipProvider&lt;/code&gt; joins its delay group, so moving between locked controls skips the delay (KIT-224). &lt;code&gt;useTooltipProviderAbove()&lt;/code&gt;, from &lt;code&gt;tooltip&lt;/code&gt;, says whether there is one; Locked uses it.&lt;/li&gt;&lt;li&gt;ToolCall: no counts for a negative or non-finite line count (KIT-159); a finished row keeps its locked button until focus leaves it (KIT-245). Composer: a locked, empty box draws a focus ring (KIT-247).&lt;/li&gt;&lt;li&gt;&lt;code&gt;locked&lt;/code&gt; accepts &lt;code&gt;null&lt;/code&gt; (Slider). PermissionPrompt's doc shows &lt;code&gt;headingLevel={3}&lt;/code&gt; inside a dialog (KIT-243).&lt;/li&gt;&lt;li&gt;Forced colours reach an indicator given to Progress as children (MOT-63).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Nothing to do.&lt;/p&gt;&lt;h3&gt;Motion (Pro &lt;code&gt;motion-drawings&lt;/code&gt;)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;SheetContent's push drawing finds the sheet's edge by &lt;code&gt;data-edge&lt;/code&gt; and pushes the page by the sheet's own width, with a Tailwind prefix and in RTL (MOT-50). A 5.0 sheet, which has no &lt;code&gt;data-edge&lt;/code&gt;, is still found by its side's class.&lt;/li&gt;&lt;li&gt;A dialog's, sheet's or drawer's nudge keeps its ring under a family-wide attention drawing (MOT-51).&lt;/li&gt;&lt;li&gt;The typing window on &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; and GlideHighlight's travel leave out &lt;code&gt;data-motion=&amp;quot;none&amp;quot;&lt;/code&gt; and calm (MOT-56, MOT-57).&lt;/li&gt;&lt;li&gt;The row-hover drawing on a &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt; is checked in WebKit (MOT-52).&lt;/li&gt;&lt;li&gt;With &lt;code&gt;expand&lt;/code&gt; and the ripple, an icon button's name isn't trapped under the next button (MOT-65).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 3.1.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;migrate constructor&lt;/code&gt;, &lt;code&gt;toString&lt;/code&gt; and &lt;code&gt;hasOwnProperty&lt;/code&gt; say there is no such codemod, as any unknown name does (CLI-39).&lt;/li&gt;&lt;li&gt;&lt;code&gt;update --differing keep&lt;/code&gt; keeps its copies by number inside &lt;code&gt;.candor-keep/&lt;/code&gt;, never outside it from a monorepo path; &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;doctor&lt;/code&gt; say when one is left behind (KIT-192).&lt;/li&gt;&lt;li&gt;Where it can't work out what installing an item's new dependencies writes, a plain &lt;code&gt;update&lt;/code&gt; no longer runs shadcn's dry run to list it; only &lt;code&gt;--differing&lt;/code&gt; does, since only it reads that list (KIT-225).&lt;/li&gt;&lt;li&gt;&lt;code&gt;types-data&lt;/code&gt; rewrites &lt;code&gt;export type { ToolCall as Call }&lt;/code&gt; to &lt;code&gt;ToolCallData as Call&lt;/code&gt;, and the other five types (CLI-38).&lt;/li&gt;&lt;li&gt;&lt;code&gt;strings-keys&lt;/code&gt; lists &lt;code&gt;standardCards&lt;/code&gt; inside &lt;code&gt;observer(…)&lt;/code&gt; or an app's own wrapper, rather than rewriting it into the wrong scope (CLI-42).&lt;/li&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; follows a monorepo theme moved out of the shared package and recorded (CLI-41).&lt;/li&gt;&lt;li&gt;The commands &lt;code&gt;update&lt;/code&gt; prints, and the upgrade page's, name &lt;code&gt;npx candor-ui@3&lt;/code&gt; (CLI-37).&lt;/li&gt;&lt;li&gt;&lt;code&gt;theme check&lt;/code&gt;: &lt;code&gt;motion-value&lt;/code&gt; doesn't say a keyframe-named value plays nothing where it plays (MOT-61).&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; leave a dependency's specifier alone when it already satisfies the item's range, so exact pins stay pinned.&lt;/li&gt;&lt;li&gt;Where the project's &lt;code&gt;utils&lt;/code&gt; alias already exports &lt;code&gt;cn&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; write no &lt;code&gt;lib/utils.ts&lt;/code&gt; and add no &lt;code&gt;cn&lt;/code&gt; package; the plan and &lt;code&gt;--dry-run&lt;/code&gt; name every npm package before anything is written.&lt;/li&gt;&lt;li&gt;&lt;code&gt;migrate headings&lt;/code&gt; lists &lt;code&gt;&amp;lt;AppLayout&amp;gt;&lt;/code&gt; only with &lt;code&gt;chat&lt;/code&gt;, and leaves out a heading whose 5.0 level is already what 4.x drew; &lt;code&gt;types-data&lt;/code&gt; writes &lt;code&gt;MessageData&lt;/code&gt;, not &lt;code&gt;MessageData as MessageData&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; and &lt;code&gt;migrate strings-keys&lt;/code&gt; print the string keys a release adds to your installed items, under &amp;quot;New strings to translate&amp;quot;, read from each item's strings table at both versions.&lt;/li&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; names npm packages the updated items no longer import and no other recorded item needs (&amp;quot;No longer needed: cmdk&amp;quot;); it removes nothing.&lt;/li&gt;&lt;li&gt;&lt;code&gt;--differing replace&lt;/code&gt; names every file it replaced, and its count matches its list.&lt;/li&gt;&lt;li&gt;A codemod says which files it didn't read (as installed, or from an older version), and &lt;code&gt;migrate --verbose&lt;/code&gt; lists them.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The docs MCP's &lt;code&gt;theme_check&lt;/code&gt; description names &lt;code&gt;motion-value&lt;/code&gt; (MOT-62).&lt;/li&gt;&lt;li&gt;PermissionPrompt's example shows &lt;code&gt;headingLevel={3}&lt;/code&gt; in a dialog (KIT-243); SemanticBadge's doc names &lt;code&gt;FindingData&lt;/code&gt; (KIT-257); LiveRows has an example.&lt;/li&gt;&lt;li&gt;Diagram's doc says that &lt;code&gt;mermaid&lt;/code&gt; loads only when &lt;code&gt;source&lt;/code&gt; is drawn, never for &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;edges&lt;/code&gt;, and that it is still installed with the item, since the registry has no optional dependencies. Nothing changed in how it loads: 5.0 already loaded &lt;code&gt;mermaid&lt;/code&gt; lazily, through &lt;code&gt;import()&lt;/code&gt;, and a test now holds it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For maintainers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;scripts/motion-baseline.json&lt;/code&gt;'s entries name a problem's place (&lt;code&gt;file&lt;/code&gt;, &lt;code&gt;at&lt;/code&gt;, &lt;code&gt;rule&lt;/code&gt;, and a &lt;code&gt;count&lt;/code&gt; where there are several), not its words, and &lt;code&gt;check:motion&lt;/code&gt; says which entry no longer matches (MOT-59). With 5.1's fixes it is empty. &lt;code&gt;check:motion&lt;/code&gt; strips a negated running state before it decides (MOT-60), and its &lt;code&gt;@ease&lt;/code&gt; check says a value it can't read can't be checked, not that it doesn't overshoot (MOT-64).&lt;/li&gt;&lt;li&gt;&lt;code&gt;release:check&lt;/code&gt; counts the tests from its one full run (ARCH-35).&lt;/li&gt;&lt;li&gt;The 4.5.0 upgrade check moves a theme and records it, then checks the move holds (CLI-41).&lt;/li&gt;&lt;li&gt;A kit suite checks the heading rule on every item that draws a heading, from &lt;code&gt;HEADING_LEFT&lt;/code&gt; (KIT-258).&lt;/li&gt;&lt;li&gt;The layer checks run Firefox locally too, skipping an engine that can't start with a line saying why; on CI it fails (KIT-213). Check M asserts the app's &lt;code&gt;popupClassName&lt;/code&gt; on the open menu (KIT-206); &lt;code&gt;contracts.mjs --list&lt;/code&gt; is tested and its header names every group (KIT-208, KIT-209); &lt;code&gt;fresh-app.mjs&lt;/code&gt; reads the Radix app's Candor items from the layer page's imports (KIT-212).&lt;/li&gt;&lt;li&gt;The OrgSmith pack installs through &lt;code&gt;candor-ui add&lt;/code&gt;, so &lt;code&gt;candor-lock.json&lt;/code&gt; is written, and its &lt;code&gt;.gitignore&lt;/code&gt; covers what the install writes (ARCH-36, ARCH-37).&lt;/li&gt;&lt;li&gt;Two test files wait on fake timers, not real time (HK-8).&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 5.0.0</title>
      <link>https://candor.themethodic.com/changelog#5-0-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#5-0-0</guid>
      <pubDate>Fri, 13 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A major release, with CLI 3.0.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 5.0.0: one heading outline, one name per idea, and strings a translation can reach. Every item that draws a heading takes &lt;code&gt;headingLevel&lt;/code&gt; (1 to 6) and, without it, draws one level below the nearest &lt;code&gt;HeadingScope&lt;/code&gt;, else &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, so a page's outline skips no level; dialogs, sheets, drawers, settings sections and dashboard tiles set the scope. The nav items' selected item is &lt;code&gt;activeId&lt;/code&gt;, Tree's and EnvironmentBand's &lt;code&gt;onSelect&lt;/code&gt; passes an id, and an accessible name is &lt;code&gt;label&lt;/code&gt;. The &amp;quot; · &amp;quot; between parts is one string, &lt;code&gt;locale.separator&lt;/code&gt;, and sentences that were joined in code are one string each with &lt;code&gt;{placeholders}&lt;/code&gt;. The six data types are &lt;code&gt;MessageData&lt;/code&gt;, &lt;code&gt;ToolCallData&lt;/code&gt; and so on, as &lt;code&gt;@candor-ui/react&lt;/code&gt; already named them, and the English exports kept for compatibility are gone. CLI 3.0 runs the upgrade (&lt;code&gt;npx candor-ui@3 update --to 5.0.0&lt;/code&gt;, then &lt;code&gt;npx candor-ui@3 migrate 5.0.0&lt;/code&gt;) and no longer takes a 3.x project, which keeps CLI 2. &lt;code&gt;heading-level&lt;/code&gt; and &lt;code&gt;heading-scope&lt;/code&gt; are new, so the kit has 401 items: 74 free and 370 in Pro.&lt;/p&gt;&lt;h3&gt;Upgrading from 4.x&lt;/h3&gt;&lt;p&gt;Start from a committed tree, so you can see what each step changed. Then, from the app's folder (the one with &lt;code&gt;components.json&lt;/code&gt;):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Look first:&lt;/strong&gt; &lt;code&gt;npx candor-ui@3 update --to 5.0.0 --dry-run&lt;/code&gt; prints what 5.0 changes for the items in &lt;code&gt;candor-lock.json&lt;/code&gt;, and writes nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;code&gt;npx candor-ui@3 update --to 5.0.0&lt;/code&gt; updates every item, merging your changes into Candor's as &lt;code&gt;update&lt;/code&gt; always has.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Migrate:&lt;/strong&gt; &lt;code&gt;npx candor-ui@3 migrate 5.0.0&lt;/code&gt; runs each of 5.0's codemods that an entry on your installed items names, in this order: &lt;code&gt;types-data&lt;/code&gt;, &lt;code&gt;props&lt;/code&gt;, &lt;code&gt;strings-keys&lt;/code&gt;, &lt;code&gt;headings&lt;/code&gt;. Each lists what it couldn't change under &amp;quot;Left for you&amp;quot;. &lt;code&gt;--dry-run&lt;/code&gt; shows it first.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Finish and check:&lt;/strong&gt; make the changes the &amp;quot;Left for you&amp;quot; lines name and those marked &amp;quot;by hand&amp;quot; below, then type-check (&lt;code&gt;npx tsc --noEmit&lt;/code&gt;) and build.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;code&gt;migrate&lt;/code&gt; parses your source with the project's TypeScript or, on TypeScript 7 (which has no JavaScript API) or with none, with the TypeScript 5 that CLI 3 brings, so there is nothing to install for the run. Strings you override are checked only where they are written as a &lt;code&gt;strings&lt;/code&gt; object Candor can see: on &lt;code&gt;LocaleProvider&lt;/code&gt; or &lt;code&gt;CandorProvider&lt;/code&gt;, in a &lt;code&gt;CandorConfig&lt;/code&gt;, or typed &lt;code&gt;StringOverrides&lt;/code&gt;. The type check doesn't find an override of a key 5.0 removes, since &lt;code&gt;StringOverrides&lt;/code&gt; takes any key: it still compiles and isn't read, so &lt;code&gt;migrate strings-keys&lt;/code&gt; is what moves or lists it.&lt;/p&gt;&lt;p&gt;Every change, by its id in &lt;code&gt;scripts/breaking.json&lt;/code&gt; (the same entries &lt;code&gt;update --to 5.0.0&lt;/code&gt; prints, and the [Upgrading to 5.0](https://candor.themethodic.com/upgrading-to-5) page lists):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;types-data&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;types-data&lt;/code&gt;): &lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;ToolCall&lt;/code&gt; (lib/candor/chat), &lt;code&gt;ApprovalRequest&lt;/code&gt; and &lt;code&gt;ResultTable&lt;/code&gt; (lib/candor/work), &lt;code&gt;Finding&lt;/code&gt; (lib/candor/data) and &lt;code&gt;RunReceipt&lt;/code&gt; (lib/candor/ops) are &lt;code&gt;MessageData&lt;/code&gt;, &lt;code&gt;ToolCallData&lt;/code&gt;, &lt;code&gt;ApprovalRequestData&lt;/code&gt;, &lt;code&gt;ResultTableData&lt;/code&gt;, &lt;code&gt;FindingData&lt;/code&gt; and &lt;code&gt;RunReceiptData&lt;/code&gt;, the names &lt;code&gt;@candor-ui/react&lt;/code&gt; already used. No alias is kept. The codemod renames each import and its uses; an import you aliased keeps your local name. Imports from &lt;code&gt;@candor-ui/react&lt;/code&gt; don't change.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;heading-default&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;headings&lt;/code&gt;, which lists): without &lt;code&gt;headingLevel&lt;/code&gt;, an item's top heading is one level below the nearest &lt;code&gt;HeadingScope&lt;/code&gt;, else &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, and its sub-headings sit below it. Most items that drew &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;h4&amp;gt;&lt;/code&gt; now draw &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; outside a scope; they look the same. DialogContent, SheetContent, DrawerContent, AlertDialogContent, SettingsSection, DashboardTile, ArtifactPanel, AppLayout's chat, a floating DockWindow, ReportSheet and ReportSection put their content in a scope, so a Candor item inside draws one level lower than before. ReportSheet's cover, a fixed &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; in 4.x, is &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;: pass &lt;code&gt;headingLevel={1}&lt;/code&gt; where a ReportSheet is the whole page. The free PermissionPrompt draws &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; (was &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;) and reads no scope. PageHeader stays &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, AccountState (a whole page) keeps its &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, EmailPreview keeps &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;, and RestoreDialog's &amp;quot;not undone&amp;quot; heading keeps &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;, under the dialog's &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; title. The codemod lists each use without &lt;code&gt;headingLevel&lt;/code&gt; with the level it drew in 4.x, and changes nothing: where a page or a test needs that level, pass &lt;code&gt;headingLevel={n}&lt;/code&gt;, or wrap a section in &lt;code&gt;&amp;lt;HeadingScope level={n}&amp;gt;&lt;/code&gt; (lib/candor/heading-scope).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;heading-level-type&lt;/code&gt;&lt;/strong&gt; (no codemod: nothing to change): &lt;code&gt;headingLevel&lt;/code&gt; is &lt;code&gt;HeadingLevel&lt;/code&gt; (1 to 6) on every item, where DataTable, ReorderableList, Board and BoardCard, NarrativeBlock, PortfolioCard, MonitorCard, DashboardTile and EnvironmentList took &lt;code&gt;2 | 3 | 4 | 5 | 6&lt;/code&gt;. A level you pass still type-checks. Where you type a level of your own, import &lt;code&gt;HeadingLevel&lt;/code&gt; from lib/candor/heading-level (&lt;code&gt;layout/heading&lt;/code&gt; still exports it).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-active-id-nav&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;): TabBar's and NavRail's &lt;code&gt;current&lt;/code&gt;, AppSidebar's &lt;code&gt;activeNav&lt;/code&gt; and SettingsLayout's &lt;code&gt;active&lt;/code&gt; are &lt;code&gt;activeId&lt;/code&gt;, with the same value. Stepper's, PlanPicker's and InlineSuggestion's &lt;code&gt;current&lt;/code&gt; mean something else and stay.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-label-name&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;): SettingsLayout's and DocumentViewer's &lt;code&gt;title&lt;/code&gt;, their accessible name, which isn't drawn, is &lt;code&gt;label&lt;/code&gt;; &lt;code&gt;title&lt;/code&gt; is Candor's word for a heading that is drawn.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-popup-class&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;): PersonMenu's and ScopeSwitcher's &lt;code&gt;layerClass&lt;/code&gt; prop, the classes for the menu's popup, is &lt;code&gt;popupClassName&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;on-select-id&lt;/code&gt;&lt;/strong&gt; (by hand): Tree's and EnvironmentBand's &lt;code&gt;onSelect&lt;/code&gt; passes the id of the node or environment, not the object. Write &lt;code&gt;onSelect={(id) =&amp;gt; …}&lt;/code&gt; and look it up by id where the handler needs it. &lt;code&gt;migrate props&lt;/code&gt; lists each &lt;code&gt;onSelect&lt;/code&gt; on them, and the type check finds a handler that still takes the object.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;strings-compat-exports&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;): &lt;code&gt;statusLabel&lt;/code&gt; (lib/candor/status), &lt;code&gt;environmentLabel&lt;/code&gt; (lib/candor/team), &lt;code&gt;approvalStateLabel&lt;/code&gt; (approval-request), &lt;code&gt;reviewLevels&lt;/code&gt; (review-ladder) and &lt;code&gt;standardCards&lt;/code&gt; (standard-cards), English only, are removed. The codemod rewrites &lt;code&gt;standardCards&lt;/code&gt; used inside a component to &lt;code&gt;const standardCards = useStandardCards()&lt;/code&gt; at its top, and lists the others, and &lt;code&gt;standardCards&lt;/code&gt; used outside a component, with what to use: &lt;code&gt;useStatusLabel()&lt;/code&gt; (&lt;code&gt;label(&amp;quot;running&amp;quot;)&lt;/code&gt;); EnvironmentBand's &lt;code&gt;production&lt;/code&gt; and &lt;code&gt;nonProduction&lt;/code&gt; strings joined with &lt;code&gt;useFormat().join&lt;/code&gt;; &lt;code&gt;useStrings(&amp;quot;approvalRequest&amp;quot;, approvalRequestStrings)&lt;/code&gt;; &lt;code&gt;useStrings(&amp;quot;reviewLadder&amp;quot;, reviewLadderStrings)&lt;/code&gt;. SessionList's &lt;code&gt;statusLabel&lt;/code&gt; prop is a different thing and stays.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;chart-strings&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;): &lt;code&gt;barChart.byCategory&lt;/code&gt;, &lt;code&gt;lineChart.over&lt;/code&gt;, &lt;code&gt;lineChart.chartValues&lt;/code&gt; and &lt;code&gt;heatmap.heatmap&lt;/code&gt;, unread since 4.2, are removed. An override of one still compiles and draws nothing; the codemod deletes it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;strings-separator&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;): the &amp;quot; · &amp;quot; between parts is one string, &lt;code&gt;strings.locale.separator&lt;/code&gt;, read through &lt;code&gt;useFormat().separator&lt;/code&gt; and &lt;code&gt;useFormat().join&lt;/code&gt;. The keys that held it are removed: &lt;code&gt;message.metaSeparator&lt;/code&gt;, &lt;code&gt;payload.titleSeparator&lt;/code&gt;, &lt;code&gt;permissionPrompt.scopeSeparator&lt;/code&gt;, &lt;code&gt;reasoning.summarySeparator&lt;/code&gt;, &lt;code&gt;composer.hintSeparator&lt;/code&gt;, &lt;code&gt;searchTrace.domainSeparator&lt;/code&gt;, &lt;code&gt;changeSetReview.hintSeparator&lt;/code&gt;, &lt;code&gt;taskTray.countSeparator&lt;/code&gt;, &lt;code&gt;workflowEditor.hintSeparator&lt;/code&gt; and &lt;code&gt;markSeparator&lt;/code&gt;, and &lt;code&gt;reviewQueue.hintSeparator&lt;/code&gt;. The codemod moves an override of one to &lt;code&gt;locale.separator&lt;/code&gt;; where two give different values, it lists them for you to choose. &lt;code&gt;subscoreCard.separator&lt;/code&gt; and &lt;code&gt;tableScrubberMap.kindSeparator&lt;/code&gt; (&amp;quot;, &amp;quot;) are removed too: those lists follow the locale's list format, and the codemod lists an override of either. These strings no longer hold the mark, since Candor joins the parts: &lt;code&gt;integrationConnect.connectedSince&lt;/code&gt; (&amp;quot;since {when}&amp;quot;) and &lt;code&gt;checkedAt&lt;/code&gt; (&amp;quot;checked {when}&amp;quot;), &lt;code&gt;subscriptionStatus.cardExpires&lt;/code&gt; (&amp;quot;expires {expires}&amp;quot;), &lt;code&gt;membersTable.invitedBy&lt;/code&gt; (&amp;quot;Invited by {name}&amp;quot;, with the new &lt;code&gt;expiresIn&lt;/code&gt;), &lt;code&gt;awayDigest.group&lt;/code&gt; (&amp;quot;{label}&amp;quot;), &lt;code&gt;blastRadius.group&lt;/code&gt; (&amp;quot;{noun}s&amp;quot;), &lt;code&gt;escalation.sentLine&lt;/code&gt; and &lt;code&gt;acknowledged&lt;/code&gt;, &lt;code&gt;environmentPromotion.requestedBy&lt;/code&gt;, &lt;code&gt;promoted&lt;/code&gt; and &lt;code&gt;declined&lt;/code&gt; (each without &lt;code&gt;{when}&lt;/code&gt;), &lt;code&gt;taskTray.started&lt;/code&gt; (&amp;quot;started&amp;quot;), &lt;code&gt;clarifyingQuestions.progress&lt;/code&gt; (&amp;quot;question {step} of {total}&amp;quot;, with the new &lt;code&gt;before&lt;/code&gt;), &lt;code&gt;agentRoster.failed&lt;/code&gt; (&amp;quot;{count} failed&amp;quot;) and &lt;code&gt;columnMapper.suggested&lt;/code&gt; (&amp;quot;Suggested&amp;quot;, with the new &lt;code&gt;percentSure&lt;/code&gt;, &amp;quot;{percent}% sure&amp;quot;). Four that held it between parts are removed, their parts joined by Candor: &lt;code&gt;reconcileTable.summary&lt;/code&gt; (&lt;code&gt;openCount&lt;/code&gt;, &lt;code&gt;resolvedCount&lt;/code&gt;, &lt;code&gt;matchedCount&lt;/code&gt;), &lt;code&gt;evalScorecard.passedFailed&lt;/code&gt; (&lt;code&gt;passedCount&lt;/code&gt;, &lt;code&gt;failedCount&lt;/code&gt;), &lt;code&gt;reviewQueue.progress&lt;/code&gt; (&lt;code&gt;position&lt;/code&gt;, &amp;quot;{position} of {total}&amp;quot;, and &lt;code&gt;gradedCount&lt;/code&gt;) and &lt;code&gt;dataTable.aggregateLine&lt;/code&gt;, which has nothing to translate; the codemod lists an override of one with the keys that say it now. An override of a kept string that kept its own &amp;quot; · &amp;quot; shows it twice. One that kept a placeholder Candor no longer fills (&lt;code&gt;{when}&lt;/code&gt;, &lt;code&gt;{count}&lt;/code&gt;, &lt;code&gt;{status}&lt;/code&gt;, &lt;code&gt;{expires}&lt;/code&gt; or &lt;code&gt;{percent}&lt;/code&gt;) shows it as written: &lt;code&gt;{when}&lt;/code&gt; on screen. The codemod lists an override that still has either: take it out.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;strings-sentences&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;, which lists): sentences built by joining strings and numbers in code are one string each with &lt;code&gt;{placeholders}&lt;/code&gt;, or are parts Candor joins with the separator. The removed keys, and what says them now: &lt;code&gt;scheduleEditor.announceNext&lt;/code&gt; (&lt;code&gt;announceRule&lt;/code&gt;, &lt;code&gt;announceRuleAlone&lt;/code&gt;); &lt;code&gt;dataRetention.policy&lt;/code&gt; (&lt;code&gt;policyVersion&lt;/code&gt;, &lt;code&gt;policyChanged&lt;/code&gt;); &lt;code&gt;subscriptionStatus.price&lt;/code&gt; (&lt;code&gt;pricePerSeat&lt;/code&gt;, &lt;code&gt;priceTotal&lt;/code&gt;); &lt;code&gt;inviteChooser.from&lt;/code&gt; (&lt;code&gt;fromName&lt;/code&gt;, &lt;code&gt;expiresIn&lt;/code&gt;); &lt;code&gt;dualListbox.added&lt;/code&gt; and &lt;code&gt;removed&lt;/code&gt; (&lt;code&gt;addedNow&lt;/code&gt; and &lt;code&gt;removedNow&lt;/code&gt;, &amp;quot;Added 3 to Members, which now holds 5.&amp;quot;) and &lt;code&gt;total&lt;/code&gt;; &lt;code&gt;subscoreCard.outOf100&lt;/code&gt; (&lt;code&gt;scoreOutOf&lt;/code&gt;, &amp;quot;{score} / {max}&amp;quot;); &lt;code&gt;freshnessStamp.stampOverdue&lt;/code&gt; (&lt;code&gt;overdue&lt;/code&gt;); &lt;code&gt;memoryManager.summary&lt;/code&gt; (&lt;code&gt;inferredCount&lt;/code&gt;); &lt;code&gt;blastRadius.reach&lt;/code&gt; (&lt;code&gt;reachChanged&lt;/code&gt;, &lt;code&gt;reachRead&lt;/code&gt;); &lt;code&gt;changeSetReview.summary&lt;/code&gt; (&lt;code&gt;keptCount&lt;/code&gt;, &lt;code&gt;droppedCount&lt;/code&gt;, &lt;code&gt;toDecide&lt;/code&gt;); &lt;code&gt;documentProgressQueue.counts&lt;/code&gt; (&lt;code&gt;countDone&lt;/code&gt;, &lt;code&gt;countWorking&lt;/code&gt;, &lt;code&gt;countQueued&lt;/code&gt;, &lt;code&gt;countFailed&lt;/code&gt;); &lt;code&gt;logStream.problemsCount&lt;/code&gt; and &lt;code&gt;workflowEditor.graphProblems&lt;/code&gt; (&lt;code&gt;problems&lt;/code&gt;); &lt;code&gt;plan.sentBackSummary&lt;/code&gt; (&lt;code&gt;notAccepted&lt;/code&gt;); &lt;code&gt;shipReview.summary&lt;/code&gt; (&lt;code&gt;createdCount&lt;/code&gt;, &lt;code&gt;updatedCount&lt;/code&gt;, &lt;code&gt;deletedCount&lt;/code&gt;); and &lt;code&gt;environmentConnect.nameDetail&lt;/code&gt;, &lt;code&gt;environmentPromotion.nameDetail&lt;/code&gt; and &lt;code&gt;approvedAt&lt;/code&gt;, &lt;code&gt;driftChange.where&lt;/code&gt; and &lt;code&gt;plan.proposedSummary&lt;/code&gt;, whose parts Candor joins with nothing to translate; so do &lt;code&gt;composer.scopeChip&lt;/code&gt;, &lt;code&gt;composerScopePicker.scopeChip&lt;/code&gt;, &lt;code&gt;searchTrace.counts&lt;/code&gt;, &lt;code&gt;appSidebar.labelCount&lt;/code&gt;, &lt;code&gt;inbox.needsYouCount&lt;/code&gt; and &lt;code&gt;sessionList.contextKindShown&lt;/code&gt;, which held &amp;quot; · &amp;quot; in 4.x; and &lt;code&gt;inbox.needsYouCountAtLeast&lt;/code&gt; (&lt;code&gt;countAtLeast&lt;/code&gt;, &amp;quot;{count}+&amp;quot;, joined to &lt;code&gt;needsYou&lt;/code&gt;). The codemod lists each override of a removed key with the key to translate and its placeholders; your words can't be moved for you, since the sentence is different. New keys that replace none, so the codemod doesn't list them and a translated app says them in English until you translate them: &lt;code&gt;modelKey.keyFor&lt;/code&gt; (ModelKey's field label for one provider), &lt;code&gt;runTree.verdictNote&lt;/code&gt;, &lt;code&gt;presence.hereStale&lt;/code&gt;, &lt;code&gt;progressButton.measuredFailed&lt;/code&gt; and &lt;code&gt;failedWithFiles&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;card-deck-backspace&lt;/code&gt;&lt;/strong&gt; (no codemod: behaviour): CardDeck no longer dismisses a card on Backspace; Delete does. The hint keeps its space and names &amp;quot;Left and right arrows&amp;quot; (&lt;code&gt;cardDeck.keysMoveDismiss&lt;/code&gt;, &lt;code&gt;keysMove&lt;/code&gt;). Where your own help names Backspace for CardDeck, name Delete. A dismissal is announced once the app has answered: on the redraw after &lt;code&gt;onDismiss&lt;/code&gt;, or when the promise it returns settles. Where &lt;code&gt;onDismiss&lt;/code&gt; saves before it takes the card out, return the promise (an &lt;code&gt;async&lt;/code&gt; handler does), or the dismissal isn't announced.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;locked-not-disabled&lt;/code&gt;&lt;/strong&gt; (no codemod: behaviour): a control that waits on something stays focusable and is &lt;code&gt;aria-disabled&lt;/code&gt; with the reason, through &lt;code&gt;Locked&lt;/code&gt;, where it was natively &lt;code&gt;disabled&lt;/code&gt;; a press does nothing until it can be used. It covers 32 items, three of them free (ToolCall, PermissionPrompt and Composer), each with its reasons as new &lt;code&gt;locked…&lt;/code&gt; strings. Composer's box and TypeToConfirm's are &lt;code&gt;readOnly&lt;/code&gt; while locked. With &lt;code&gt;onGoTo&lt;/code&gt;, every StepWalker stage is a button: a stage not reached yet is locked, and the current one is marked &lt;code&gt;aria-current=&amp;quot;step&amp;quot;&lt;/code&gt;, so the stage the person pressed keeps focus when it becomes the current one. A ToolCall or SearchTrace row that has finished with nothing behind it is text, not a button (one still running is locked until it has something to show). In a test, check &lt;code&gt;toHaveAttribute(&amp;quot;aria-disabled&amp;quot;, &amp;quot;true&amp;quot;)&lt;/code&gt; in place of &lt;code&gt;toBeDisabled()&lt;/code&gt;, and find such a row by its text. Nothing changes in the app's code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;cli-3&lt;/code&gt;&lt;/strong&gt; (no codemod): use &lt;code&gt;npx candor-ui@3&lt;/code&gt; for 5.0. It works with Candor 4.0 and later. &lt;code&gt;npx candor-ui@2&lt;/code&gt; stays on npm for a 3.x project (upgrade it to 4.0 with &lt;code&gt;@2&lt;/code&gt; first), for &lt;code&gt;update --fold&lt;/code&gt;, and for &lt;code&gt;update --from&lt;/code&gt;, which records items installed before the lockfile.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;heading-level&lt;/code&gt;&lt;/strong&gt;: the &lt;code&gt;HeadingLevel&lt;/code&gt; type (1 to 6), in lib/candor/heading-level. The free items type their &lt;code&gt;headingLevel&lt;/code&gt; with the same union written out.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;heading-scope&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;HeadingScope&lt;/code&gt;, which says the content inside sits under a heading of a level, so Candor items in it draw one below; &lt;code&gt;useHeadingLevel(headingLevel)&lt;/code&gt;, the level an item draws at; and &lt;code&gt;belowLevel(level, n)&lt;/code&gt;, for the headings under it. Never deeper than 6.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;Headings (KIT-226, KIT-205, KIT-220). These take &lt;code&gt;headingLevel&lt;/code&gt; and follow the rule above, most for the first time or with a new default:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Shell: McpConnect and ModelKey draw &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; (were &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;); ArtifactPanel, StopAll, AppLayout's chat heading, DockWindow's window title and SettingsSection keep &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; outside a scope and draw one below inside one. AccountState keeps &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, takes &lt;code&gt;headingLevel&lt;/code&gt;, and its controls and steps sit one level below its title.&lt;/li&gt;&lt;li&gt;Chat: EntityDisambiguation (a fixed &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; in 4.x), ThreadHeader and FormErrorSummary take &lt;code&gt;headingLevel&lt;/code&gt;. The free MessageContent takes &lt;code&gt;headingLevel&lt;/code&gt;, the level a model's &lt;code&gt;#&lt;/code&gt; is drawn at (default 3, as before; &lt;code&gt;##&lt;/code&gt; and &lt;code&gt;###&lt;/code&gt; below it, to 6), and reads no scope; ArtifactPanel passes one below its title, so a document's headings sit under it where in 4.x they were always &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;h5&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Data, reports, ops and evals: DataTable, ReorderableList, Board, BoardCard, DetailsList, ReconcileTable, ColumnMapper, Finding, NarrativeBlock, PortfolioCard, ReportSheet, ReportSection, MonitorCard, RunLog, RunEstimate, FailureClusters, ReviewQueue and DashboardTile; ColumnMapper, RunEstimate, ReviewQueue, ReportSheet and ReportSection gain the prop. Without a title, DataTable's stacked group heads and cards take the table's own level, so no level is skipped. A loading, empty or failed list's heading sits below the list's own.&lt;/li&gt;&lt;li&gt;Work, knowledge and collaboration: ApprovalRequest, ApprovalDecision, ChangeSetReview, ExtractionReview (still &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; outside a scope), ResultCard, FileList, Proposal, Plan, CheckpointList, RestoreDialog, WorkflowEditor, ProseDiff, VersionHistory, CommentThread, Escalation, BlastRadius, AgentScreen, ClarifyingQuestions, DocumentProgressQueue, DriftChange, EnvironmentPromotion, ShipReview, RunRecovery, KnowledgeSources, MemoryManager, RetrievalInspector and AwayDigest. ApprovalRequest sets a scope round &lt;code&gt;change&lt;/code&gt;, ResultCard and Plan round their actions, EnvironmentPromotion round its diff.&lt;/li&gt;&lt;li&gt;Admin, team and billing: ApiKeys, ChannelSetup, DataRegion, DataRetention, DeviceSessions, EnvironmentConnect, EnvironmentList (default 3 to 2, and it accepts 1), IntegrationConnect, ScheduleEditor, ScheduleList, SsoSetup, Webhooks, AccountCreate, ConsentCeremony, InviteChooser, SetupChecklist, SignIn, TermsConsent, BillingDetails, InvoiceHistory and PlanGate. EmailPreview's prop is typed &lt;code&gt;HeadingLevel&lt;/code&gt; and keeps its default of 3, since an email is rendered on the server and can't read a scope.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Names (KIT-227): TabBar, NavRail, AppSidebar and SettingsLayout take &lt;code&gt;activeId&lt;/code&gt;; SettingsLayout and DocumentViewer take &lt;code&gt;label&lt;/code&gt;; PersonMenu and ScopeSwitcher take &lt;code&gt;popupClassName&lt;/code&gt;; Tree's and EnvironmentBand's &lt;code&gt;onSelect&lt;/code&gt; passes the id. SettingsLayout's &lt;code&gt;contentLabel&lt;/code&gt; doc says to set &amp;quot;{item}&amp;quot; where the items' labels already say &amp;quot;settings&amp;quot; (KIT-204).&lt;/p&gt;&lt;p&gt;The separator and sentences (KIT-229, KIT-202, KIT-188): every &amp;quot; · &amp;quot; typed into an item, about forty of them, reads &lt;code&gt;locale.separator&lt;/code&gt;. Text from a model, a tool or another person stays in its own &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt; beside it: Message's model and cost, ColumnMapper's sample values and DriftChange's agent name each are. ThreadHeader's agent names and InstructionsEditor's unknown variables are joined as the locale joins a list (&amp;quot;a and b&amp;quot;). DualListbox says one sentence in the list's own name, and ProgressButton names the files that failed. SubscoreCard's score is &amp;quot;{score} / {max}&amp;quot; in the locale's digits, and a total it can't compute says &amp;quot;Not computed&amp;quot;.&lt;/p&gt;&lt;p&gt;CardDeck (KIT-157): Backspace no longer dismisses; the hint keeps its space; a dismissal the app refuses isn't announced later; &lt;code&gt;onDismiss&lt;/code&gt; may return a promise, and a card the app takes out before it settles is announced. ScheduleEditor (KIT-156) no longer reads &lt;code&gt;announceNext&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;@candor-ui/react 5.0.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;PermissionPrompt's heading defaults to &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; (was &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;); pass &lt;code&gt;headingLevel={3}&lt;/code&gt; to keep 4.x's.&lt;/li&gt;&lt;li&gt;PageState and ListStateView take &lt;code&gt;headingLevel&lt;/code&gt; (default 2); PageHeader takes it (default 1). Additive.&lt;/li&gt;&lt;li&gt;MessageContent takes &lt;code&gt;headingLevel&lt;/code&gt; (default 3, as before): the level a model's &lt;code&gt;#&lt;/code&gt; heading is drawn at. Additive.&lt;/li&gt;&lt;li&gt;Message, Payload, PermissionPrompt, Reasoning, ToolCall, Composer, ThreadEvent and ShimmerLabel read &lt;code&gt;strings.locale.separator&lt;/code&gt;; &lt;code&gt;message.metaSeparator&lt;/code&gt;, &lt;code&gt;payload.titleSeparator&lt;/code&gt;, &lt;code&gt;permissionPrompt.scopeSeparator&lt;/code&gt;, &lt;code&gt;reasoning.summarySeparator&lt;/code&gt;, &lt;code&gt;composer.hintSeparator&lt;/code&gt;, &lt;code&gt;composer.scopeChip&lt;/code&gt; and &lt;code&gt;searchTrace.domainSeparator&lt;/code&gt; are gone, as above.&lt;/li&gt;&lt;li&gt;&lt;code&gt;localeStrings&lt;/code&gt; is exported, with &lt;code&gt;locale.separator&lt;/code&gt;; &lt;code&gt;useFormat()&lt;/code&gt; gives &lt;code&gt;separator&lt;/code&gt; and &lt;code&gt;join(parts)&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;statusLabel&lt;/code&gt; is no longer exported: use &lt;code&gt;useStatusLabel()&lt;/code&gt;. The data types' names don't change here.&lt;/li&gt;&lt;li&gt;ToolCall, PermissionPrompt and Composer: a control that waits on something is &lt;code&gt;aria-disabled&lt;/code&gt; with the reason, and stays focusable, where it was natively &lt;code&gt;disabled&lt;/code&gt; (&lt;code&gt;locked-not-disabled&lt;/code&gt; above). Composer's box is &lt;code&gt;readOnly&lt;/code&gt; while it is locked. A finished ToolCall row with no details is text (&lt;code&gt;data-slot=&amp;quot;tool-call-row&amp;quot;&lt;/code&gt;), not a button, and Composer's scope chip is a &lt;code&gt;span&lt;/code&gt; unless you pass &lt;code&gt;onScopeClick&lt;/code&gt;. In a test, check &lt;code&gt;toHaveAttribute(&amp;quot;aria-disabled&amp;quot;, &amp;quot;true&amp;quot;)&lt;/code&gt; in place of &lt;code&gt;toBeDisabled()&lt;/code&gt;, and find such a row by its text. A translated app translates the new reasons: ToolCall's &lt;code&gt;lockedNoDetail&lt;/code&gt;; PermissionPrompt's &lt;code&gt;lockedBusy&lt;/code&gt;, &lt;code&gt;lockedInvalid&lt;/code&gt; and &lt;code&gt;lockedUnanswered&lt;/code&gt;; Composer's &lt;code&gt;lockedUnavailable&lt;/code&gt;, &lt;code&gt;lockedHeld&lt;/code&gt;, &lt;code&gt;lockedEmpty&lt;/code&gt;, &lt;code&gt;lockedSending&lt;/code&gt; and &lt;code&gt;lockedStreaming&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 3.0.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;New: &lt;code&gt;migrate 5.0.0&lt;/code&gt;, with the codemods &lt;code&gt;types-data&lt;/code&gt;, &lt;code&gt;props&lt;/code&gt; (5.0's renames and &lt;code&gt;onSelect&lt;/code&gt; listing), &lt;code&gt;strings-keys&lt;/code&gt; (the separator, the removed keys and the English exports) and &lt;code&gt;headings&lt;/code&gt; (lists only). A codemod table's row says which release it belongs to, so &lt;code&gt;migrate 4.0.0&lt;/code&gt; makes none of 5.0's changes.&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;migrate&lt;/code&gt; refuse a project older than 4.0, naming &lt;code&gt;npx candor-ui@2&lt;/code&gt; (and &lt;code&gt;@1&lt;/code&gt; for 2.x).&lt;/li&gt;&lt;li&gt;Removed, with 3.x: &lt;code&gt;migrate motion-aliases&lt;/code&gt; and its tables; strings-keys' &lt;code&gt;message.thinking&lt;/code&gt; and &lt;code&gt;useAnsweringApprovals&lt;/code&gt; rows; &lt;code&gt;update --fold&lt;/code&gt;, which now refuses and names &lt;code&gt;npx candor-ui@2 update --fold&lt;/code&gt;; and &lt;code&gt;update --from&lt;/code&gt;, which names &lt;code&gt;npx candor-ui@2 update &amp;lt;items&amp;gt; --from &amp;lt;version&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Kept: 4.0's codemods, and &lt;code&gt;theme check&lt;/code&gt;'s errors for 2.2's motion tokens, which now name &lt;code&gt;npx candor-ui@2 migrate motion-aliases&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Fixed: a table rename keeps an inline &lt;code&gt;type&lt;/code&gt; modifier on the import.&lt;/li&gt;&lt;li&gt;&lt;code&gt;migrate&lt;/code&gt;, and &lt;code&gt;update&lt;/code&gt; where it moves files, run on a TypeScript 7 project: where the project's &lt;code&gt;typescript&lt;/code&gt; has no JavaScript API, or there is none, they parse with the TypeScript 5 candor-ui depends on, where CLI 2 stopped and said to install it. The Base UI &lt;code&gt;asChild&lt;/code&gt; rewrite in &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; still uses the project's own, else shadcn's preview.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For maintainers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The react build fails on a name two modules both export, where it renamed the data types before.&lt;/li&gt;&lt;li&gt;&lt;code&gt;scripts/check-slots.mjs&lt;/code&gt; looks through &lt;code&gt;HeadingScope&lt;/code&gt; to an item's root.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.5.0</title>
      <link>https://candor.themethodic.com/changelog#4-5-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-5-0</guid>
      <pubDate>Thu, 12 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 2.3.1 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.5.0; nothing breaks. Steps and conditions dragged into place in WorkflowEditor's graph, by pointer, keyboard or touch; heading levels on seven items, so they fit under a page's own headings; the fixes 4.4's reviews found, in the kit, the motion system and the docs MCP; and the fixes the Fable review of 4.3.0 and 4.4.0 found. The kit has 399 items: 74 free and 368 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; takes a 4.4 project to 4.5.0, with no codemod. If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 4.5.0, which carries the free fixes to &lt;code&gt;Button&lt;/code&gt;, &lt;code&gt;Locked&lt;/code&gt; and &lt;code&gt;Progress&lt;/code&gt;. Three changes a 4.4 app sees, each with what to do:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;MonitorCard (Pro) without &lt;code&gt;onToggle&lt;/code&gt;&lt;/strong&gt; says &amp;quot;On&amp;quot; or &amp;quot;Off&amp;quot; in words (&lt;code&gt;span[data-slot=monitor-on]&lt;/code&gt;, the new strings &lt;code&gt;monitorCard.isOn&lt;/code&gt; and &lt;code&gt;isOff&lt;/code&gt;) in place of a switch that did nothing when pressed. An unavailable monitor keeps its switch, locked with the reason. Pass &lt;code&gt;onToggle&lt;/code&gt; where the person can turn the monitor on or off; a test that found the switch on a card without &lt;code&gt;onToggle&lt;/code&gt; should find the words.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DriftChange (Pro)&lt;/strong&gt; keeps its actions locked once Adopt or Revert has finished, saying &amp;quot;Waiting for the change to update.&amp;quot; (the new string &lt;code&gt;driftChange.waitUpdate&lt;/code&gt;), until its &lt;code&gt;status&lt;/code&gt; leaves &lt;code&gt;&amp;quot;open&amp;quot;&lt;/code&gt; or a new change arrives; then it announces the outcome. Set &lt;code&gt;status&lt;/code&gt; to &lt;code&gt;&amp;quot;adopted&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;reverted&amp;quot;&lt;/code&gt; when &lt;code&gt;onAdopt&lt;/code&gt; or &lt;code&gt;onRevert&lt;/code&gt; has done its work; an app that never sets it leaves the actions locked.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;PersonMenu's avatar (Pro)&lt;/strong&gt; is named after the initials it shows, then its 4.4 name: &amp;quot;PS, Priya Shah, account menu&amp;quot;, through the new string &lt;code&gt;personMenu.withInitials&lt;/code&gt; (&lt;code&gt;&amp;quot;{initials}, {label}&amp;quot;&lt;/code&gt;), so its name starts with what can be seen. A test that found the avatar by its name should look for the new one; the row form is unchanged.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Translators: these keys are new. Until you translate them, each says its English words, except where noted.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;scheduleEditor.announceRule&lt;/code&gt; and &lt;code&gt;announceRuleAlone&lt;/code&gt;, the announcement once the person stops changing the rule. An app that translated 4.4's &lt;code&gt;announceNext&lt;/code&gt; and not these still hears its own words, joined as 4.4 joined them. &lt;code&gt;announceNext&lt;/code&gt; is no longer read otherwise; 5.0 removes it.&lt;/li&gt;&lt;li&gt;&lt;code&gt;settingsLayout.contentLabel&lt;/code&gt; (&amp;quot;{item} settings&amp;quot;), the open section's region name. An app that translated SettingsLayout's other strings and not this one gets 4.4's name, the item's own label.&lt;/li&gt;&lt;li&gt;&lt;code&gt;personMenu.withInitials&lt;/code&gt;; &lt;code&gt;monitorCard.isOn&lt;/code&gt; and &lt;code&gt;isOff&lt;/code&gt;; &lt;code&gt;driftChange.waitUpdate&lt;/code&gt; and &lt;code&gt;revertUndo&lt;/code&gt;; &lt;code&gt;modelKey.cancelLocked&lt;/code&gt;; &lt;code&gt;permissionMode.changingLocked&lt;/code&gt;; &lt;code&gt;linkPreview.userinfo&lt;/code&gt;; &lt;code&gt;dateField.readingWithProblem&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;sessionList.contextWords&lt;/code&gt; and &lt;code&gt;contextKindShown&lt;/code&gt;; &lt;code&gt;cardDeck.dismissedNext&lt;/code&gt;, &lt;code&gt;keysMoveDismiss&lt;/code&gt;, &lt;code&gt;keysMove&lt;/code&gt; and &lt;code&gt;keysDismiss&lt;/code&gt;; &lt;code&gt;dataTable.sortBy&lt;/code&gt;, &lt;code&gt;notSorted&lt;/code&gt;, &lt;code&gt;order&lt;/code&gt;, &lt;code&gt;ascending&lt;/code&gt;, &lt;code&gt;descending&lt;/code&gt; and &lt;code&gt;sortFirst&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;IntegrationConnect's hold: &lt;code&gt;integrationConnect.waitingTitle&lt;/code&gt;, &lt;code&gt;waitingNote&lt;/code&gt;, &lt;code&gt;blockedTitle&lt;/code&gt;, &lt;code&gt;blockedNote&lt;/code&gt;, &lt;code&gt;approveWho&lt;/code&gt;, &lt;code&gt;approveWhere&lt;/code&gt;, &lt;code&gt;blockedWhat&lt;/code&gt;, &lt;code&gt;unblocker&lt;/code&gt;, &lt;code&gt;askedAt&lt;/code&gt;, &lt;code&gt;holdCheckedAt&lt;/code&gt;, &lt;code&gt;checkAgain&lt;/code&gt;, &lt;code&gt;checking&lt;/code&gt;, &lt;code&gt;waitCheck&lt;/code&gt;, &lt;code&gt;checkFailed&lt;/code&gt; and &lt;code&gt;back&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The workflow graph's move: &lt;code&gt;graphView.places&lt;/code&gt;, and &lt;code&gt;workflowEditor.move&lt;/code&gt;, &lt;code&gt;moveNode&lt;/code&gt;, &lt;code&gt;moveHint&lt;/code&gt;, &lt;code&gt;cancelMove&lt;/code&gt;, &lt;code&gt;cancelMoveNode&lt;/code&gt;, &lt;code&gt;triggerFixed&lt;/code&gt;, &lt;code&gt;placeAt&lt;/code&gt;, &lt;code&gt;placeHere&lt;/code&gt;, &lt;code&gt;pickedUp&lt;/code&gt; and &lt;code&gt;putBack&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some DOM your own CSS or tests may match has changed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;SettingsLayout's open section (Pro)&lt;/strong&gt; is a region named &amp;quot;{item} settings&amp;quot; (&amp;quot;Members settings&amp;quot;), no longer the item's label alone, so it no longer shares &amp;quot;Members&amp;quot; with MembersTable's section. A test that found the region by the item's label should use the new name.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;PermissionMode (Pro)&lt;/strong&gt;, while a change of mode is on its way, keeps the other modes focusable, &lt;code&gt;aria-disabled&lt;/code&gt; in &lt;code&gt;Locked&lt;/code&gt; with the reason &amp;quot;Changing the mode&amp;quot; (&lt;code&gt;permissionMode.changingLocked&lt;/code&gt;), not &lt;code&gt;disabled&lt;/code&gt;, and focus stays where it was. A test that expected them disabled should check &lt;code&gt;aria-disabled=&amp;quot;true&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CardDeck (Pro)&lt;/strong&gt; lists its keys in &lt;code&gt;aria-keyshortcuts&lt;/code&gt; and describes them in &lt;code&gt;[data-slot=card-deck-hint]&lt;/code&gt;, shown while the stack has keyboard focus. Once the app has taken a dismissed card out, it announces &amp;quot;{card} dismissed. {next}, 2 of 5&amp;quot; once, in place of &amp;quot;{card} dismissed&amp;quot;. A test expecting the shorter announcement should expect the sentence. Backspace still dismisses.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AppLayout's app frame (Pro)&lt;/strong&gt; draws no &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; when there is no &lt;code&gt;brand&lt;/code&gt;, no &lt;code&gt;top&lt;/code&gt; and no menu button; the banner's row collapses. A test that expected an empty banner landmark there should expect none.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; (free)&lt;/strong&gt;, without a reason, hands back the control as it is: it no longer gives it an id or a tooltip trigger's attributes and handlers, so an app's own &lt;code&gt;TooltipTrigger&lt;/code&gt; round it finds the app's &lt;code&gt;Tooltip&lt;/code&gt;. Locked's tooltip now sits beside the control rather than round it. &lt;code&gt;locked&lt;/code&gt; imports &lt;code&gt;@base-ui/react/tooltip&lt;/code&gt;. Each &lt;code&gt;Locked&lt;/code&gt; also has its own tooltip provider, on your &lt;code&gt;TooltipProvider&lt;/code&gt;'s timing, so moving from one locked control to the next waits the provider's &lt;code&gt;delay&lt;/code&gt; again rather than opening at once within its &lt;code&gt;timeout&lt;/code&gt;. Nothing to change in the app; a test that expected the next locked control's tooltip at once should wait for it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;LinkPreview (Pro)&lt;/strong&gt; shows the scheme and host the browser goes to: lower-cased, an international name as its punycode, without a user name or password. An address that carries one has a note under it, &lt;code&gt;[data-slot=link-preview-userinfo]&lt;/code&gt; (&lt;code&gt;linkPreview.userinfo&lt;/code&gt;). A test that matched the address as written should match the host as the browser reads it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DataTable's stacked form (Pro)&lt;/strong&gt; has &lt;code&gt;[data-slot=data-table-sort]&lt;/code&gt; above its cards whenever it has rows.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ReorderableList's drag ghost (Pro)&lt;/strong&gt;, &lt;code&gt;[data-slot=reorderable-list-ghost]&lt;/code&gt;, and GraphView's new one are drawn through &lt;code&gt;LayerPortal&lt;/code&gt;, at the end of &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; (or in the layer host inside another library's dialog), so inside a Dialog or Sheet the ghost sits beside the pointer and isn't cut off by the window. A test that looked for the ghost inside the list should look in &lt;code&gt;document&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tabs (Pro)&lt;/strong&gt; leave &lt;code&gt;data-tab-value&lt;/code&gt; off a tab whose value is an object or a function, where 4.4 wrote &amp;quot;[object Object]&amp;quot;; strings, numbers, booleans, &lt;code&gt;null&lt;/code&gt; and bigints keep it.&lt;/li&gt;&lt;li&gt;Added attributes, with nothing to do: LineChart's plot carries &lt;code&gt;data-plot-dir=&amp;quot;ltr&amp;quot;&lt;/code&gt;; GraphView's node buttons, and the backdrops of Dialog, AlertDialog, Sheet and Drawer, carry their moment's motion chain in their own &lt;code&gt;style&lt;/code&gt;, with the caller's style merged over it; DriftChange's Revert confirmation has &lt;code&gt;[data-slot=drift-change-revert-undo]&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;@candor/initials&lt;/code&gt;&lt;/strong&gt;, a lib item: &lt;code&gt;initialsOf(name, locale?)&lt;/code&gt;, the first letter of each of a name's first two words, upper-cased in &lt;code&gt;locale&lt;/code&gt; (&amp;quot;ilker&amp;quot; is &amp;quot;İ&amp;quot; in Turkish, &amp;quot;I&amp;quot; in English). Left out, the letters are upper-cased the same in every language, so the server and the browser agree. PersonMenu and Board import it, so installing Board no longer brings in PersonMenu; &lt;code&gt;person-menu&lt;/code&gt; still exports &lt;code&gt;initialsOf&lt;/code&gt; for apps that import it from there.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;WorkflowEditor (Pro):&lt;/strong&gt; steps and conditions move in the graph view. Drag one with a mouse or pen to a place between two nodes or into a branch, or press the Move button on its card under the graph: the arrow keys choose a place, Enter drops it there and Escape puts it back, each step said; on a touch screen, tap a place, or Cancel. The layout stays automatic. A move is marked &amp;quot;Moved by you&amp;quot; and Undo takes it back. The trigger always comes first, and its Move button says so. Escape during a move or a drag doesn't close a Dialog or Sheet the editor is in.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;GraphView (Pro)&lt;/strong&gt; takes &lt;code&gt;places&lt;/code&gt;, a function giving the places a node can go (&lt;code&gt;GraphViewPlace&lt;/code&gt;, in the layout's layer and slot), &lt;code&gt;onPlace&lt;/code&gt; (a drop) and &lt;code&gt;moving&lt;/code&gt; (a keyboard move the app draws). While a move is on, each place is a button named by its place, out of the tab order. After a drop the nodes that moved slide, a &lt;code&gt;settle&lt;/code&gt; moment in the move family. Without &lt;code&gt;places&lt;/code&gt; a graph draws as before, so Plan, RunTree and Diagram are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;headingLevel&lt;/code&gt; (Pro)&lt;/strong&gt; on ReorderableList (its group heads, default 4), Board (its column heads, default 4), BoardCard (one below its board's heads; used alone, 5), DataTable (its title, default 3; the stacked form's group heads and cards below it), ApprovalDecision (1 to 6, default 3), MonitorCard (default 3) and EnvironmentList (default 3), so each fits under a page's own headings. ApprovalRequest and PortfolioCard already had it. The defaults are 4.4's levels, so nothing a 4.4 page draws changes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;IntegrationConnect (Pro)&lt;/strong&gt; takes &lt;code&gt;hold&lt;/code&gt; (&lt;code&gt;IntegrationHold&lt;/code&gt;, &lt;code&gt;&amp;quot;waiting&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;blocked&amp;quot;&lt;/code&gt;), &lt;code&gt;onCheckAgain&lt;/code&gt; and &lt;code&gt;onBack&lt;/code&gt;, as EnvironmentConnect does: who has to approve the app, where and when it was asked and checked, or whose policy blocks it and who can unblock it. Without &lt;code&gt;hold&lt;/code&gt; nothing changes; once connected, &lt;code&gt;hold&lt;/code&gt; is ignored. The names in a hold are another tenant's text, neutralised and drawn in a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SessionList (Pro):&lt;/strong&gt; &lt;code&gt;contextKind=&amp;quot;visible&amp;quot;&lt;/code&gt; prints the context's kind before its chip (&amp;quot;Approval · Quote over $50k&amp;quot;); the default, &lt;code&gt;&amp;quot;name&amp;quot;&lt;/code&gt;, reads it in the chip's name only, as in 4.4.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ScheduleEditor and SessionList (Pro)&lt;/strong&gt; build their sentences from strings with placeholders (&lt;code&gt;announceRule&lt;/code&gt;, &lt;code&gt;announceRuleAlone&lt;/code&gt;, &lt;code&gt;contextWords&lt;/code&gt;), not by joining words in code, so a translation can order them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DataTable (Pro):&lt;/strong&gt; &lt;code&gt;stackBelow&lt;/code&gt; is measured before the first paint, so a phone never draws the wide table first; server-rendered HTML shows the wide table until it hydrates. The stacked form has a Sort by control (a column, or Not sorted) and Ascending and Descending above the cards: the same sort as the column heads, asked of the server in server mode and kept when the table widens. Nothing is chosen until the person chooses.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ConfirmField (Pro)&lt;/strong&gt; takes &lt;code&gt;entry&lt;/code&gt; and &lt;code&gt;onEntryChange&lt;/code&gt;, to control the second entry; &lt;code&gt;entry=&amp;quot;&amp;quot;&lt;/code&gt; resets it and its judgement. Both entries are compared after &lt;code&gt;normalize(&amp;quot;NFC&amp;quot;)&lt;/code&gt;, so a name typed with a combining accent matches; case and spacing still count. &amp;quot;Matches&amp;quot; is withdrawn as soon as either entry changes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;PlanPicker (Pro):&lt;/strong&gt; the totals' value moment waits a second with no More or Fewer press, then plays once for the settled total; a typed seat number doesn't play it. A test of the moment should advance timers by 1000 ms.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;NumberInput (Pro)&lt;/strong&gt; replays its value moment only on a step: clearing &lt;code&gt;attend&lt;/code&gt; no longer replays it, and a step pressed while &lt;code&gt;attend&lt;/code&gt; rings doesn't replay the ring.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;MaskedInput (Pro):&lt;/strong&gt; a literal in the mask that would fit a slot (&amp;quot;+1 ###&amp;quot;) is no longer read as typed input. MaskedInput and NumberInput read digits in every script.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DateField and DateRangeField (Pro)&lt;/strong&gt; take &lt;code&gt;onProblemChange&lt;/code&gt;: what is wrong with what the field last read (&lt;code&gt;unreadable&lt;/code&gt;, &lt;code&gt;pastMonthEnd&lt;/code&gt;, &lt;code&gt;beforeMin&lt;/code&gt;, &lt;code&gt;afterMax&lt;/code&gt;) or &lt;code&gt;null&lt;/code&gt;. After text it couldn't read, the app's &lt;code&gt;value&lt;/code&gt; is still the last date it read, so check this before saving a controlled field. In a locale whose calendar isn't the Gregorian one (Thai's Buddhist, Persian's Solar Hijri), the date in words carries its era. Enter announces the reading.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AppLayout (Pro):&lt;/strong&gt; &lt;code&gt;useHideOnScroll&lt;/code&gt;'s &lt;code&gt;header&lt;/code&gt; takes the element as well as a ref, so a header that mounts later still hides and comes back. When a hidden banner unmounts, the frame moves back.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DialogContent (Pro)&lt;/strong&gt; gives the window to an app's &lt;code&gt;ref&lt;/code&gt;, an object or a callback, and keeps &lt;code&gt;from=&amp;quot;trigger&amp;quot;&lt;/code&gt; working; before, an app's ref turned it off without a word. Dialog's nudge ring is drawn inside the window's edge, so a scrolling window doesn't clip it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ModelKey (Pro):&lt;/strong&gt; while a replacement key is being checked, Cancel is locked and says why (&lt;code&gt;modelKey.cancelLocked&lt;/code&gt;); Replace opens with nothing from an earlier attempt.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DriftChange (Pro)&lt;/strong&gt; takes &lt;code&gt;revertUndo&lt;/code&gt;, whether a reverted change can be had again, in the app's words; left out, Revert's confirmation says it isn't kept (&lt;code&gt;driftChange.revertUndo&lt;/code&gt;). See the list above for its locked actions.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Focus kept on the page (Pro):&lt;/strong&gt; FlipCard moves focus to its button when the app sets &lt;code&gt;flipped&lt;/code&gt; while focus is in the face turning away. NeedsYouLine passes Retry's focus to the line when Retry goes, even after a blur to nowhere. FilterChips' Clear all passes over what Tab can't reach (hidden, inert, disabled, &lt;code&gt;aria-hidden&lt;/code&gt;, &lt;code&gt;tabIndex&lt;/code&gt; -1), and removing the only chip keeps focus on the page. EnvironmentList takes focus back only from the page itself, not from where the person is.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ReorderableList and Board (Pro):&lt;/strong&gt; removing the held item ends the move.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tabs and DropdownMenu (Pro):&lt;/strong&gt; an app's callback ref runs once, and its cleanup runs. Tabs find the chosen tab by its order, so the panel's arrive moment travels the right way for any value.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Command (Pro):&lt;/strong&gt; a controlled &lt;code&gt;value&lt;/code&gt; on a disabled item, or one two items share, no longer loops.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;GlideHighlight (Pro)&lt;/strong&gt; puts back its host's position and isolation when it unmounts.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;RunEstimate (Pro)&lt;/strong&gt; counts down from when &lt;code&gt;endsAt&lt;/code&gt; is given, not from when the card mounted, and stops after it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SliderMarks (Pro):&lt;/strong&gt; a locked slider ignores the range input's change event.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ScopeSwitcher (Pro):&lt;/strong&gt; a locked level's reason describes its items.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SectionNav (Pro)&lt;/strong&gt; links sections that arrive after it mounts.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;initialsOf&lt;/code&gt;&lt;/strong&gt; takes an optional locale (see &lt;code&gt;@candor/initials&lt;/code&gt;); PersonMenu and BoardCard pass LocaleProvider's language. Without a locale it now upper-cases the same in every language, where 4.4's followed the runtime's (a Turkish runtime gave &amp;quot;İ&amp;quot;, now &amp;quot;I&amp;quot;). An app that calls it from &lt;code&gt;person-menu&lt;/code&gt; without one and wants the language's letters passes &lt;code&gt;useLocale().locale&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Button (free):&lt;/strong&gt; Enter, Space or a click with no pointer clears the press point (&lt;code&gt;--cd-press-x&lt;/code&gt;, &lt;code&gt;--cd-press-y&lt;/code&gt;), so the Pro ripple grows from the middle; the app's own &lt;code&gt;onKeyDown&lt;/code&gt; and &lt;code&gt;onClick&lt;/code&gt; still run.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Progress (free)&lt;/strong&gt; is seen in forced colours: a measured bar is filled in &lt;code&gt;Highlight&lt;/code&gt; on a &lt;code&gt;Canvas&lt;/code&gt; track edged in &lt;code&gt;CanvasText&lt;/code&gt;, and an indeterminate bar shows a &lt;code&gt;Highlight&lt;/code&gt; band, never a full bar.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Motion (Pro &lt;code&gt;motion-drawings&lt;/code&gt;)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Backdrops follow their window.&lt;/strong&gt; Dialog's, AlertDialog's, Sheet's and Drawer's backdrops carry their item's open chain, so they fade in their own open time and a brand's &lt;code&gt;--cd-motion-&amp;lt;item&amp;gt;-open-*&lt;/code&gt; reaches them; in 4.4 a sheet's dim faded in 150 ms while its panel took longer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;--cd-draw-button-icon: expand&lt;/code&gt;&lt;/strong&gt; shows an icon button's name beside it without widening it or moving its neighbours, and leaves its position and &lt;code&gt;z-index&lt;/code&gt; to the app. Where the browser has anchor positioning the name is anchored to the button, so it adds no sideways scroll at the end of a row, and goes to the button's start when its end has no room for it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;At the Off level&lt;/strong&gt; an indeterminate Progress with a Pro drawing (travel, refill, stripes) shows the free still band, in forced colours too; in 4.4 travel showed a still bar 40% full and refill a full one. In forced colours the Pro bands are drawn in &lt;code&gt;Highlight&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Drawings travel the right way when an element's direction comes from &lt;code&gt;dir=&amp;quot;auto&amp;quot;&lt;/code&gt; or the browser (&lt;code&gt;--cd-inline-sign&lt;/code&gt; from &lt;code&gt;:dir()&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;In a right-to-left page a line chart's line draws in from its first point, the end its points pop in from.&lt;/li&gt;&lt;li&gt;The button press spring falls back to the press family's 0.96 and 150 ms.&lt;/li&gt;&lt;li&gt;4.1's chart rule on &lt;code&gt;svg[role=&amp;quot;img&amp;quot;]&lt;/code&gt;, which matched nothing since 4.2, is gone; charts still draw in.&lt;/li&gt;&lt;li&gt;&lt;code&gt;--cd-tab-sign&lt;/code&gt; is the kit's own, set by TabsContent, not a token: &lt;code&gt;theme check&lt;/code&gt; says so if a brand file sets it. Remove the line.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 2.3.1&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --differing keep&lt;/code&gt;&lt;/strong&gt;, where &lt;code&gt;add&lt;/code&gt; can't plan the project itself (&lt;code&gt;tsx: false&lt;/code&gt;, or no tsconfig paths), keeps every file on disk that shadcn's own dry run lists for the install, including ones the lockfile doesn't record, such as &lt;code&gt;lib/utils.ts&lt;/code&gt;. 2.2.1 to 2.3.0 kept only the files the lockfile recorded as changed, and shadcn replaced the rest. Both modes name the files the install changed, and a dry run that can't be read stops before anything is written.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme check&lt;/code&gt;&lt;/strong&gt; (also the docs MCP's &lt;code&gt;theme_check&lt;/code&gt;) warns &lt;code&gt;motion-value&lt;/code&gt; on a &lt;code&gt;--cd-show-*&lt;/code&gt; or &lt;code&gt;--cd-draw-*&lt;/code&gt; value the item doesn't draw, naming the values it takes; &lt;code&gt;none&lt;/code&gt; and &lt;code&gt;var()&lt;/code&gt; aren't judged. The exit code doesn't change.&lt;/li&gt;&lt;li&gt;&lt;code&gt;theme check&lt;/code&gt; and the theme builder no longer say that &lt;code&gt;mark: fade&lt;/code&gt; and &lt;code&gt;pop: rise&lt;/code&gt; need the Pro item: their keyframes are in the free &lt;code&gt;candor.css&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;suggest_components&lt;/code&gt;&lt;/strong&gt; answers &amp;quot;a table with sortable columns&amp;quot; and &amp;quot;a sortable table&amp;quot; with &lt;code&gt;data-table&lt;/code&gt; first. DataTable's description now says what people ask for (search, sort, filter, page and select rows), and Table's says it is the plain elements; &amp;quot;a plain table&amp;quot; still answers &lt;code&gt;table&lt;/code&gt;. With &lt;code&gt;sdk: &amp;quot;claude&amp;quot;&lt;/code&gt;, a related Premium block is judged as the version the ranking found, so its &lt;code&gt;-claude&lt;/code&gt; version is no longer dropped for its own words; no answer on today's index changes.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site and repository&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;/screens&lt;/code&gt;:&lt;/strong&gt; the &lt;code&gt;home-dashboard&lt;/code&gt; brief scores as a weighted mean of its subscores and uses &lt;code&gt;DashboardGrid&lt;/code&gt; as &lt;code&gt;/apps/workspace&lt;/code&gt; does; &lt;code&gt;/screens/app-shell#topbar&lt;/code&gt; lands on &amp;quot;Workspace frame&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;App examples:&lt;/strong&gt; the board's TW-110 moves from Building, not &amp;quot;Waiting for you&amp;quot;; the workspace's &amp;quot;Value a year&amp;quot; and its client estimates say saved or reclaimable, as an estimate with its basis.&lt;/li&gt;&lt;li&gt;The 4.3.0 section of this file labelled Dialog, the menus, Command and nested dialogs &amp;quot;(free)&amp;quot;; they are Pro, and the labels say so.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For maintainers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;check:motion&lt;/code&gt; checks each &lt;code&gt;@ease&lt;/code&gt; line's &lt;code&gt;overshoots&lt;/code&gt; against its values; that every show or control rule leaves out &lt;code&gt;data-motion=&amp;quot;calm&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;none&amp;quot;&lt;/code&gt;, scales by a level and loops only while running; and that an element whose class names a family utility carries its moment's chain in its own style (a component's &lt;code&gt;{...props}&lt;/code&gt; doesn't count). Known problems in files no stream owned are in &lt;code&gt;scripts/motion-baseline.json&lt;/code&gt;, each with its row; an entry that stops matching fails, so the list can only shrink.&lt;/li&gt;&lt;li&gt;&lt;code&gt;npm run test:browser -- --only &amp;lt;group&amp;gt;&lt;/code&gt; reaches the runner that has the group (&lt;code&gt;tests/browser/run.mjs&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;The layer checks open PersonMenu's and ScopeSwitcher's menus in a Radix dialog.&lt;/li&gt;&lt;li&gt;&lt;code&gt;tests/repo/changelog-tiers.test.ts&lt;/code&gt; fails when a bold label in this file says &amp;quot;(free)&amp;quot; of a Pro item.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.4.0</title>
      <link>https://candor.themethodic.com/changelog#4-4-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-4-0</guid>
      <pubDate>Thu, 12 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 2.3.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.4.0; nothing breaks. An app frame for workspace apps (one chrome in an L round an inset page, with a navigation rail, a top bar, a scope switcher and a person menu) and the items a workspace home and a board need; fields, buttons and cards for forms and show; the rest of the motion backlog in the Pro &lt;code&gt;motion-drawings&lt;/code&gt; item; the fixes 4.3 left; a sturdier &lt;code&gt;suggest_components&lt;/code&gt;; and whole app examples on the site at &lt;code&gt;/apps&lt;/code&gt;. The kit has 398 items: 74 free and 367 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; takes a 4.3 project to 4.4.0, with no codemod. To use the new drawings and motion for show, install or update the Pro &lt;code&gt;motion-drawings&lt;/code&gt; item and import &lt;code&gt;styles/candor-motion-drawings.css&lt;/code&gt; after &lt;code&gt;candor.css&lt;/code&gt;; without a brand value naming them, nothing moves differently. If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 4.4.0.&lt;/p&gt;&lt;p&gt;One behaviour changes: when more toasts arrive than &lt;code&gt;Toaster&lt;/code&gt; shows (four), it now hides the extra ones and counts them (&amp;quot;Show 2 more&amp;quot;) instead of dropping them. An app that relied on the dropped toasts vanishing sees them come back when the person shows them. A toast still waiting on &lt;code&gt;toast.promise&lt;/code&gt; is never hidden. And if your brand already sets &lt;code&gt;--cd-show-charts: cd-show-draw&lt;/code&gt;, the bar, line and donut charts now draw in, as 4.1 meant them to (see Motion).&lt;/p&gt;&lt;p&gt;Some DOM your own CSS or tests may match has changed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;A travelling highlight's box.&lt;/strong&gt; DropdownMenu's popups and sub-menus hold an &lt;code&gt;aria-hidden&lt;/code&gt; &lt;code&gt;span[data-slot=glide-highlight]&lt;/code&gt; as their first child; TabsList holds one after its &lt;code&gt;tabs-indicator&lt;/code&gt;; AppSidebar's places and NavRail hold one too. The container gets &lt;code&gt;data-glide&lt;/code&gt; (and is &lt;code&gt;isolate&lt;/code&gt;; a menu popup is also &lt;code&gt;relative&lt;/code&gt;). The box draws nothing unless a brand sets &lt;code&gt;--cd-draw-highlight&lt;/code&gt;. If your CSS or a test takes a popup's or a tab list's children by position (&lt;code&gt;&amp;gt; :first-child&lt;/code&gt;, &lt;code&gt;children[0]&lt;/code&gt;), select the items by their own &lt;code&gt;data-slot&lt;/code&gt;, or skip &lt;code&gt;[data-slot=glide-highlight]&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AppSidebar's person menu is a &lt;code&gt;PersonMenu&lt;/code&gt;.&lt;/strong&gt; Its trigger is &lt;code&gt;[data-slot=person-menu]&lt;/code&gt; (with &lt;code&gt;data-form=&amp;quot;row&amp;quot;&lt;/code&gt;) in place of &lt;code&gt;[data-slot=dropdown-menu-trigger]&lt;/code&gt;; its words and collapsed tooltip are as before. Select &lt;code&gt;[data-slot=person-menu]&lt;/code&gt; instead. AppSidebar's places also carry &lt;code&gt;data-slot=&amp;quot;app-sidebar-item&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PopoverTrigger&lt;/code&gt; (free) and &lt;code&gt;HoverCardTrigger&lt;/code&gt; (Pro) keep a rendered control's own &lt;code&gt;data-slot&lt;/code&gt;,&lt;/strong&gt; as &lt;code&gt;TooltipTrigger&lt;/code&gt; has since 4.3: a &lt;code&gt;Button&lt;/code&gt; given through &lt;code&gt;render&lt;/code&gt; stays &lt;code&gt;[data-slot=button]&lt;/code&gt;. Only the trigger's own element is &lt;code&gt;popover-trigger&lt;/code&gt; or &lt;code&gt;hover-card-trigger&lt;/code&gt;. If you styled such a Button through &lt;code&gt;[data-slot=popover-trigger]&lt;/code&gt; or &lt;code&gt;[data-slot=hover-card-trigger]&lt;/code&gt;, select &lt;code&gt;[data-slot=button]&lt;/code&gt; instead. To lock such a trigger, put &lt;code&gt;Locked&lt;/code&gt; around it (&lt;code&gt;&amp;lt;Locked reason={…}&amp;gt;&amp;lt;PopoverTrigger render={&amp;lt;Button /&amp;gt;} /&amp;gt;&amp;lt;/Locked&amp;gt;&lt;/code&gt;), not in &lt;code&gt;render&lt;/code&gt;: &lt;code&gt;Locked&lt;/code&gt; passes on nothing the trigger gives it, so in &lt;code&gt;render&lt;/code&gt; the button would never open anything.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DataTable's selection boxes and ConsentCeremony's acknowledgement are Candor's &lt;code&gt;Checkbox&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;[data-slot=checkbox]&lt;/code&gt;, &lt;code&gt;role=&amp;quot;checkbox&amp;quot;&lt;/code&gt;), not &lt;code&gt;input[type=checkbox]&lt;/code&gt;, so the person's tick is drawn. The select-all box is &lt;code&gt;aria-checked=&amp;quot;mixed&amp;quot;&lt;/code&gt; when part of the page is selected. A test that read &lt;code&gt;.checked&lt;/code&gt; or fired &lt;code&gt;change&lt;/code&gt; on the input should find the box by role, read &lt;code&gt;aria-checked&lt;/code&gt;, and click it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;StreamingText&lt;/code&gt; (free)&lt;/strong&gt;, when a brand names a stream drawing (&lt;code&gt;--cd-show-stream&lt;/code&gt;, from the Pro &lt;code&gt;motion-drawings&lt;/code&gt; item), draws text that arrives after its first draw in &lt;code&gt;&amp;lt;span data-arrived&amp;gt;&lt;/code&gt; elements, which join the plain text as later chunks arrive. Without one it draws the text as one plain run, as in 4.3. With one, a &lt;code&gt;getByText&lt;/code&gt; on a whole reply while it streams can miss it: read the &lt;code&gt;[data-slot=streaming-text]&lt;/code&gt; element's &lt;code&gt;textContent&lt;/code&gt;, or use a function matcher.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;StatCard's figure&lt;/strong&gt; is &lt;code&gt;p[data-slot=stat-card-figure]&lt;/code&gt; holding &lt;code&gt;[data-slot=stat-card-value]&lt;/code&gt; (and a unit or an &amp;quot;Estimate&amp;quot; badge when the &lt;code&gt;Kpi&lt;/code&gt; has one), so only the number moves. &lt;code&gt;KpiRow&lt;/code&gt; with five or more cards is a &lt;code&gt;DashboardGrid&lt;/code&gt;, still &lt;code&gt;[data-slot=kpi-row]&lt;/code&gt;. CSS aimed at the figure's text should select &lt;code&gt;[data-slot=stat-card-value]&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DegradedPanel&lt;/code&gt;'s Retry (free)&lt;/strong&gt; is &lt;code&gt;aria-disabled&lt;/code&gt; inside &lt;code&gt;Locked&lt;/code&gt; while a retry runs, not &lt;code&gt;disabled&lt;/code&gt;. A test that expected it to be disabled should check &lt;code&gt;aria-disabled=&amp;quot;true&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;PlanPicker's Fewer seats (Pro)&lt;/strong&gt; is &lt;code&gt;aria-disabled&lt;/code&gt; at the fewest seats, not &lt;code&gt;disabled&lt;/code&gt;, and is described by why (the &amp;quot;At least …&amp;quot; line, or the new string &lt;code&gt;planPicker.atFewest&lt;/code&gt;); a press does nothing and focus stays on it. A test that expected it to be disabled should check &lt;code&gt;aria-disabled=&amp;quot;true&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ToolCall's row (free):&lt;/strong&gt; the line counts, badges, tool name, duration and chevron after the title are in a &lt;code&gt;span[data-slot=tool-call-meta]&lt;/code&gt;, which wraps to a line of its own on a narrow row; the title keeps at least 8rem and truncates. CSS that took those parts as the row's own children should select them inside &lt;code&gt;[data-slot=tool-call-meta]&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Some new items' controls have their own &lt;code&gt;data-slot&lt;/code&gt;:&lt;/strong&gt; ConfirmButton's button is &lt;code&gt;confirm-button-trigger&lt;/code&gt; (the wrapper is &lt;code&gt;confirm-button&lt;/code&gt;), and CorrectionOffer's Use and Keep are &lt;code&gt;correction-offer-accept&lt;/code&gt; and &lt;code&gt;correction-offer-dismiss&lt;/code&gt;, so brand CSS and drawings aimed at &lt;code&gt;[data-slot=button]&lt;/code&gt; don't reach them; select them by these slots. AccordionGallery's panel buttons are &lt;code&gt;accordion-gallery-trigger&lt;/code&gt; and CardDeck's focusable stack is &lt;code&gt;card-deck-stack&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Smaller DOM changes:&lt;/strong&gt; SetupChecklist's done tick is &lt;code&gt;svg[data-slot=setup-checklist-tick]&lt;/code&gt;, no longer lucide's &lt;code&gt;svg.lucide-check&lt;/code&gt;; RadioGroup's indicator is &lt;code&gt;absolute inset-0 flex&lt;/code&gt;, not &lt;code&gt;relative flex&lt;/code&gt;; SplitView's detail body is &lt;code&gt;div[data-slot=split-view-detail-body]&lt;/code&gt;; and DegradedPanel's Retry (free) always sits in &lt;code&gt;span[data-slot=locked][data-unlocked]&lt;/code&gt; (&lt;code&gt;display: contents&lt;/code&gt;), even when it isn't busy. Tests or CSS that matched &lt;code&gt;.lucide-check&lt;/code&gt;, or Retry as the panel's &lt;code&gt;&amp;gt; button&lt;/code&gt;, should select the new slots or find the button by role.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Toast's title and detail&lt;/strong&gt; are each in a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;. A &lt;code&gt;getByText&lt;/code&gt; on the text alone still finds them.&lt;/li&gt;&lt;li&gt;Added attributes, with nothing to do: tab triggers carry &lt;code&gt;data-tab-value&lt;/code&gt;; Switch's thumb carries &lt;code&gt;data-turned=&amp;quot;a&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;b&amp;quot;&lt;/code&gt; after a flip the person makes; the × of a Dialog, Sheet or Drawer, and the Close DialogFooter draws with &lt;code&gt;showCloseButton&lt;/code&gt;, carry &lt;code&gt;data-dismiss&lt;/code&gt;; chart marks carry &lt;code&gt;data-mark&lt;/code&gt;; Button sets &lt;code&gt;--cd-press-x&lt;/code&gt; and &lt;code&gt;--cd-press-y&lt;/code&gt; in its own style where a pointer pressed it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ComposerScopePicker&lt;/code&gt;&lt;/strong&gt;, a picker for where the next message's work lands, for Composer's &lt;code&gt;tools&lt;/code&gt;: scopes grouped by kind (environment, client, project, or personal, read &amp;quot;Just me&amp;quot;) in a &lt;code&gt;Popover&lt;/code&gt;, each with its icon and words, and production still a warning in words. The arrow keys, Home and End move without choosing. Props &lt;code&gt;scope&lt;/code&gt;, &lt;code&gt;scopes&lt;/code&gt;, &lt;code&gt;onScopeChange&lt;/code&gt;; types &lt;code&gt;ComposerScopeChoice&lt;/code&gt; (a &lt;code&gt;ComposerScope&lt;/code&gt; with &lt;code&gt;kind&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;) and &lt;code&gt;ComposerScopeKind&lt;/code&gt;; the pill's separator is the string &lt;code&gt;scopeChip&lt;/code&gt;. Scope names are neutralised and drawn in a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;. The free Composer's own &lt;code&gt;scope&lt;/code&gt; is unchanged from 4.3: leave it out when you use the picker.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The app frame:&lt;/strong&gt; &lt;code&gt;TopBar&lt;/code&gt;, the bar across the top of an app, with start, middle and end slots; the middle gives way below &lt;code&gt;compactAt&lt;/code&gt; of its own width. &lt;code&gt;NavRail&lt;/code&gt;, the app's places as icons above words, in groups, with a pinned foot; places that don't fit scroll while the foot stays; a count is read in the place's name (&amp;quot;Approvals, 3 waiting&amp;quot;) and filled only when urgent; &lt;code&gt;navRailTabs()&lt;/code&gt; makes &lt;code&gt;TabBar&lt;/code&gt;'s destinations from the same places, the ones the app picks, and &lt;code&gt;useNavRailTabs()&lt;/code&gt; does so in a component, naming a counted tab through the new string &lt;code&gt;navRail.waiting&lt;/code&gt; with the count in the locale's numbers, as the rail reads it. &lt;code&gt;ScopeSwitcher&lt;/code&gt;, where the person is working in one control: the name over the environment (production in words, in the warning colour), the mode the agent reports (&amp;quot;Changing to …&amp;quot; while another is asked for) and the connection in words; &lt;code&gt;compact&lt;/code&gt; leaves out the environment line but keeps production's icon and the word &amp;quot;Production&amp;quot;; its menu has a radio group per level, a level with no value says &amp;quot;Choose …&amp;quot; with nothing checked, and options take a &lt;code&gt;detail&lt;/code&gt; line and the menu &lt;code&gt;actions&lt;/code&gt;. &lt;code&gt;PersonMenu&lt;/code&gt;, the signed-in person's menu, as an avatar or a row: only the entries the app wires, a header with name and email, the theme as a radio group in &lt;code&gt;ThemeSetting&lt;/code&gt;'s words, and the app's own &lt;code&gt;choices&lt;/code&gt;, with nothing checked while a value is null. &lt;code&gt;NeedsYouLine&lt;/code&gt;, what waits on this person in one line: &amp;quot;Nothing needs you right now&amp;quot; only at a known zero, and &amp;quot;Couldn't check what needs you&amp;quot; with Retry when it isn't known; pass it the same count as the rail's badge.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Workspace:&lt;/strong&gt; &lt;code&gt;ScoreRing&lt;/code&gt;, a computed score as a figure, not a progressbar: &lt;code&gt;computedAt&lt;/code&gt; and &lt;code&gt;basis&lt;/code&gt; are required, the delta names its period, a null score says &amp;quot;Not computed&amp;quot; and why, and &lt;code&gt;projected&lt;/code&gt; draws a projected score apart, as a dashed arc with its basis. &lt;code&gt;PortfolioCard&lt;/code&gt;, one workspace in a portfolio: one link, its hue as identity only, what needs you in words, up to three figures, and an estimate labelled with its basis. &lt;code&gt;MonitorCard&lt;/code&gt;, a rule that watches something: its switch shows what the service reports and says &amp;quot;Turning on&amp;quot; or &amp;quot;Turning off&amp;quot; while it waits, and an unavailable monitor keeps its switch, locked with the reason. &lt;code&gt;EnvironmentList&lt;/code&gt;, the environments an app is connected to, with the connection in words, last sync, Set active, Reconnect, and a Disconnect that says in the row what stops and what stays before it acts; the buttons are named from the strings &lt;code&gt;environmentList.setActiveName&lt;/code&gt; (&amp;quot;Set active: {name}&amp;quot;), &lt;code&gt;reconnectName&lt;/code&gt; and &lt;code&gt;disconnectName&lt;/code&gt;. &lt;code&gt;Board&lt;/code&gt; and &lt;code&gt;BoardCard&lt;/code&gt;, a kanban board on &lt;code&gt;ReorderableList&lt;/code&gt;: column limits in words (&amp;quot;6 of 5, over the limit&amp;quot;), folding columns, one column at a time below 640 px of the board's width, agents drawn as agents, costs that say spent or estimated, and an agent's move with Undo, after which focus stays on the card.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Agents, admin and billing:&lt;/strong&gt; &lt;code&gt;ModelKey&lt;/code&gt;, the person's own key for a model provider: what a key unlocks, where data will go shown beside Add key, the key checked with the provider before it is stored, a refused key's reason with what to check, and once verified only its masked part; no provider is chosen for the person, on Replace too. &lt;code&gt;DriftChange&lt;/code&gt;, a change made outside the app: what changed and where, how severe in words, who made it (&amp;quot;Not attributed&amp;quot; drawn loudest), when (or that it isn't known), its diff, and Review, Adopt and Revert, each saying what it undoes; Revert confirms in place. &lt;code&gt;PlanGate&lt;/code&gt;, a feature the plan doesn't include: which plan has it, what it would show in words with no sample data, its controls drawn locked with the plan they need, and how to get it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Fields:&lt;/strong&gt; &lt;code&gt;FloatLabelInput&lt;/code&gt;, whose label rises out of the way and is always the field's &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;. &lt;code&gt;InputGroup&lt;/code&gt; with &lt;code&gt;InputGroupAddon&lt;/code&gt; and &lt;code&gt;InputGroupCount&lt;/code&gt;, a field with addons and a count against a limit that is announced only near and past it. &lt;code&gt;MaskedInput&lt;/code&gt;, a field shaped by a pattern or grouped digits in the locale's way, that reads a paste through the mask and says its format. &lt;code&gt;ConfirmField&lt;/code&gt;, a second entry judged on leaving it or after a pause. &lt;code&gt;StrengthMeter&lt;/code&gt;, which needs the &lt;code&gt;basis&lt;/code&gt; it was measured by and says &amp;quot;Not checked&amp;quot; for &lt;code&gt;null&lt;/code&gt;. &lt;code&gt;CorrectionOffer&lt;/code&gt;, a correction applied only when the person accepts it (&amp;quot;Use …&amp;quot;, &amp;quot;Keep …&amp;quot;), its reason neutralised as untrusted text. &lt;code&gt;SliderMarks&lt;/code&gt;, a slider with marks, detents and a readout; on a labelled mark the value is read with the mark's word (&amp;quot;1.0, Default&amp;quot;, the new string &lt;code&gt;sliderMarks.valueAtMark&lt;/code&gt;). &lt;code&gt;LinkPreview&lt;/code&gt;, a link with another site's preview on hover and focus; the link's scheme and host always show whole, and only the path after them is cut.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Buttons:&lt;/strong&gt; &lt;code&gt;ResultButton&lt;/code&gt;, whose face reports the real result once the work settles. &lt;code&gt;ProgressButton&lt;/code&gt;, whose fill is the measured progress, never past it; with unknown progress it says so, and a failed file's bar is empty, in forced colours too. Either, while &lt;code&gt;aria-disabled&lt;/code&gt; or inside &lt;code&gt;Locked&lt;/code&gt;, stays focusable, says why and does nothing when pressed. &lt;code&gt;ConfirmButton&lt;/code&gt;, which asks for a second, separate press (a double-click or a held Enter arms it at most), says what can be undone, disarms on Escape, blur or its timer, and shows &amp;quot;Done&amp;quot; only once &lt;code&gt;onConfirm&lt;/code&gt; resolves.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;For show:&lt;/strong&gt; &lt;code&gt;FlipCard&lt;/code&gt;, a card with two faces turned by a button that keeps focus. &lt;code&gt;CardDeck&lt;/code&gt;, a stack of cards to go through one at a time, by buttons, arrow keys or a drag, each step announced; a press becomes a drag only once it has moved 6 px, so a button or link in a card takes its click. &lt;code&gt;AccordionGallery&lt;/code&gt;, panels side by side, one open at a time, a column when narrow; a panel whose content holds focus stays wide whatever the pointer passes over, and when narrow the open panel's content is still reached by Tab. &lt;code&gt;StepCapsules&lt;/code&gt;, &lt;code&gt;StepList&lt;/code&gt;'s steps as a wrapping row of small cards. &lt;code&gt;TypedText&lt;/code&gt;, the app's own words typing out once as the page first draws, with &lt;code&gt;--cd-show-typing: type&lt;/code&gt;; a key, a press or a focus finishes it. &lt;code&gt;Loader&lt;/code&gt;, which turns only while the work runs and is heard from, stops and says &amp;quot;Not heard from since …&amp;quot; past &lt;code&gt;staleAfter&lt;/code&gt;, and stops when &lt;code&gt;status&lt;/code&gt; says the work is over; its shape is &lt;code&gt;shape&lt;/code&gt; or &lt;code&gt;--cd-draw-loader&lt;/code&gt;, and its turning is a &lt;code&gt;live&lt;/code&gt; moment of its own, so a brand's &lt;code&gt;--cd-motion-loader-turning&lt;/code&gt; and its &lt;code&gt;-dur&lt;/code&gt; reach every shape.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;GlideHighlight&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;ui/&lt;/code&gt;), the box that travels behind the item under the pointer in DropdownMenu, Tabs, AppSidebar and NavRail when a brand sets &lt;code&gt;--cd-draw-highlight&lt;/code&gt;; for your own lists too.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;AppLayout (Pro) &lt;code&gt;frame=&amp;quot;app&amp;quot;&lt;/code&gt;:&lt;/strong&gt; one chrome in an L round an inset canvas. &lt;code&gt;brand&lt;/code&gt; is the banner's first child, laid into the navigation's column, so it sits over the rail level with the top bar; the navigation (a &lt;code&gt;NavRail&lt;/code&gt;, or an &lt;code&gt;AppSidebar&lt;/code&gt; as the wider arm) runs full height beside the page; only the canvas scrolls. The canvas is &lt;code&gt;[data-slot=app-layout-canvas]&lt;/code&gt;, round the page, the panel and the quick chat, and is drawn from three new tokens: &lt;code&gt;--cd-canvas&lt;/code&gt; (from &lt;code&gt;--background&lt;/code&gt;), &lt;code&gt;--cd-canvas-border&lt;/code&gt; (from &lt;code&gt;--border&lt;/code&gt;) and &lt;code&gt;--cd-canvas-radius&lt;/code&gt; (from &lt;code&gt;--cd-radius-xl&lt;/code&gt;), with the corner where the L's arms meet. Theme it flat (the canvas on &lt;code&gt;var(--sidebar)&lt;/code&gt;, a transparent border, a radius of 0) or sunken (&lt;code&gt;var(--cd-sunken)&lt;/code&gt; in a &lt;code&gt;--sidebar: var(--card)&lt;/code&gt; chrome). Below &lt;code&gt;sidebarAt&lt;/code&gt; the banner holds the brand, the menu button and &lt;code&gt;top&lt;/code&gt;. In this frame AppSidebar leaves out its own brand. The page frame, the default, draws the same DOM as 4.3. &lt;code&gt;hideHeader=&amp;quot;on-scroll&amp;quot;&lt;/code&gt; hides the banner (in the app frame, the whole row, brand included) as the page scrolls down and brings it back on a scroll up or a focus inside; it stays while focus is in it or a menu from it is open, the very end of the page doesn't bring it back, and in the app frame the navigation and the page still reach the frame's bottom while it is hidden. It is off by default in both frames, and &lt;code&gt;useHideOnScroll&lt;/code&gt; does the same for an app's own header. &lt;code&gt;--cd-nav-rail-width&lt;/code&gt; sets the rail's width.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;TabBar (Pro):&lt;/strong&gt; &lt;code&gt;TabBarDestination.badgeLabel&lt;/code&gt; names a destination with a badge in your words (&amp;quot;Approvals, 3 waiting&amp;quot;) where TabBar's &amp;quot;3 new&amp;quot; would be false; &lt;code&gt;navRailTabs&lt;/code&gt; sets it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;StatCard and KpiRow (Pro):&lt;/strong&gt; &lt;code&gt;Kpi&lt;/code&gt; gains optional &lt;code&gt;unit&lt;/code&gt; (drawn after the figure and read with it: &amp;quot;2.4M records&amp;quot;), &lt;code&gt;note&lt;/code&gt; (a second line in words) and &lt;code&gt;estimate: { basis }&lt;/code&gt; (the card says &amp;quot;Estimate&amp;quot;, read as &amp;quot;estimated&amp;quot;, and the basis in words). StatCard takes &lt;code&gt;icon&lt;/code&gt;; KpiRow takes &lt;code&gt;iconOf&lt;/code&gt; and lays five or more cards out through &lt;code&gt;DashboardGrid&lt;/code&gt;, in the fewest rows that hold them, as even as the width allows: five where four fit are three and two. A card still sits alone where one column is all that fits, or two for an odd number of cards, and until the row is measured (as the server draws it) it is as many columns as fit. &lt;code&gt;useCountUp&lt;/code&gt; is exported from &lt;code&gt;stat-card&lt;/code&gt; for your own figures. A 4.3 &lt;code&gt;Kpi&lt;/code&gt; draws as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ToolCall (free):&lt;/strong&gt; &lt;code&gt;ToolCall.lines: { added, removed }&lt;/code&gt;, when a tool counted the lines it changed, shows &amp;quot;+12 −3&amp;quot;, read as &amp;quot;12 lines added, 3 removed&amp;quot;. Left out, nothing is drawn; it is never estimated. On a narrow row the title keeps at least 8rem and truncates, and what follows it wraps to a line of its own, so a row fits a 320 px screen (see the DOM list).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SessionList (Pro):&lt;/strong&gt; &lt;code&gt;Session.context&lt;/code&gt;, an entity the thread is about, drawn as an &lt;code&gt;EntityChip&lt;/code&gt; under the row's second line and read as the row's description. A pinned thread slides to its group, and focus stays on it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ThreadHeader (Pro):&lt;/strong&gt; its &lt;code&gt;scope&lt;/code&gt; takes a &lt;code&gt;kind&lt;/code&gt; (&amp;quot;environment&amp;quot;, &amp;quot;client&amp;quot;, &amp;quot;project&amp;quot; or &amp;quot;personal&amp;quot;) as &lt;code&gt;ThreadHeaderScope&lt;/code&gt;, drawn with the kind's icon and words; a personal scope reads &amp;quot;Just me&amp;quot;, and production is still a warning. A scope without &lt;code&gt;kind&lt;/code&gt; draws as in 4.3.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DataTable (Pro):&lt;/strong&gt; &lt;code&gt;stackBelow&lt;/code&gt; draws each row as a card of labelled values when the table itself is narrower than that many pixels; selection, details, groups, paging and totals keep working, each card's box is named by its row (&amp;quot;Select Alpha&amp;quot;, the new string &lt;code&gt;dataTable.selectRowNamed&lt;/code&gt;), and without it the table draws the same DOM. The select-all box shows a dash when part of the page is selected.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DetailsList (Pro):&lt;/strong&gt; &lt;code&gt;layout=&amp;quot;grid&amp;quot;&lt;/code&gt; lays rows out as cells, label over value, in as many columns as fit; &lt;code&gt;code&lt;/code&gt; values are identifiers (left to right, never translated); &lt;code&gt;DetailRow.copy&lt;/code&gt; adds a &amp;quot;Copy {label}&amp;quot; control that says &amp;quot;Copied&amp;quot; only once the clipboard took the value.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SubscoreCard (Pro):&lt;/strong&gt; &lt;code&gt;layout=&amp;quot;tiles&amp;quot;&lt;/code&gt;: each subscore's tone as a dot with the app's word, its full name, &amp;quot;74 / 100&amp;quot;, its weight and its findings in words. &lt;code&gt;SubscoreTile&lt;/code&gt; extends &lt;code&gt;Subscore&lt;/code&gt;, so 4.3 arrays still fit. Fixed from 4.3: the bars drew their scores, the total and their weight as raw numbers while screen readers heard them formatted, so under a locale such as ar-EG the two disagreed; tiles and bars now format them through &lt;code&gt;LocaleProvider&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ReorderableList (Pro)&lt;/strong&gt; gains &lt;code&gt;groupHeader&lt;/code&gt;, &lt;code&gt;collapsed&lt;/code&gt; and &lt;code&gt;onCollapsedChange&lt;/code&gt;; a folded group is still a target for the menu and the arrow keys. Without them it draws the same DOM. Fixed from 4.3: a menu move into another group announced the wrong count, and a pointer drag into another group stayed held instead of dropping. And when the app moves an item while a control inside it has focus, and that control isn't drawn again, focus now goes to the item's handle in its new place instead of the page.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Dialog, Sheet and Drawer (Pro):&lt;/strong&gt; &lt;code&gt;Dialog&lt;/code&gt; and &lt;code&gt;Sheet&lt;/code&gt; take &lt;code&gt;onDismissAttempt&lt;/code&gt; (return &lt;code&gt;false&lt;/code&gt; to stay open), as the drawer does, and &lt;code&gt;DialogContent&lt;/code&gt;, &lt;code&gt;SheetContent&lt;/code&gt;, &lt;code&gt;DrawerContent&lt;/code&gt; and &lt;code&gt;ResponsiveDialogContent&lt;/code&gt; take &lt;code&gt;unsaved&lt;/code&gt; (&amp;quot;your reply&amp;quot;): a dismissal (Escape, the ×, or the Close DialogFooter draws) then asks first, in a bar in the window, and a refused press outside rings the window. ResponsiveDialog passes both on. &lt;code&gt;DialogContent from=&amp;quot;trigger&amp;quot;&lt;/code&gt; lets the window grow from its trigger with the Pro &lt;code&gt;morph&lt;/code&gt; drawing. The drawer's backdrop follows the drag, and &lt;code&gt;DrawerSwipeArea&lt;/code&gt; opens it by a finger's swipe in from its edge (the trigger stays the way in for everyone): a 12 px strip, not drawn while the drawer is open, that passes a tap that isn't a swipe to what is under it; keep scrolling content and small controls clear of that edge. Sheet and Drawer now import &lt;code&gt;ui/dialog&lt;/code&gt;, so updating them installs it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Drawer (Pro)&lt;/strong&gt; measures a fling from the drag's last 100 ms, not one move: a fast first move, or a twitch just before letting go, no longer closes it. A release is a fling when the pointer went at least 10 px toward the edge in that time.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Toast (Pro):&lt;/strong&gt; &lt;code&gt;toast.promise(promise, { pending, success, failure })&lt;/code&gt; says &lt;code&gt;pending&lt;/code&gt; with a spinner, is never dismissed while it waits, then shows its result (a failure stays until dismissed) and returns the promise; if a &lt;code&gt;success&lt;/code&gt; or &lt;code&gt;failure&lt;/code&gt; function throws, it settles on the new strings &lt;code&gt;toast.succeeded&lt;/code&gt; (&amp;quot;Done&amp;quot;) or &lt;code&gt;toast.failed&lt;/code&gt; (&amp;quot;That didn’t work&amp;quot;). A toast can be swiped toward the inline end to dismiss it (mirrored right to left), Escape dismisses the one with focus, and focus moves to the next toast or back where it was. The cap hides and counts instead of dropping (above). Fixed from 4.3: a timed toast ran on its clock with focus in it and dropped focus to the page. Its timer now waits while the pointer or focus is in it and runs on with the time it had left, and focus in a toast that goes any way (its timer, the cap, the app's &lt;code&gt;dismissToast&lt;/code&gt;) moves to the next toast or back where it was. A toast's title and detail, and &lt;code&gt;toast.promise&lt;/code&gt;'s texts, which can carry an error's message, are now neutralised and drawn in a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;, as are the words its live regions read.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CardDeck&lt;/strong&gt; neutralises the card names it announces (&lt;code&gt;labelOf&lt;/code&gt;, which may be an agent's).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;FilterChips (Pro):&lt;/strong&gt; Clear all no longer drops focus onto the page: it moves to the next control after the chips (else the one before), or to the new &lt;code&gt;focusAfterClear&lt;/code&gt; ref. FilterBar sends it to Add filter.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DegradedPanel (free):&lt;/strong&gt; Retry stays focusable while a retry runs and says &amp;quot;Already retrying&amp;quot;; it keeps focus when the retry starts. New string &lt;code&gt;degradedPanel.retryingLocked&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Forms and fields (Pro):&lt;/strong&gt; &lt;code&gt;Field&lt;/code&gt; takes &lt;code&gt;validating&lt;/code&gt; (&amp;quot;Checking…&amp;quot;) and &lt;code&gt;valid&lt;/code&gt;, the app's word that its check found nothing wrong: &amp;quot;Looks good&amp;quot; shows only while &lt;code&gt;valid&lt;/code&gt; is set, and is never inferred from a check that stopped or an error that was cleared, so clear &lt;code&gt;valid&lt;/code&gt; when the value changes. Its hint arrives when it appears or changes. &lt;code&gt;NumberInput&lt;/code&gt; takes &lt;code&gt;scrub&lt;/code&gt;, a grip the person drags to change the value (Shift for steps of ten, mirrored right to left); its docs example has a fine-tune card. Fixed from 4.3: a disabled, read-only or locked NumberInput still changed by its step buttons and arrow keys; now nothing changes it, the step buttons are &lt;code&gt;aria-disabled&lt;/code&gt; and described by what describes the field (&lt;code&gt;Locked&lt;/code&gt;'s reason), and the grip is inert. &lt;code&gt;ToolbarGroup&lt;/code&gt; takes &lt;code&gt;reveal&lt;/code&gt;, for a selection's actions, announced once. &lt;code&gt;SplitView&lt;/code&gt; takes &lt;code&gt;detailKey&lt;/code&gt;, so the detail arrives when the selection changes without remounting. &lt;code&gt;RunEstimate&lt;/code&gt; takes &lt;code&gt;endsAt&lt;/code&gt; and counts down to it in the locale's units, hours included (&amp;quot;Expected to end in 4m 12s&amp;quot;, the new string &lt;code&gt;runEstimate.endsIn&lt;/code&gt;), then says &amp;quot;Past its expected end&amp;quot;. PlanPicker's Fewer seats says why at the fewest seats and keeps focus (see the DOM list). PlanPicker, ScheduleEditor and RunEstimate follow the new &amp;quot;Values that depend on other values&amp;quot; pattern: only what the person changed moves, and the result is announced once after they stop. SetupChecklist draws a step's tick when it is confirmed done; RunScrubber shows the title of the event under the pointer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;UndoWindow (Pro)&lt;/strong&gt; takes &lt;code&gt;display=&amp;quot;ring&amp;quot;&lt;/code&gt;, a ring painted from the same clock as the bar.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Carousel (Pro)&lt;/strong&gt; takes &lt;code&gt;transition&lt;/code&gt;: slide (the default), fade, vertical, blur, zoom, uncover or fill. The stacked forms keep slides not shown &lt;code&gt;inert&lt;/code&gt; and hidden from screen readers; a change plays only when the person makes it. Fixed from 4.3: the arrow keys, Home and End changed slide when pressed anywhere in &lt;code&gt;CarouselContent&lt;/code&gt;, so in a field on a slide the caret and the slide moved at once; they now change slide only from the slides' own tab stop.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ChartFrame (Pro)&lt;/strong&gt;, while &lt;code&gt;busy&lt;/code&gt;, says &amp;quot;Refreshing&amp;quot; in its header beside a turning icon. New string &lt;code&gt;chartFrame.refreshing&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;EnvironmentConnect (Pro)&lt;/strong&gt; takes &lt;code&gt;hold&lt;/code&gt;, for when the other side has to act first: &lt;code&gt;&amp;quot;waiting&amp;quot;&lt;/code&gt; (an admin there must approve the app, with who, where and when it was asked and checked, and &lt;code&gt;onCheckAgain&lt;/code&gt;) or &lt;code&gt;&amp;quot;blocked&amp;quot;&lt;/code&gt; (their policy blocks it, and who can unblock it). The hold stands in place of the ways of connecting; &lt;code&gt;onBack&lt;/code&gt; is the app's way back. Without &lt;code&gt;hold&lt;/code&gt;, nothing changes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;RadioGroup, ClarifyingQuestions and FormErrorSummary (Pro)&lt;/strong&gt; gain moments a brand can draw: a dot when the person presses a radio (never for the arrow keys or the app's choice), ticks, dots and a step in ClarifyingQuestions, and a ring on FormErrorSummary when a submit fails on screen. Nothing changes without a brand value.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ClarifyingQuestions (Pro):&lt;/strong&gt; fixed from 4.3, an agent's question id that is also a property of every object (&lt;code&gt;constructor&lt;/code&gt;, &lt;code&gt;__proto__&lt;/code&gt;) was read through the prototype, so &amp;quot;Other&amp;quot; showed as picked before the person chose anything; answers are now read as the question's own keys only.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Free hooks, inert alone:&lt;/strong&gt; &lt;code&gt;Switch&lt;/code&gt;'s thumb carries &lt;code&gt;data-turned&lt;/code&gt; after each flip the person makes, Button notes where a pointer pressed it (&lt;code&gt;--cd-press-x&lt;/code&gt;, &lt;code&gt;--cd-press-y&lt;/code&gt;), and &lt;code&gt;StreamingText&lt;/code&gt;, when a stream drawing is named, marks newly arrived text with &lt;code&gt;data-arrived&lt;/code&gt; for 600 ms. The free kit draws none of them; &lt;code&gt;motion-drawings&lt;/code&gt; does, and its file's header names them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The &lt;code&gt;attention&lt;/code&gt; family&lt;/strong&gt; takes Pro drawings through the new &lt;code&gt;--cd-motion-attention-variant&lt;/code&gt;, which falls back to &lt;code&gt;cd-ring&lt;/code&gt;; nothing changes without a brand value.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Motion (Pro &lt;code&gt;motion-drawings&lt;/code&gt;)&lt;/h3&gt;&lt;p&gt;Everything here is off until a brand file names it, off at the Off level, under calm where it says so and under reduced motion, and ends on the real content.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Fixed: 4.1's chart draw-in never reached the charts from 4.2 on.&lt;/strong&gt; Its rule selected &lt;code&gt;svg[role=&amp;quot;img&amp;quot;]&lt;/code&gt;, and since 4.2 the bar, line and donut charts draw &lt;code&gt;svg[role=&amp;quot;group&amp;quot;]&lt;/code&gt;. &lt;code&gt;cd-show-draw&lt;/code&gt; now reaches them. A brand that set &lt;code&gt;--cd-show-charts: cd-show-draw&lt;/code&gt; sees its charts draw in.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Fixed: clip-path draw-ins appeared at the halfway point.&lt;/strong&gt; 4.1's chart draw-in and the &lt;code&gt;wipe&lt;/code&gt; drawing, like 4.4's sweep, grow and the carousel's uncover and fill, hid the element for the first half of their run and then showed it whole. They now draw along their whole run.&lt;/li&gt;&lt;li&gt;**Show (&lt;code&gt;--cd-show-*&lt;/code&gt;):** &lt;code&gt;--cd-show-entrance&lt;/code&gt; gains &lt;code&gt;cd-show-bounce&lt;/code&gt;. &lt;code&gt;--cd-show-lists&lt;/code&gt; (&lt;code&gt;cd-show-fade&lt;/code&gt;, &lt;code&gt;-rise&lt;/code&gt;, &lt;code&gt;-scale&lt;/code&gt;, &lt;code&gt;-blur&lt;/code&gt;, &lt;code&gt;-bounce&lt;/code&gt;) brings a dashboard grid's tiles, a stack's children, a details list's rows and a data table's body rows in one after another as the page first draws. &lt;code&gt;--cd-show-overlay-content: stagger&lt;/code&gt; brings an opening dialog's, sheet's, drawer's or menu's parts in from 0.4 opacity, never from nothing. &lt;code&gt;--cd-show-charts&lt;/code&gt; gains &lt;code&gt;cd-show-sweep&lt;/code&gt; (donuts and score rings sweep round from 12 o'clock) and &lt;code&gt;cd-show-grow&lt;/code&gt; (bars grow from their baseline); &lt;code&gt;--cd-show-points: pop&lt;/code&gt; pops a line chart's points in after its line; progress rings and bullet bars fill from empty in the first-draw window when the brand also sets an entrance, lists or numbers. &lt;code&gt;--cd-show-numbers: count&lt;/code&gt; counts a stat card's figure up as the page first draws, ending on the measured figure. &lt;code&gt;--cd-show-stream&lt;/code&gt; (words, blur, rise, pop) draws a streaming reply's chunks as they arrive (pop keeps each line breaking where it would without it), and &lt;code&gt;--cd-show-typing: type&lt;/code&gt; turns on &lt;code&gt;TypedText&lt;/code&gt;. &lt;code&gt;--cd-show-hover&lt;/code&gt; gains shadow, border and background hovers (shadow-fade, shadow-grow, shadow-bounce, shadow-drop, shadow-rise, shadow-sweep, shadow-settle, border-thicken, border-draw, border-split, border-converge, border-pulse, bg-tint, bg-slide, bg-rise, bg-bloom, bg-diagonal) and tilt, and now reaches DashboardTile, lift and glow included. &lt;code&gt;--cd-show-image&lt;/code&gt; (zoom, pan, tilt, focus, scrim) moves an image in a Card or AttachmentPreview inside its own box. &lt;code&gt;--cd-show-backdrop: scale | push&lt;/code&gt; moves the page behind an open dialog, sheet or drawer.&lt;/li&gt;&lt;li&gt;**Drawings on controls (&lt;code&gt;--cd-draw-*&lt;/code&gt;, in the builder's &amp;quot;Controls · Pro&amp;quot; group):** &lt;code&gt;--cd-draw-switch&lt;/code&gt; (spring, bouncy, elastic, wind-up, swell, coin, skew, blur, fade) for the thumb. &lt;code&gt;--cd-draw-button-hover&lt;/code&gt; (wipe, two-tone, centre, side, pinch, slide-out, collapse, skew, arrow-sweep, shine, zoom, flood, circle, frame, glow), &lt;code&gt;--cd-draw-button-icon&lt;/code&gt; (nudge, fly, roll, morph, expand) and &lt;code&gt;--cd-draw-button-press&lt;/code&gt; (spring, ripple), never on a link, a locked, disabled or &lt;code&gt;aria-disabled&lt;/code&gt; button, or in forced colours. &lt;code&gt;--cd-draw-focus: ripple&lt;/code&gt; on keyboard focus. &lt;code&gt;--cd-draw-input-focus&lt;/code&gt; (underline, sweep, border, expand, lift, ring, glow) for Input, Textarea and OneTimeCode taking focus, drawn on an InputGroup as a whole; none changes a field's size (FloatLabelInput's and taller fields' included), lift and glow follow the field's box, not its letters, an invalid field keeps its red border (expand draws its edge in red there), and the focus ring stays. &lt;code&gt;--cd-draw-highlight&lt;/code&gt; (glide, ease, bouncy, slow, pop) and &lt;code&gt;--cd-draw-row-hover&lt;/code&gt; (wipe, wipe-end, wipe-centre, curtain-down, curtain-up, blur, slide, scale) for menus, sidebars, the rail, tabs and table rows. &lt;code&gt;--cd-draw-loader&lt;/code&gt; for Loader's shapes (ring, dots, bars, grid, drive, orbit, pixel, equaliser, wave), and &lt;code&gt;--cd-draw-progress&lt;/code&gt; (travel, refill, stripes) for the free Progress's indeterminate bar, which is unchanged; refill never fills the track.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New family drawings, for a &lt;code&gt;-variant&lt;/code&gt; token:&lt;/strong&gt; for opening and arriving, &lt;code&gt;curtain&lt;/code&gt; and &lt;code&gt;clip&lt;/code&gt; (reveal, overlay), &lt;code&gt;circle&lt;/code&gt;, &lt;code&gt;roll&lt;/code&gt;, &lt;code&gt;stretch&lt;/code&gt;, &lt;code&gt;slide-scale&lt;/code&gt;, &lt;code&gt;blur-slide&lt;/code&gt;, &lt;code&gt;elastic-slide&lt;/code&gt; and &lt;code&gt;flip-x&lt;/code&gt; (overlay, arrive), and &lt;code&gt;height&lt;/code&gt;, &lt;code&gt;zoom-through&lt;/code&gt; and &lt;code&gt;uncover&lt;/code&gt; (overlay); &lt;code&gt;morph&lt;/code&gt; (overlay), for &lt;code&gt;DialogContent from=&amp;quot;trigger&amp;quot;&lt;/code&gt;; &lt;code&gt;slide-from&lt;/code&gt; (arrive), tab panels coming in from the chosen tab's side; &lt;code&gt;carousel-fade&lt;/code&gt;, &lt;code&gt;-vertical&lt;/code&gt;, &lt;code&gt;-blur&lt;/code&gt;, &lt;code&gt;-zoom&lt;/code&gt;, &lt;code&gt;-uncover&lt;/code&gt; and &lt;code&gt;-fill&lt;/code&gt;; for ticks and dots, &lt;code&gt;fade&lt;/code&gt;, &lt;code&gt;zoom&lt;/code&gt;, &lt;code&gt;spin-in&lt;/code&gt;, &lt;code&gt;jelly&lt;/code&gt;, &lt;code&gt;tick-rise&lt;/code&gt;, &lt;code&gt;swing&lt;/code&gt; and &lt;code&gt;blur&lt;/code&gt; (mark), and &lt;code&gt;jelly&lt;/code&gt;, &lt;code&gt;rise&lt;/code&gt; and &lt;code&gt;ripple&lt;/code&gt; (pop), for example &lt;code&gt;--cd-motion-checkbox-tick-variant: cd-spin-in&lt;/code&gt;; &lt;code&gt;jolt&lt;/code&gt;, the error shake, and &lt;code&gt;beat&lt;/code&gt; (attention), for example &lt;code&gt;--cd-motion-input-invalid-variant: cd-jolt&lt;/code&gt;; &lt;code&gt;flash&lt;/code&gt; and six number drawings, &lt;code&gt;number-flip&lt;/code&gt;, &lt;code&gt;-blur&lt;/code&gt;, &lt;code&gt;-pop&lt;/code&gt;, &lt;code&gt;-drop&lt;/code&gt;, &lt;code&gt;-zoom&lt;/code&gt; and &lt;code&gt;-skew&lt;/code&gt; (value), where an increase rolls up and a decrease rolls down; on a field such as NumberInput only the text moves, and the box stays in place.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Pro eases,&lt;/strong&gt; named in a &lt;code&gt;-ease&lt;/code&gt; token as &lt;code&gt;var(--cd-ease-&amp;lt;word&amp;gt;)&lt;/code&gt;: &lt;code&gt;stiff&lt;/code&gt;, &lt;code&gt;snappy&lt;/code&gt; and &lt;code&gt;gentle&lt;/code&gt;, and &lt;code&gt;bouncy&lt;/code&gt; and &lt;code&gt;wobbly&lt;/code&gt;, which overshoot (move, pop, arrive); &lt;code&gt;anticipate&lt;/code&gt;, &lt;code&gt;linear-travel&lt;/code&gt; and &lt;code&gt;snap&lt;/code&gt; (move); &lt;code&gt;stepped&lt;/code&gt; and &lt;code&gt;settle&lt;/code&gt; (fill, never past the value). No overshooting ease is ever allowed on a measured value.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Moments that play these:&lt;/strong&gt; tab panels arrive when the person chooses a tab; NumberInput's step buttons play its value moment; DataTable plays &lt;code&gt;changed&lt;/code&gt; on a cell whose value changes (not on first draw or paging), keeping the cell's element and any focus in it; ToolCall's line counts play &lt;code&gt;value:lines&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Typing effects draw only text already on the page: text a person types into a native field isn't drawn character by character.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 2.3.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme check&lt;/code&gt; reads what &lt;code&gt;motion-drawings&lt;/code&gt; adds in 4.4&lt;/strong&gt; (also the docs MCP's &lt;code&gt;theme_check&lt;/code&gt;): a &lt;code&gt;-ease&lt;/code&gt; of &lt;code&gt;var(--cd-ease-&amp;lt;word&amp;gt;)&lt;/code&gt; is accepted for the families that ease lists, with a note naming the item and saying that without it the family's easing, or Candor's own, is used; on another family it warns and names the families it is for; an ease that overshoots on a family that can't is the &lt;code&gt;motion-spring&lt;/code&gt; error, as &lt;code&gt;spring&lt;/code&gt; is. The &lt;code&gt;attention&lt;/code&gt; family's &lt;code&gt;-variant&lt;/code&gt; token and its drawings are known, and so are the &lt;code&gt;--cd-draw-*&lt;/code&gt; tokens, from the token manifest. A 4.3 project's file reads as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme check&lt;/code&gt; treats &lt;code&gt;candor-motion-drawings.css&lt;/code&gt; as Candor's,&lt;/strong&gt; as it does &lt;code&gt;candor.css&lt;/code&gt;. It followed the app's &lt;code&gt;@import&lt;/code&gt; of the file and checked it as the app's own CSS, with warnings telling you to remove lines the drawings need: about 290 on a clean 4.4 install (24 with 4.3's file). A clean install now shows none, and the app's own lines beside the import are still checked.&lt;/li&gt;&lt;li&gt;&lt;code&gt;lint&lt;/code&gt; knows the new items. &lt;code&gt;ProgressButton&lt;/code&gt;, &lt;code&gt;ConfirmButton&lt;/code&gt;, &lt;code&gt;InputGroup&lt;/code&gt;, &lt;code&gt;InputGroupAddon&lt;/code&gt;, &lt;code&gt;LinkPreview&lt;/code&gt;, &lt;code&gt;MaskedInput&lt;/code&gt;, &lt;code&gt;TopBar&lt;/code&gt;, &lt;code&gt;NavRail&lt;/code&gt;, &lt;code&gt;Board&lt;/code&gt;, &lt;code&gt;BoardCard&lt;/code&gt; and &lt;code&gt;Loader&lt;/code&gt; are names other libraries and apps also use, so importing one doesn't by itself mark a file as using Candor.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;suggest_components&lt;/code&gt;&lt;/strong&gt; names a higher tier's item beside &amp;quot;Candor has no …&amp;quot; only when it matches two words of the task, or is named by one: &amp;quot;rich text editor for code&amp;quot; now names &lt;code&gt;code-editor&lt;/code&gt; alone, and &amp;quot;wysiwyg editor&amp;quot; names nothing. &amp;quot;A kanban board of tasks&amp;quot; now answers &lt;code&gt;board&lt;/code&gt;, and the gap that said Candor has no task board is gone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ColumnMapper's description&lt;/strong&gt; now says it maps the columns of an imported spreadsheet or CSV file to the object's fields, so &amp;quot;import a spreadsheet and map its columns to fields&amp;quot; leads with &lt;code&gt;column-mapper&lt;/code&gt;, then &lt;code&gt;data-import&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Screens:&lt;/strong&gt; app-shell's &amp;quot;Top bar and command palette&amp;quot; layout is now &amp;quot;Workspace frame&amp;quot; (AppLayout's app frame with NavRail, TopBar, ScopeSwitcher and PersonMenu). There is a new &lt;code&gt;home-dashboard&lt;/code&gt; screen (dashboard, quiet and phone layouts). A screen can name its running example, which &lt;code&gt;get_screen&lt;/code&gt; returns; both of these point at &lt;code&gt;/apps/workspace&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;A new pattern, &amp;quot;Values that depend on other values&amp;quot;. The design reference's Layout table lists the canvas tokens, and the accessibility page's motion paragraph covers drawings on controls, the loader and the indeterminate bar.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Theme builder&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&amp;quot;Page ground&amp;quot; and &amp;quot;Page corner&amp;quot;&lt;/strong&gt; theme AppLayout's app frame: the ground is the page, a card, sunken or the chrome (flat), and the corner none, small or large. Both are written to and read back from a brand file and a Share link, and named in the list of changes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&amp;quot;Fully round&amp;quot;&lt;/strong&gt; in a component's Shape section gives every radius 9999px, as round as its height allows: a composer can be a pill with no change to &lt;code&gt;composer.tsx&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The Pro drawings' tokens are listed under &amp;quot;Controls · Pro&amp;quot;, and Pro eases show in the easing menus as &amp;quot;(Pro)&amp;quot;, with a hint that without the item the family's easing, or Candor's own, is used.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site and repository&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;App examples, at /apps on the site:&lt;/strong&gt; whole apps built from Candor's free and Pro items on sample data, free to view, beside the hosted Premium templates; each names the items it is built from and their tiers. The chat app (&lt;code&gt;/apps/chat&lt;/code&gt;; &lt;code&gt;/app&lt;/code&gt; now redirects there) has threads grouped by what needs you, a permission prompt, a draft in the side panel, prompt suggestions, quick settings, sharing and a free-items-only thread. The workspace app (&lt;code&gt;/apps/workspace&lt;/code&gt;) shows the app frame with NavRail, TopBar, ScopeSwitcher and PersonMenu, and NeedsYouLine, StatCard's new fields, ScoreRing, SubscoreCard's tiles, DetailsList's grid, PortfolioCard, MonitorCard, EnvironmentList and ModelKey. The board app (&lt;code&gt;/apps/board&lt;/code&gt;) shows Board with agents as assignees and an agent's proposal before it moves a card someone else owns. The Build menu has App examples; links to &lt;code&gt;/app&lt;/code&gt; point at &lt;code&gt;/apps&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;/screens&lt;/code&gt;&lt;/strong&gt; shows the workspace frame layout and the new &lt;code&gt;home-dashboard&lt;/code&gt; screen, each with a link to its running example.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For maintainers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;candor-motion-drawings.css&lt;/code&gt; is assembled by &lt;code&gt;npm run theme&lt;/code&gt; from partials in &lt;code&gt;src/styles/motion-drawings/&lt;/code&gt;; 4.1's and 4.3's rules are &lt;code&gt;01-base.css&lt;/code&gt;, unchanged but for the ends of two keyframes, &lt;code&gt;cd-wipe&lt;/code&gt; and &lt;code&gt;cd-show-draw&lt;/code&gt; (the clip-path fix), which &lt;code&gt;theme.test.ts&lt;/code&gt;'s guard takes out before comparing the rest with 4.3.0's. A buyer still imports one file. The motion manifest reads &lt;code&gt;@draw&lt;/code&gt;, &lt;code&gt;@name&lt;/code&gt; and &lt;code&gt;@ease&lt;/code&gt; lines, &lt;code&gt;check:motion&lt;/code&gt; checks the partials, and the token manifest lists the &lt;code&gt;--cd-draw-*&lt;/code&gt; tokens.&lt;/li&gt;&lt;li&gt;Each stream's browser checks are a pair of files in &lt;code&gt;tests/browser/motion/&lt;/code&gt;; run one group with &lt;code&gt;node tests/browser/contracts.mjs --only &amp;lt;group&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.3.0</title>
      <link>https://candor.themethodic.com/changelog#4-3-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-3-0</guid>
      <pubDate>Thu, 12 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 2.2.1 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.3.0; nothing breaks. An app shell for phones and split views, form and navigation controls, richer tables and a reorderable list; a command palette on Base UI, which takes the last Radix packages out of your project; and the fixes 4.2's reviews and Storywrite asked for. The kit has 366 items: 74 free and 335 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; takes a 4.2 project to 4.3.0, with no codemod. In CI or a coding agent, where there is no terminal, pass &lt;code&gt;--differing keep&lt;/code&gt; (or &lt;code&gt;replace&lt;/code&gt;) so &lt;code&gt;update&lt;/code&gt; doesn't stop at a file of yours that the install would replace; &lt;code&gt;--dry-run&lt;/code&gt; says first whether it would. If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 4.3.0.&lt;/p&gt;&lt;p&gt;Some DOM your own CSS or tests may match has changed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Command, Combobox and CommandPalette no longer use &lt;code&gt;cmdk&lt;/code&gt;.&lt;/strong&gt; Their exports, props and keys are the same. Gone: the &lt;code&gt;cmdk-*&lt;/code&gt; attributes (&lt;code&gt;[cmdk-root]&lt;/code&gt;, &lt;code&gt;[cmdk-input]&lt;/code&gt;, &lt;code&gt;[cmdk-item]&lt;/code&gt;, &lt;code&gt;[cmdk-group]&lt;/code&gt;, &lt;code&gt;[cmdk-group-heading]&lt;/code&gt;, &lt;code&gt;[cmdk-label]&lt;/code&gt;, &lt;code&gt;[cmdk-list-sizer]&lt;/code&gt;) and the hidden &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; (the box is named by &lt;code&gt;aria-label&lt;/code&gt;, from &lt;code&gt;Command&lt;/code&gt;'s &lt;code&gt;label&lt;/code&gt;). The highlighted item has &lt;code&gt;data-highlighted&lt;/code&gt; instead of &lt;code&gt;data-selected=&amp;quot;true&amp;quot;&lt;/code&gt;; a disabled item has &lt;code&gt;data-disabled&lt;/code&gt; present (and &lt;code&gt;aria-disabled=&amp;quot;true&amp;quot;&lt;/code&gt;) instead of &lt;code&gt;&amp;quot;true&amp;quot;&lt;/code&gt;/&lt;code&gt;&amp;quot;false&amp;quot;&lt;/code&gt;. Groups are &lt;code&gt;[data-slot=command-group]&lt;/code&gt;, headings &lt;code&gt;[data-slot=command-group-heading]&lt;/code&gt;. Items keep the order you gave them instead of being sorted by score, and the default match is every typed word appearing in the value or keywords, ignoring case and accents, instead of cmdk's fuzzy match; pass &lt;code&gt;filter&lt;/code&gt; for your own. Items sit in a &lt;code&gt;[data-slot=command-group-items]&lt;/code&gt; element (&lt;code&gt;role=&amp;quot;group&amp;quot;&lt;/code&gt;) inside each group, and there is no &lt;code&gt;--cmdk-list-height&lt;/code&gt;. &lt;code&gt;CommandEmpty&lt;/code&gt; now announces its words once as typing empties the list, so a &lt;code&gt;getByText&lt;/code&gt; on them finds them twice: scope it to &lt;code&gt;[data-slot=command-empty]&lt;/code&gt;. Replace &lt;code&gt;data-[selected=true]:&lt;/code&gt; with &lt;code&gt;data-highlighted:&lt;/code&gt; and &lt;code&gt;[cmdk-item]&lt;/code&gt; with &lt;code&gt;[data-slot=command-item]&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; always draws its wrapper&lt;/strong&gt; &lt;code&gt;span[data-slot=locked]&lt;/code&gt;, with &lt;code&gt;display: contents&lt;/code&gt; and &lt;code&gt;data-unlocked&lt;/code&gt; when there is no reason, so a control isn't drawn anew when a reason comes or goes. If your CSS selects a parent's children (&lt;code&gt;&amp;gt; *&lt;/code&gt;, &lt;code&gt;:first-child&lt;/code&gt;) around a locked control, also select &lt;code&gt;[data-slot=locked] &amp;gt; *&lt;/code&gt;; a test that took the control as its container's first child should find it by its own &lt;code&gt;data-slot&lt;/code&gt;. A control inside &lt;code&gt;Locked&lt;/code&gt; keeps its own &lt;code&gt;data-slot&lt;/code&gt;: before 4.3, a locked one took the tooltip trigger's &lt;code&gt;data-slot=&amp;quot;tooltip-trigger&amp;quot;&lt;/code&gt;, so a locked Switch or Checkbox lost its checked state in forced colours. &lt;code&gt;TooltipTrigger&lt;/code&gt; now sets its slot only on a button of its own; if your CSS reached a control through &lt;code&gt;[data-slot=&amp;quot;tooltip-trigger&amp;quot;]&lt;/code&gt;, use the control's own slot.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DataTable's root &lt;code&gt;section&lt;/code&gt; has &lt;code&gt;tabIndex=&amp;quot;-1&amp;quot;&lt;/code&gt;&lt;/strong&gt;, so focus has somewhere to go when a row's detail closes; with &lt;code&gt;renderDetail&lt;/code&gt; a virtualised table's rows sit in one &lt;code&gt;tbody&lt;/code&gt; each, and with &lt;code&gt;groupBy&lt;/code&gt; each group is a &lt;code&gt;tbody&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Every dialog is capped at the viewport's height less 2 rem and scrolls inside&lt;/strong&gt; rather than running off the screen.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ProfileSettings&lt;/code&gt;' theme field&lt;/strong&gt; is a &lt;code&gt;ThemeSetting&lt;/code&gt;, with a &lt;code&gt;data-slot=&amp;quot;theme-setting&amp;quot;&lt;/code&gt; wrapper round the same label and trigger.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Shell:&lt;/strong&gt; &lt;code&gt;TabBar&lt;/code&gt;, a phone's bottom bar of up to five places, each with its word; give it to AppLayout's &lt;code&gt;tabBar&lt;/code&gt; and below &lt;code&gt;tabBarAt&lt;/code&gt; (640 px) it replaces the menu button, its More opening the sidebar. AppLayout's &lt;strong&gt;quick chat&lt;/strong&gt;, &lt;code&gt;chat={{ content, label }}&lt;/code&gt;, draws a chat with the agent beside the page or over it and keeps its thread when it is closed or moved (below &lt;code&gt;chatAt&lt;/code&gt;, 900 px, it is drawn over the page); &lt;code&gt;useAppLayout()&lt;/code&gt; gives your own buttons the frame's state. &lt;code&gt;SplitView&lt;/code&gt;, a list and its detail side by side when there is room and one at a time when there isn't, with a Back button that says where it goes; the list keeps its state, scroll position and focus. &lt;code&gt;DockWindow&lt;/code&gt;, content the person can float in a window over the page and bring back without losing its state, inside another library's dialog too; &lt;code&gt;useDockMorph&lt;/code&gt; gives your own docking the same slide. &lt;code&gt;useAutoDensity(choice?)&lt;/code&gt;, the value for &lt;code&gt;data-density&lt;/code&gt;: &amp;quot;spacious&amp;quot; for a touch pointer under &amp;quot;auto&amp;quot;, or the person's own choice. &lt;code&gt;ThemeSetting&lt;/code&gt;, the theme choice on its own (Match my system, Light, Dark, High contrast), controlled, nothing chosen without a value.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Forms:&lt;/strong&gt; &lt;code&gt;ChoiceCardGroup&lt;/code&gt; and &lt;code&gt;ChoiceCard&lt;/code&gt;, a radio group drawn as cards, as many across as the group's width allows; nothing is chosen until the person chooses, and a locked card stays in the arrow order and says why. &lt;code&gt;ButtonGroup&lt;/code&gt;, &lt;code&gt;ButtonGroupSeparator&lt;/code&gt; and &lt;code&gt;ButtonGroupText&lt;/code&gt; join buttons into one control, in a row or a column, right to left too. &lt;code&gt;DateField&lt;/code&gt; and &lt;code&gt;DateRangeField&lt;/code&gt; read a typed date in the order the locale writes dates, and ISO always, say in words which date they read, and never guess one they can't read. &lt;code&gt;SliderStops&lt;/code&gt;, a slider over named stops that reads the stop's name and chooses nothing until moved (the free &lt;code&gt;Slider&lt;/code&gt; doesn't change). &lt;code&gt;DualListbox&lt;/code&gt; moves options between Available and Chosen with keys or buttons that say what, how many and why not; each move is announced.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Navigation:&lt;/strong&gt; &lt;code&gt;Toolbar&lt;/code&gt; and its parts, a row or column of controls that is one tab stop, the arrow keys swapped in right-to-left pages. &lt;code&gt;SearchInput&lt;/code&gt;, a named search field whose &lt;code&gt;onSearch&lt;/code&gt; hears the text once typing pauses, at once on Enter, and &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; when cleared, with &lt;code&gt;shortcut&lt;/code&gt;, &lt;code&gt;busy&lt;/code&gt;, and the number of results announced once a search settles; &lt;code&gt;SearchTrigger&lt;/code&gt;, a button drawn like a search field. &lt;code&gt;SectionNav&lt;/code&gt;, &amp;quot;On this page&amp;quot; as real links, the section being read marked as the page scrolls. &lt;code&gt;ScopeBreadcrumb&lt;/code&gt;, where the person is level by level, each level a menu, a level with no value saying &amp;quot;Choose …&amp;quot;. &lt;code&gt;Timeline&lt;/code&gt; and &lt;code&gt;TimelineItem&lt;/code&gt;, a history on an icon rail, each tone with its own icon; a time not recorded says so.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Data:&lt;/strong&gt; &lt;code&gt;ReorderableList&lt;/code&gt;, a list a person orders by dragging a handle, from the keyboard (Space or Enter picks up, the arrows move, Escape puts back) or from a menu of moves; items move between &lt;code&gt;groups&lt;/code&gt;, every step is announced, and focus stays on the moved item.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Dialogs:&lt;/strong&gt; &lt;code&gt;ResponsiveDialog&lt;/code&gt;, a dialog from 640 px wide (&lt;code&gt;breakpoint&lt;/code&gt;) and a bottom drawer below, chosen when it opens and kept while open.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;DataTable (Pro):&lt;/strong&gt; &lt;code&gt;renderDetail&lt;/code&gt; gives a row a disclosure button that opens a full-width row under it (&lt;code&gt;expanded&lt;/code&gt;, &lt;code&gt;defaultExpanded&lt;/code&gt;, &lt;code&gt;onExpandedChange&lt;/code&gt;, &lt;code&gt;expandMode&lt;/code&gt;). &lt;code&gt;groupBy&lt;/code&gt; puts rows under group headings (&amp;quot;Production (12)&amp;quot;), sorted within each group (&lt;code&gt;groupOrder&lt;/code&gt;, &lt;code&gt;groupLabel&lt;/code&gt;, and &lt;code&gt;groupCounts&lt;/code&gt; in server mode; without it a heading says the count is this page's). &lt;code&gt;page&lt;/code&gt; now works in memory too, with &lt;code&gt;onPageChange&lt;/code&gt;, so a &lt;code&gt;TableScrubberMap&lt;/code&gt; can drive an in-memory table: if you passed &lt;code&gt;page&lt;/code&gt; to an in-memory table (it was ignored), it now applies, so pass &lt;code&gt;onPageChange&lt;/code&gt; as well, or drop &lt;code&gt;page&lt;/code&gt;. &lt;code&gt;onOrderChange(rowIds)&lt;/code&gt; gives, in memory, every matching row's id in the order the table shows them, at first and whenever a search, a sort or grouping changes it: build &lt;code&gt;TableScrubberMap&lt;/code&gt;'s &lt;code&gt;marks&lt;/code&gt; from it, since marks index the table's current order. A disclosure named by a numeric first column reads the number as the locale writes it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tree (Pro)&lt;/strong&gt; loads children when a node opens: &lt;code&gt;loadChildren(node, { offset, limit })&lt;/code&gt;, &lt;code&gt;isLeaf&lt;/code&gt; and &lt;code&gt;cap&lt;/code&gt;. A node whose &lt;code&gt;children&lt;/code&gt; is left out has children to load (&lt;code&gt;[]&lt;/code&gt; has none); each loads once, shows &amp;quot;Loading…&amp;quot;, offers a retry when a load fails, and past &lt;code&gt;cap&lt;/code&gt; a &amp;quot;Show more&amp;quot; row loads the next page. Loads are announced. Without &lt;code&gt;loadChildren&lt;/code&gt;, a tree behaves as before, with &lt;code&gt;aria-posinset&lt;/code&gt; and &lt;code&gt;aria-setsize&lt;/code&gt; added.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;SessionList (Pro):&lt;/strong&gt; &lt;code&gt;Session.archived&lt;/code&gt; moves a thread behind one &amp;quot;Archived (n)&amp;quot; row, which a search still finds; &lt;code&gt;onArchive&lt;/code&gt; adds Archive and Unarchive to its menu; &lt;code&gt;recency=&amp;quot;long&amp;quot;&lt;/code&gt; adds Previous 30 days, this year's months and earlier years. Days are now read in LocaleProvider's &lt;code&gt;timeZone&lt;/code&gt; when you set one. Archiving, unarchiving or deleting a thread moves focus to the next one.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Dialog (Pro):&lt;/strong&gt; &lt;code&gt;DialogContent&lt;/code&gt; takes &lt;code&gt;size&lt;/code&gt; (&amp;quot;default&amp;quot;, &amp;quot;wide&amp;quot;, &amp;quot;full&amp;quot;); the new &lt;code&gt;DialogBody&lt;/code&gt; scrolls between header and footer, focusable and named by the title while it overflows.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Composer (free):&lt;/strong&gt; the row of mentioned records and attached files is a group named &amp;quot;Attached to this message&amp;quot; (&lt;code&gt;composer.tray&lt;/code&gt;), so your &lt;code&gt;attachmentPreview&lt;/code&gt; and &lt;code&gt;composer&lt;/code&gt; strings reach it; removing a chip moves focus to the next chip, the one before, or the text box, not the page (Storywrite A-43).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; (free)&lt;/strong&gt; keeps focus and a screen reader's place on the control when a reason comes or goes, and the control keeps its own &lt;code&gt;data-slot&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Menus (Pro):&lt;/strong&gt; a &lt;code&gt;DropdownMenuItem&lt;/code&gt;, &lt;code&gt;ContextMenuItem&lt;/code&gt; or &lt;code&gt;MenubarItem&lt;/code&gt; inside &lt;code&gt;Locked&lt;/code&gt;, or &lt;code&gt;aria-disabled&lt;/code&gt;, or whose &lt;code&gt;onClick&lt;/code&gt; calls &lt;code&gt;preventDefault()&lt;/code&gt;, no longer runs &lt;code&gt;onSelect&lt;/code&gt;, and the menu stays open.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Command (Pro):&lt;/strong&gt; &lt;code&gt;defaultValue&lt;/code&gt; and a controlled &lt;code&gt;value&lt;/code&gt; set the first highlight (before, the first item was always highlighted, and a controlled &lt;code&gt;value&lt;/code&gt; got &lt;code&gt;onValueChange&lt;/code&gt; with the first item's value on mount). &lt;code&gt;CommandDialog&lt;/code&gt; names its search box by its &lt;code&gt;title&lt;/code&gt;, or &amp;quot;Search&amp;quot;; &lt;code&gt;CommandInput&lt;/code&gt; no longer accepts &lt;code&gt;defaultValue&lt;/code&gt;, which it never read; Enter and the arrow keys in another field inside a &lt;code&gt;Command&lt;/code&gt; are left to that field.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CommandPalette (Pro):&lt;/strong&gt; a locked item stays in the arrow-key order and is described by its reason.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DegradedPanel (free)&lt;/strong&gt; takes &lt;code&gt;live&lt;/code&gt; (default true): set it to &lt;code&gt;false&lt;/code&gt; where something else already announces the failure. SettlingCard does, so its failure is read once.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;HoldToConfirm:&lt;/strong&gt; while &lt;code&gt;locked&lt;/code&gt;, its &amp;quot;Press and hold&amp;quot; instructions aren't shown or read.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ArtifactChip&lt;/strong&gt; takes &lt;code&gt;kindLabel&lt;/code&gt;, the app's word for its kind, read before the title.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CopilotPanel&lt;/strong&gt; keeps the name of the agent it names for screen readers on that agent's messages but doesn't repeat it on screen (&lt;code&gt;nameShownAbove&lt;/code&gt;); &lt;code&gt;renderMessage&lt;/code&gt; gets &lt;code&gt;{ nameShownAbove }&lt;/code&gt; as a second argument.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Heatmap (Pro)&lt;/strong&gt; draws its cells and the &amp;quot;No data&amp;quot; hatch in SVG, so they show in forced colours.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;FilterChips (Pro)&lt;/strong&gt; announces a filter that goes (&amp;quot;Removed filter Status: Open&amp;quot;), or one replaced by another with the same label (&amp;quot;Changed filter Status to Closed&amp;quot;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Message (free):&lt;/strong&gt; with &lt;code&gt;markdownBlocks(text, { breaks: true })&lt;/code&gt; (Storywrite A-46), a lone newline in an agent's paragraph is kept and shown as a line break; the default stays CommonMark. Such a paragraph block carries a new optional &lt;code&gt;breaks: true&lt;/code&gt;; a paragraph your app builds with a &amp;quot;\n&amp;quot; in its text still shows it as a space.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Motion drawings (Pro &lt;code&gt;motion-drawings&lt;/code&gt;):&lt;/strong&gt; for picking up, &lt;code&gt;swell&lt;/code&gt;, &lt;code&gt;lift&lt;/code&gt;, &lt;code&gt;tilt&lt;/code&gt; and &lt;code&gt;ghost&lt;/code&gt;; for adding and removing, &lt;code&gt;fall&lt;/code&gt;, &lt;code&gt;slide-start&lt;/code&gt; (mirrored right to left), &lt;code&gt;bounce&lt;/code&gt; and &lt;code&gt;zoom&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 2.2.1&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --differing keep|replace&lt;/code&gt;&lt;/strong&gt; (Storywrite A-48): where installing a Candor item the new versions need would replace a file of yours that differs from what the install writes, &lt;code&gt;update&lt;/code&gt; now works out every such file the way &lt;code&gt;add&lt;/code&gt; does, before writing anything: a shared item you've changed, such as the tokens, and a &lt;code&gt;lib/utils.ts&lt;/code&gt; of your own that &lt;code&gt;candor-lock.json&lt;/code&gt; doesn't record. Without a terminal and without the flag, it stops there and names each file. &lt;code&gt;--differing keep&lt;/code&gt; keeps every one of them, and their records in &lt;code&gt;candor-lock.json&lt;/code&gt;; &lt;code&gt;--differing replace&lt;/code&gt; takes what the install writes; both name the files. If the registry can't be read to tell, &lt;code&gt;update&lt;/code&gt; stops before writing too (without a terminal, or with &lt;code&gt;keep&lt;/code&gt;). &lt;code&gt;--differing&lt;/code&gt; with &lt;code&gt;--no-deps&lt;/code&gt; is refused. &lt;code&gt;--dry-run&lt;/code&gt; says where the real run would stop and which files, and exits 1 if it would. While shadcn runs, &lt;code&gt;keep&lt;/code&gt; holds a copy of your files in &lt;code&gt;.candor-keep/&lt;/code&gt; (ignored by git), so stopping the CLI with Ctrl-C or a signal still puts them back; if it can't, it says where the copies are. &lt;code&gt;--record&lt;/code&gt; and &lt;code&gt;--differing&lt;/code&gt; are refused on commands that don't use them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; record one hash for one install&lt;/strong&gt; (Storywrite A-49): without RSC, the same item at the same version recorded two hashes, and its file looked changed. Hashes written by earlier CLIs still match, and &lt;code&gt;verify&lt;/code&gt; no longer calls a CLI 2.2.0 entry stale where shadcn had kept the file's &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt; line. &lt;code&gt;verify&lt;/code&gt; names a stale entry, and where the file is Candor's as released, &lt;code&gt;npx candor-ui verify --record&lt;/code&gt; records its hash again: it changes only &lt;code&gt;candor-lock.json&lt;/code&gt;, writes no file and doesn't run shadcn. Use CLI 2.2.1 throughout a team: in a project without RSC, CLI 2.2.0 reading a lockfile 2.2.1 wrote takes files with a &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt; line for ones you've changed.&lt;/li&gt;&lt;li&gt;&lt;code&gt;lint&lt;/code&gt; knows the new items; names other libraries and apps also use (&lt;code&gt;Toolbar&lt;/code&gt;, &lt;code&gt;SearchInput&lt;/code&gt;, &lt;code&gt;Timeline&lt;/code&gt;, &lt;code&gt;SplitView&lt;/code&gt;, &lt;code&gt;TabBar&lt;/code&gt;, &lt;code&gt;DialogBody&lt;/code&gt;) don't by themselves mark a file as using Candor.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site and repository&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Try Candor with no key and no install&lt;/strong&gt; at https://candor.themethodic.com/try: the Vite starter, built with the site. The public README links it and shows the downloads.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;For maintainers:&lt;/strong&gt; &lt;code&gt;npm run lint&lt;/code&gt; fails on any warning; the kit has none.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.2.0</title>
      <link>https://candor.themethodic.com/changelog#4-2-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-2-0</guid>
      <pubDate>Thu, 12 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 2.2.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.2.0; nothing breaks. Layout components for building pages on Candor's tokens; dashboards with keyboard-readable charts, drill-down, tiles and new small charts; reports whose claims show their evidence; more for the thread (quick replies, cards that wait for a service, artifact chips, separators that fit the thread's span); nested dialogs that close as people expect; and CLI 2.2.0's &lt;code&gt;update --fold&lt;/code&gt;. The kit has 349 items: 74 free and 318 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; takes a 4.1 project to 4.2.0, with no codemod. If CLI 2.0.0 installed your project wholly under &lt;code&gt;&amp;lt;app&amp;gt;/candor/candor/&lt;/code&gt;, run &lt;code&gt;npx candor-ui@2 update --fold --dry-run&lt;/code&gt;, then &lt;code&gt;--fold&lt;/code&gt;, then &lt;code&gt;npx candor-ui@2 verify&lt;/code&gt;; this replaces the manual recipe in the 4.0.2 section. If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 4.2.0.&lt;/p&gt;&lt;p&gt;Some DOM your own tests may match has changed, all of it for keyboard and screen-reader access:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;BarChart's &lt;code&gt;svg&lt;/code&gt; was a &lt;code&gt;role=&amp;quot;img&amp;quot;&lt;/code&gt; named &amp;quot;{series} by category&amp;quot;; it is now a &lt;code&gt;role=&amp;quot;group&amp;quot;&lt;/code&gt; named by the chart's title, and its one tab stop per category (&amp;quot;Mon: Passed 3, Failed 1&amp;quot;) is one tab stop for the plot, with a &lt;code&gt;role=&amp;quot;img&amp;quot;&lt;/code&gt; per bar (&amp;quot;Mon: Passed 3&amp;quot;).&lt;/li&gt;&lt;li&gt;LineChart's &lt;code&gt;svg&lt;/code&gt; is a &lt;code&gt;role=&amp;quot;group&amp;quot;&lt;/code&gt; named by the title, with a &lt;code&gt;role=&amp;quot;img&amp;quot;&lt;/code&gt; per point; the focusable &amp;quot;Chart values&amp;quot; element is gone (the table view has them).&lt;/li&gt;&lt;li&gt;DonutChart's &lt;code&gt;svg&lt;/code&gt; is named by the title, not the list of parts; each slice is its own &lt;code&gt;role=&amp;quot;img&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Heatmap's grid is named by the title, not &amp;quot;Heatmap&amp;quot;; it has &lt;code&gt;row&lt;/code&gt;s with a hidden &amp;quot;Row&amp;quot; column header, and its cells take one tab stop with arrow keys instead of each being a tab stop.&lt;/li&gt;&lt;li&gt;DonutChart: a part of 0 draws no slice and is not a keyboard stop; the legend and the table still list it.&lt;/li&gt;&lt;li&gt;The strings &lt;code&gt;barChart.byCategory&lt;/code&gt;, &lt;code&gt;lineChart.over&lt;/code&gt;, &lt;code&gt;lineChart.chartValues&lt;/code&gt; and &lt;code&gt;heatmap.heatmap&lt;/code&gt; are no longer read, so an override of them does nothing; they will go at the next major.&lt;/li&gt;&lt;li&gt;A Dialog, Sheet or Drawer opened from another draws a transparent backdrop of its own.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A Testing Library &lt;code&gt;getByRole(&amp;quot;img&amp;quot;, { name })&lt;/code&gt; on a whole chart needs &lt;code&gt;getByRole(&amp;quot;group&amp;quot;, { name: &amp;lt;title&amp;gt; })&lt;/code&gt;. &lt;code&gt;report-sheet&lt;/code&gt;'s &lt;code&gt;onExport&lt;/code&gt; now receives a second argument, &lt;code&gt;{ provenance }&lt;/code&gt;; a handler that took an optional second argument of its own will now get that object.&lt;/p&gt;&lt;h3&gt;New items (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Layout, in a new &lt;code&gt;layout&lt;/code&gt; group:&lt;/strong&gt; &lt;code&gt;Text&lt;/code&gt;, &lt;code&gt;Heading&lt;/code&gt;, &lt;code&gt;Stack&lt;/code&gt;, &lt;code&gt;VisuallyHidden&lt;/code&gt;, &lt;code&gt;PageContainer&lt;/code&gt;, &lt;code&gt;DashboardGrid&lt;/code&gt; with &lt;code&gt;DashboardGridItem&lt;/code&gt;, and &lt;code&gt;FormLayout&lt;/code&gt; with &lt;code&gt;FormSection&lt;/code&gt;. They lay out pages on Candor's tokens without hand-written classes, follow &lt;code&gt;data-density&lt;/code&gt; and right-to-left pages, and take &lt;code&gt;render&lt;/code&gt; (there is no &lt;code&gt;as&lt;/code&gt;): if you are moving from your own layout components, &lt;code&gt;&amp;lt;Text as=&amp;quot;span&amp;quot;&amp;gt;&lt;/code&gt; becomes &lt;code&gt;&amp;lt;Text render={&amp;lt;span /&amp;gt;}&amp;gt;&lt;/code&gt;. A &lt;code&gt;Heading&lt;/code&gt; needs its &lt;code&gt;level&lt;/code&gt;; its size is set apart from the level.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;narrative-block&lt;/code&gt;:&lt;/strong&gt; report prose as claims, each followed by the sources or report sections it rests on. A claim that states a figure with no evidence is marked &amp;quot;No evidence given for this figure&amp;quot; rather than shown as fact. &lt;code&gt;claimStatesNumber()&lt;/code&gt; is exported, and &lt;code&gt;numeric&lt;/code&gt; overrides it (&amp;quot;Q3&amp;quot;, a year).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;semantic-badge&lt;/code&gt;:&lt;/strong&gt; a badge with an icon and a word for each neutral vocabulary (severity, risk, effort, confidence, provenance, autonomy, classification), whose values match the kit's own types. &lt;code&gt;null&lt;/code&gt; reads &amp;quot;Unknown&amp;quot;. Add your own vocabularies with &lt;code&gt;VocabulariesProvider&lt;/code&gt;; change a built-in word through LocaleProvider under &lt;code&gt;semanticBadge&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;dashboard-tile&lt;/code&gt;:&lt;/strong&gt; a titled tile with a freshness stamp, ChartFrame's loading, empty, partial and error states, a drill-down button in your words, a view switch whose disallowed views stay locked with the reason, and a toolbar slot. A chart inside shows its title once. ChartFrame exports &lt;code&gt;ChartStateView&lt;/code&gt; and &lt;code&gt;ChartNestedProvider&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;artifact-toolbar&lt;/code&gt;:&lt;/strong&gt; maximise, download (one format a button, several a menu) and &amp;quot;Ask about this&amp;quot; for an artifact or tile, each button naming it. Controls without a handler aren't drawn; locked ones say why. Your own actions go in as &lt;code&gt;ArtifactToolbarButton&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;share-bar&lt;/code&gt;:&lt;/strong&gt; parts of one whole as one bar with a legend of values and shares. Unmeasured parts say so, and the caption says when the shares are of the measured parts only and how many were left out. Against a &lt;code&gt;whole&lt;/code&gt;, a shortfall shows as &amp;quot;Not accounted for&amp;quot;, and parts that add up to more than the whole say so instead of drawing shares. A value that isn't a finite number counts as not measured. Shares round down, so only the whole reads 100%, and a part under 0.1% reads &amp;quot;&amp;lt;0.1%&amp;quot;. Drawn in SVG, so it shows in forced colours.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;mini-bar&lt;/code&gt;:&lt;/strong&gt; a bar for a table cell, beside &lt;code&gt;Sparkline&lt;/code&gt;; &amp;quot;no data&amp;quot; for a missing value. Its fill shows in forced colours.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;progress-ring&lt;/code&gt;:&lt;/strong&gt; circular completion for a measured value, as a progressbar. The share shown is rounded down, so it never reads 100% before the total is reached, and past the total it says so (&amp;quot;120 of 100&amp;quot;). A value that isn't a finite number, or a total of zero or less, reads &amp;quot;Unknown&amp;quot;. It starts at 12 o'clock and runs the reading direction's way. An unknown value draws the track only and says &amp;quot;Unknown&amp;quot;; for work of unknown length, use &lt;code&gt;StatusDot&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;table-scrubber-map&lt;/code&gt;:&lt;/strong&gt; beside a server-mode &lt;code&gt;DataTable&lt;/code&gt;, where the flagged rows are across pages, with a button per page that holds flags. With an unknown total it lists the pages without placing them. A DataTable paging in the browser keeps its page to itself, so it can't be driven from here.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;chart-focus&lt;/code&gt;, &lt;code&gt;pattern-fill&lt;/code&gt;, &lt;code&gt;chart-views&lt;/code&gt;:&lt;/strong&gt; the keyboard model, the patterns and the allowed views the charts below use, for your own plots too (&lt;code&gt;useChartFocus&lt;/code&gt;; &lt;code&gt;ChartPatterns&lt;/code&gt;, &lt;code&gt;patternFor&lt;/code&gt;, &lt;code&gt;patternStyle&lt;/code&gt;, &lt;code&gt;markerPath&lt;/code&gt;; &lt;code&gt;allowedViews&lt;/code&gt; and &lt;code&gt;useAllowedViews&lt;/code&gt;, which say which views a dataset allows, and why not).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;useAnnouncer&lt;/code&gt;:&lt;/strong&gt; announces a message to screen-reader users from app code, politely or assertively, and says the same words again when they are repeated. One shared pair of hidden live regions is in the page while any component uses it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;QuickReplies&lt;/code&gt;:&lt;/strong&gt; the replies an agent offers to its own question, as chips under its message that send the reply at once and say so. Nothing is chosen until one is pressed; while sending and once sent the chips are locked with a reason, and the sent one keeps a tick. Use &lt;code&gt;PromptSuggestions&lt;/code&gt; for prompts that only fill the composer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;SettlingCard&lt;/code&gt; and &lt;code&gt;useCardSettlement&lt;/code&gt;:&lt;/strong&gt; a registry card whose write may not have settled. It says it is waiting for the named service, shows the service's reason with Retry and &amp;quot;Not applied&amp;quot; when it fails, and shows the card alone only once settled. A card definition reads the state to lock its own actions while pending. &lt;code&gt;RegistryCard&lt;/code&gt; is unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ArtifactChip&lt;/code&gt;:&lt;/strong&gt; a chip in the thread for a diff, approval, form, table or plan that lives in the app's panel. It opens that panel's tab, marks the tab that is showing, and gives its state in words and an icon.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;useThreadSeparators&lt;/code&gt;:&lt;/strong&gt; chooses where &lt;code&gt;ThreadDivider&lt;/code&gt;s go from how long the thread runs: by day, week, month or year, in the locale's time zone and with its first day of the week. Pass its result to the dividers you already draw.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Charts you can read by keyboard (Pro).&lt;/strong&gt; BarChart, LineChart, DonutChart and Heatmap put every bar, point, slice and cell on one tab stop per plot. Arrow keys move, PageUp and PageDown change series, and each mark is read as its series, category and value (&amp;quot;Mon: Passed 3&amp;quot;); a missing one says &amp;quot;no data&amp;quot;. Focus shows the same tooltip as hover. A drawn heatmap now has proper rows, so axe passes on it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Patterns in high contrast (Pro).&lt;/strong&gt; Under the high-contrast theme and in forced colours, bars, donut slices and their legends carry hatch patterns, and line points a marker shape per series. &lt;code&gt;patterns=&amp;quot;always&amp;quot;&lt;/code&gt; shows them in any theme and &lt;code&gt;&amp;quot;never&amp;quot;&lt;/code&gt; turns them off. The default themes look as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Drill down from a chart (Pro).&lt;/strong&gt; The four charts take &lt;code&gt;onSelect&lt;/code&gt;, &lt;code&gt;selectLabel&lt;/code&gt; and &lt;code&gt;selected&lt;/code&gt;. A mark becomes a button that says what pressing it filters to (&amp;quot;Filter to Mon&amp;quot;, or your words), pressed by a click, Enter or Space. A mark with no data, or whose value isn't a finite number, can't be selected and says so.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DateRangePicker&lt;/code&gt; &lt;code&gt;available&lt;/code&gt; (Pro).&lt;/strong&gt; Pass the span your data covers. A window picked wider is narrowed to it, the value keeps the window asked for as &lt;code&gt;requested&lt;/code&gt;, and the picker says &amp;quot;Data exists from … to …; showing that.&amp;quot; A &lt;code&gt;value&lt;/code&gt; or &lt;code&gt;defaultValue&lt;/code&gt; you pass that is wider, or a window left wider when &lt;code&gt;available&lt;/code&gt; narrows, is shown narrowed with the same note; your value is unchanged and &lt;code&gt;onValueChange&lt;/code&gt; isn't called. With no &lt;code&gt;available&lt;/code&gt;, nothing changes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;report-sheet&lt;/code&gt; provenance (Pro).&lt;/strong&gt; A new &lt;code&gt;provenance&lt;/code&gt; prop (where the data is from, provisional or final, missing sections) is said in the footer, which prints with the report. Candor doesn't write the downloaded files, so &lt;code&gt;onExport&lt;/code&gt; now gets the same lines as a second argument, &lt;code&gt;{ provenance }&lt;/code&gt;, and &lt;code&gt;exportProvenanceLines()&lt;/code&gt; returns them for files you write yourself. If you leave out the posture, the footer says &amp;quot;Not marked provisional or final.&amp;quot; One-argument &lt;code&gt;onExport&lt;/code&gt; handlers keep working.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Field&lt;/code&gt; trust (Pro).&lt;/strong&gt; A new &lt;code&gt;trust&lt;/code&gt; prop shows when a value is unverified, was filled by an agent (named by &lt;code&gt;by&lt;/code&gt;), or has a source that is unavailable (with &lt;code&gt;reason&lt;/code&gt;): an icon and words under the label, read out with the control, and a dashed edge on the control.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;MessageHeader&lt;/code&gt;: &lt;code&gt;nameShownAbove&lt;/code&gt; (free).&lt;/strong&gt; When the panel or chat above already names the agent or teammate, the header leaves the name out of sight but keeps it for screen readers. A header with nothing else to show isn't drawn. Nothing changes unless you set it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; (free)&lt;/strong&gt; adds its reason to the control's own &lt;code&gt;aria-describedby&lt;/code&gt; instead of replacing it, so a hint or an error is still read on a locked control. A control you wrap in Locked that has its own description is now described by both. A locked DateRangePicker now says why it is locked (since 4.1 it didn't), and a locked HoldToConfirm reads its consequence as well as the reason.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DonutChart (Pro)&lt;/strong&gt; shares follow the locale's number format (&amp;quot;33,3 %&amp;quot; in German).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Nested dialogs (Pro).&lt;/strong&gt; A click outside a Dialog, Sheet or Drawer opened from another closes only the inner one, as Radix and the APG dialog pattern do; before, Base UI's nested dialogs ignored it. An AlertDialog still ignores outside clicks. The page is still dimmed once. A nested dialog with &lt;code&gt;modal={false}&lt;/code&gt; or &lt;code&gt;&amp;quot;trap-focus&amp;quot;&lt;/code&gt; draws no backdrop of its own, so the outer one stays usable.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Diagram (Pro)&lt;/strong&gt; marks bidi controls in the labels Mermaid draws, so a Diagram given Mermaid &lt;code&gt;source&lt;/code&gt; shows a control in a label as a mark, like every other model text. This closes 4.1's one exception.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 2.2.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --fold&lt;/code&gt;&lt;/strong&gt; folds a project CLI 2.0.0 installed wholly under &lt;code&gt;&amp;lt;app&amp;gt;/candor/candor/&lt;/code&gt; up into &lt;code&gt;&amp;lt;app&amp;gt;/candor/&lt;/code&gt;: it moves the files, rewrites &lt;code&gt;candor-lock.json&lt;/code&gt;, points imports of &lt;code&gt;…/candor/candor/…&lt;/code&gt; at &lt;code&gt;…/candor/…&lt;/code&gt;, keeps your edits for &lt;code&gt;update&lt;/code&gt; to merge, stops before any change and names the place if a destination is taken, and with &lt;code&gt;--dry-run&lt;/code&gt; lists the moves. &lt;code&gt;doctor&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; say when a lockfile is nested that way. Only JS and TS sources are rewritten: references to &lt;code&gt;candor/candor&lt;/code&gt; in Markdown, MDX, stylesheets, Vue, Astro, Svelte and JSON files are listed under &amp;quot;Left for you&amp;quot; with their file and line, for you to point at &lt;code&gt;candor/&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;lint&lt;/code&gt; knows the new items. &lt;code&gt;Text&lt;/code&gt;, &lt;code&gt;Heading&lt;/code&gt;, &lt;code&gt;Stack&lt;/code&gt;, &lt;code&gt;VisuallyHidden&lt;/code&gt; and &lt;code&gt;PageContainer&lt;/code&gt; are names other libraries and apps also use, so importing one doesn't by itself mark a file as using Candor.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Every exported component has a doc comment, sub-parts such as &lt;code&gt;CardHeader&lt;/code&gt; and the blocks' and templates' pages included (175 added), and the docs build fails on one without. If you add components to a fork of the kit, give each a one-sentence doc comment.&lt;/li&gt;&lt;li&gt;&lt;code&gt;suggest_components&lt;/code&gt; leads with &lt;code&gt;agent-screen&lt;/code&gt; for &amp;quot;a computer-use screen with its actions&amp;quot;: a task word that only ends a compound item name counts for less than a word in an item's job, when the task has one. It no longer answers a map with &lt;code&gt;table-scrubber-map&lt;/code&gt;, and a word that is both an item's name and its group's counts once more.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For maintainers&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The test count the site quotes is the same on every machine: &lt;code&gt;npm run stats&lt;/code&gt; counts the suite with &lt;code&gt;CANDOR_STATS=1&lt;/code&gt;, which skips the tests that depend on the machine (&lt;code&gt;tests/machine.ts&lt;/code&gt;). &lt;code&gt;release:check&lt;/code&gt; no longer needs &lt;code&gt;--keep-tests&lt;/code&gt;. A new machine-dependent test goes through &lt;code&gt;onThisMachine()&lt;/code&gt;, or &lt;code&gt;tests/scripts/stats.test.ts&lt;/code&gt; fails.&lt;/li&gt;&lt;li&gt;The suite doesn't time out when other work loads the machine: &lt;code&gt;release:check&lt;/code&gt; caps Vitest's workers by the load average, and the suites that timed out under load get 30 seconds (&lt;code&gt;tests/load.ts&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;CI and &lt;code&gt;release:check&lt;/code&gt; generate on Node 24, the version Vercel builds on; &lt;code&gt;release:check&lt;/code&gt; stops on another major and says how to switch (&lt;code&gt;--any-node&lt;/code&gt; runs it anyway). The weekly shadcn canary stays on Node 26.&lt;/li&gt;&lt;li&gt;WebKit runs the layer checks in CI again. Three checks its Linux build fails with no Candor code on the page (an app's Radix dialog in its Radix dialog) are reported as WebKit-on-Linux baseline, not counted.&lt;/li&gt;&lt;li&gt;No shadowed names in the tests; RELEASING's Start step names the home pill's link and the motion manifest.&lt;/li&gt;&lt;li&gt;The context menu's keyboard test no longer fails depending on timing. It pressed ArrowDown before the menu had taken focus, which Base UI gives it on the next animation frame, up to 17 ms later in jsdom. It now waits for the menu to have focus first. 4.1.0's test has the same race; the component was never at fault.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;OrgSmith pack (in-house, not published)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;New &lt;code&gt;logo&lt;/code&gt; and &lt;code&gt;domain-icons&lt;/code&gt; items, and the preset's delivery, business and knowledge-base status vocabularies for &lt;code&gt;VocabulariesProvider&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.1.0</title>
      <link>https://candor.themethodic.com/changelog#4-1-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-1-0</guid>
      <pubDate>Thu, 12 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A minor, with CLI 2.1.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.1.0; nothing breaks. Motion is now easy to find and choose in the theme builder, with named styles and motion for show in a new Pro item; text from a model or a tool can no longer reorder what a person reads; CLI 2.1.0 checks brand scopes and handles monorepos and &lt;code&gt;@/candor&lt;/code&gt; projects better; and a round of fixes across the kit, docs and the docs MCP. The kit has 326 items: 74 free and 295 in Pro.&lt;/p&gt;&lt;p&gt;What to do: &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; takes a 4.0 project to 4.1.0, with no codemod. If your own components draw text from a model or a tool, call &lt;code&gt;neutralizeBidi&lt;/code&gt; from the new free &lt;code&gt;bidi&lt;/code&gt; item. To use the motion for show and the new drawings, install the Pro &lt;code&gt;motion-drawings&lt;/code&gt; item and import &lt;code&gt;styles/candor-motion-drawings.css&lt;/code&gt; after &lt;code&gt;candor.css&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;If you use &lt;code&gt;@candor-ui/react&lt;/code&gt;, install 4.1.0; &lt;code&gt;neutralizeBidi&lt;/code&gt; is exported from the package root. &lt;code&gt;theme check&lt;/code&gt; now counts each brand scope towards its exit code, so a CI step that runs it on a file with several brands can fail with no change on your side: run &lt;code&gt;npx candor-ui@2 theme check&lt;/code&gt; locally first. Some DOM your own tests may match has changed: a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt; now splits PermissionPrompt's blocked-path and server lines and ApprovalRequest's &amp;quot;You chose:&amp;quot; and &amp;quot;Can't be undone:&amp;quot;, so a Testing Library &lt;code&gt;getByText&lt;/code&gt; on the whole sentence needs a function matcher; TabsList has an &lt;code&gt;aria-hidden&lt;/code&gt; first child, &lt;code&gt;span[data-slot=&amp;quot;tabs-indicator&amp;quot;]&lt;/code&gt;; the inline &lt;code&gt;measured&lt;/code&gt; node is a &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;; and copied text (&lt;code&gt;blocksToText&lt;/code&gt;, Payload) shows control characters as marks such as &lt;code&gt;[U+202E]&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;The motion rule&lt;/h3&gt;&lt;p&gt;The principle &amp;quot;Motion follows the outcome&amp;quot; is now &lt;strong&gt;&amp;quot;Motion never says something false&amp;quot;&lt;/strong&gt; (the link &lt;code&gt;/principles#motion-follows-the-outcome&lt;/code&gt; still works). Motion that reports something still waits for it: a tick is drawn after the result settles, a spinner turns only while work runs, and a progress bar fills only as far as the work has gone. Motion for show, such as content arriving as a page loads, a card lifting under the pointer or a chart drawing in, is welcome when it says nothing false: it doesn't look like a status, a measurement or a result that isn't so, never hides content or holds back input, ends on the measured values, and is off under reduced motion. The Principles page, &lt;code&gt;design.md&lt;/code&gt; and both coding-agent skills say so.&lt;/p&gt;&lt;h3&gt;Theme builder&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Motion where you'd look for it.&lt;/strong&gt; The Build menu and Start name motion and sound. The canvas has an &lt;strong&gt;Animations&lt;/strong&gt; view that plays every kind of animation in turn, with Pause, and compares each kind's drawings and easings side by side on a plain stand-in shape, the current one marked &amp;quot;now&amp;quot; and nothing chosen. The Motion panel lists every component that has animations, with search. Plain words sit beside the design's terms (&amp;quot;Kinds of animation (families)&amp;quot;, &amp;quot;Animations (moments)&amp;quot;, &amp;quot;Animation · drawn as&amp;quot;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Named motion styles:&lt;/strong&gt; Quiet, Crisp and Lively, on Start and at the top of Motion, each with Replay. Nothing is chosen until you press Use, and Undo takes it back. Quiet and Crisp write only tokens a brand file already takes. Lively also turns on motion for show (Pro): it writes &lt;code&gt;--cd-show-*&lt;/code&gt;, tokens new in 4.1 that only the Pro &lt;code&gt;motion-drawings&lt;/code&gt; item reads, so without that item they do nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The Start presets carry a motion style:&lt;/strong&gt; Candor keeps Candor's own, Slate and Console take Crisp, Paper takes Quiet and Signal takes Lively; one Undo takes back the preset and its motion. Another shape of the same preset keeps the motion you set. Motion is the whole file's, so a preset picked while a brand scope is open sets it for the base and every scope, and the builder says so. This is in the builder only: the installed gallery themes are unchanged, so your project's motion doesn't change on update.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;For show · Pro&lt;/strong&gt; in the Motion panel sets entrances, charts drawing in and hover, and the drawing selects offer the Pro drawings, marked Pro.&lt;/li&gt;&lt;li&gt;The download's note for coding agents says &lt;code&gt;theme check&lt;/code&gt; (CLI 2.1.0) measures each brand scope.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New items&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;bidi&lt;/code&gt;&lt;/strong&gt; (free): &lt;code&gt;neutralizeBidi(text)&lt;/code&gt;, &lt;code&gt;hasBidiControls(text)&lt;/code&gt; and &lt;code&gt;escapeBidiJson(json)&lt;/code&gt;. Bidi control characters (U+202A to U+202E, U+2066 to U+2069) in text from a model or a tool now show as visible marks such as &lt;code&gt;[U+202E]&lt;/code&gt;, on screen, to screen readers and when copied, so a reply, file name, diff or log line can't be made to read in a different order. Names and labels from a model sit in an isolate (&lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;), so genuine mixed Arabic or Hebrew and Latin text still lays out correctly; LRM, RLM and U+061C are left alone. Every item that draws model or tool text uses it, free and Pro: messages, attachments, prompt suggestions, cards, payloads, tool calls, logs, entities, sources, permission prompts, reasoning, searches, artifacts, change sets, diffs, code, plans, test results, approvals, questions, tables, run trees, A2UI surfaces and the standard cards; and memories, retrieved passages and the claims they back, knowledge sources, rewrites (ProseDiff and SelectionActions), diagrams given as data, tool settings, an agent's last failure, findings, import problems, DataTable's agent-filled cells, traces, run receipts, eval reviews and failure clusters, threads, the inbox and the away digest. PermissionPrompt's and ApprovalRequest's edit fields show a control character as its JSON escape (&lt;code&gt;\u202e&lt;/code&gt;), and Allow or Approve still sends the input exactly; so do ImportReview's Apply, ProseDiff's resolved text and SelectionActions' Keep. One exception: a Diagram given Mermaid source draws its labels through Mermaid, which doesn't mark them; its source view does. If your own components draw text from a model or a tool, call &lt;code&gt;neutralizeBidi&lt;/code&gt;; for a JSON field, &lt;code&gt;escapeBidiJson&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;motion-drawings&lt;/code&gt;&lt;/strong&gt; (Pro): blur, flip, swing, skew and wipe drawings for dialogs, menus, arrivals and pops, each with its calm form; and motion for show, off until a brand file turns it on: cards, stat cards and chart frames arriving as the page draws (at most six, staggered), bar, line and donut charts drawing in with their values in the page for screen readers from the start, and cards that aren't controls lifting or glowing under the pointer. All of it is off at the Off level, under &lt;code&gt;data-motion=&amp;quot;calm&amp;quot;&lt;/code&gt; (on the card or around it) and under reduced motion. The entrance plays only as the page first draws, and the rules sit below your utilities, so your own animation on a Card wins.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;PermissionPrompt&lt;/strong&gt; takes &lt;code&gt;jsonEditor&lt;/code&gt;, the field the tool's input is edited in, typed by the new &lt;code&gt;PermissionJsonEditorProps&lt;/code&gt;. With Pro, pass &lt;code&gt;CodeEditor&lt;/code&gt; for line numbers, JSON colours, Tab to indent and the error read out with the field; left out, the prompt keeps its plain text field.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;In a dialog that clips its content&lt;/strong&gt; (a max height with its own scroll), your app's own Radix menu, select or dialog opened from a Candor layer is drawn above it, takes the pointer and closes with Escape; in 4.0 it was drawn underneath. Nothing changes outside such dialogs.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Separators come from the strings&lt;/strong&gt;, so a translation can change them: ReviewQueue (&lt;code&gt;hintSeparator&lt;/code&gt;, &lt;code&gt;hintEither&lt;/code&gt;, &lt;code&gt;hintItem&lt;/code&gt;), Composer (&lt;code&gt;hintSeparator&lt;/code&gt;, &lt;code&gt;hintItem&lt;/code&gt;, &lt;code&gt;scopeChip&lt;/code&gt;), Message (&lt;code&gt;metaSeparator&lt;/code&gt;), TaskTray (&lt;code&gt;countSeparator&lt;/code&gt;), PermissionPrompt (&lt;code&gt;scopeSeparator&lt;/code&gt;), Payload (&lt;code&gt;titleSeparator&lt;/code&gt;) and Reasoning (&lt;code&gt;summarySeparator&lt;/code&gt;). English text is unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tabs&lt;/strong&gt; (Pro): the selected tab's background or underline moves to the tab you choose; it is placed still on first draw. Under React's Strict Mode it never moved before; fixed, and the same in &lt;strong&gt;ToggleGroup&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DataTable&lt;/strong&gt; (Pro): the &amp;quot;n selected&amp;quot; bar fades in. &lt;strong&gt;FilterChips&lt;/strong&gt; (Pro): an added filter pops in and a removed one pops out. &lt;strong&gt;InviteMembers&lt;/strong&gt; (Pro): each address pops in as a chip.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ProfileSettings&lt;/strong&gt; (Pro): &amp;quot;Saved&amp;quot; appears only after &lt;code&gt;onSave&lt;/code&gt; resolves; if it rejects, the form says &amp;quot;Not saved&amp;quot; with the reason and keeps your changes (before, it stayed on &amp;quot;Saving…&amp;quot;). New strings &lt;code&gt;notSaved&lt;/code&gt; and &lt;code&gt;notSavedNoReason&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;BarChart and LineChart&lt;/strong&gt; (Pro): when values change on screen, bars and lines move from the old measured values to the new; nothing moves on first draw and a resize redraws in place.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inbox and ApprovalQueue&lt;/strong&gt; (Pro): rows slide to their new place when the data re-sorts them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AppLayout&lt;/strong&gt; (Pro): a click on the panel divider moves the panel to its next width; dragging and the keys resize it at once.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Dialogs keep Tab inside&lt;/strong&gt; (Storywrite): in a Candor Dialog, AlertDialog, Sheet or Drawer, Tab and Shift+Tab wrap inside the popup. Before, focus could rest for a frame on Base UI's focus guard outside it (Base UI 1.9.0 moves it back on the next frame), which happened on 4.0 too.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inside a foreign dialog&lt;/strong&gt;, layers your app portals into its own container are drawn above Candor's layer as well, and a Candor layer that leaves the top layer and comes back no longer covers your app's open menu.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tabs&lt;/strong&gt; (Pro): the indicator isn't placed until the tabs have a size, so hidden tabs don't slide it in when they show, and it follows a tab whose label grows. Inactive tabs meet 4.5:1 contrast in every theme (they were as low as 4.11:1 in the gallery themes).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inbox and ApprovalQueue&lt;/strong&gt; (Pro): only the rows a re-sort moved slide, and the selection boxes are 24px targets. &lt;strong&gt;BarChart and LineChart&lt;/strong&gt; (Pro) redraw in place when resized during an update. &lt;strong&gt;FilterChips&lt;/strong&gt; (Pro) keeps focus on the chips when one is removed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;TaskTray&lt;/strong&gt; (Pro): its open popover is named by its title (&amp;quot;Background work&amp;quot;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ProfileSettings&lt;/strong&gt;' &lt;code&gt;notSaved&lt;/code&gt; is one sentence a translation punctuates: a select phrase on &lt;code&gt;end&lt;/code&gt; (&lt;code&gt;stop&lt;/code&gt; when the reason ends in its own punctuation, &lt;code&gt;other&lt;/code&gt; otherwise).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ChartFrame&lt;/strong&gt;'s docs page describes its empty, partial, error and busy states, and a free foundation comment no longer names a product.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 2.1.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme check&lt;/code&gt; checks each brand scope&lt;/strong&gt; (&lt;code&gt;[data-brand=&amp;quot;&amp;lt;name&amp;gt;&amp;quot;]&lt;/code&gt;, as the theme builder writes several brands in one file) as a theme of its own, in light, dark, high contrast and the system's dark setting, after the base. A scope is measured as the browser draws it on an element inside &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;: a value the page works out at &lt;code&gt;:root&lt;/code&gt; from another (&lt;code&gt;--primary: var(--brand-ink)&lt;/code&gt;) keeps the root's value there unless the scope sets it again, as the theme builder's scopes do; a scope whose rules can only be on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; is measured there. Results are labelled &lt;code&gt;Light in [data-brand=&amp;quot;acme&amp;quot;]&lt;/code&gt;, count towards the totals and the exit code, and the JSON adds &lt;code&gt;themes[].brand&lt;/code&gt;. A scope that changes no colour (only &lt;code&gt;--radius&lt;/code&gt;, say) is named in a note and not measured again. The Pro drawings are accepted with a note naming the item they need.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A monorepo set up by an earlier CLI:&lt;/strong&gt; where &lt;code&gt;candor-lock.json&lt;/code&gt; records &lt;code&gt;tokens&lt;/code&gt; at a copy in the app's &lt;code&gt;styles/&lt;/code&gt; that nothing imports (a CLI before 2.1.0 wrote it on &lt;code&gt;add&lt;/code&gt;), &lt;code&gt;update&lt;/code&gt; records and updates the &lt;code&gt;candor-tokens.css&lt;/code&gt; beside the shared package's &lt;code&gt;candor.css&lt;/code&gt; instead, removes the app's copy if it hasn't changed since it was installed, and says so when it leaves one you changed. Before, the copy &lt;code&gt;candor.css&lt;/code&gt; imports stayed at the old version, so from 3.x colours such as &lt;code&gt;bg-sunken&lt;/code&gt; and &lt;code&gt;text-warning-text&lt;/code&gt; were missing. &lt;code&gt;doctor&lt;/code&gt; names such a copy. Run &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; from the app.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Monorepos:&lt;/strong&gt; &lt;code&gt;update&lt;/code&gt; updates Candor's stylesheets where &lt;code&gt;init&lt;/code&gt; installed them, in the shared package (it stopped before, saying &lt;code&gt;styles/candor.css&lt;/code&gt; wasn't on disk), and &lt;code&gt;add&lt;/code&gt; from the app no longer writes a second &lt;code&gt;candor-tokens.css&lt;/code&gt; into the app. In a monorepo app whose &lt;code&gt;ui&lt;/code&gt; alias is in a shared package, &lt;code&gt;add&lt;/code&gt; without a terminal no longer stops over a file that differs only in import paths, and the dry run lists it as &lt;code&gt;kept&lt;/code&gt;: its imports name different modules, and shadcn leaves the file as it is. The README's Monorepos section says what builds in shadcn's Base UI monorepo template.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;An &lt;code&gt;@/candor&lt;/code&gt; project stays as it is&lt;/strong&gt; when one &lt;code&gt;add&lt;/code&gt; by an older CLI wrote files into a &lt;code&gt;candor/&lt;/code&gt; folder inside it: the files recorded directly in the folder decide, and &lt;code&gt;update&lt;/code&gt; moves the nested ones up, points their imports there and records them where they are, including the files of an item already at the version it updates to. &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;doctor&lt;/code&gt; say when the lockfile records nested files, and to run &lt;code&gt;update&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;add --dry-run&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; say once when &lt;code&gt;tsx: false&lt;/code&gt; or &lt;code&gt;cssVariables: false&lt;/code&gt; in &lt;code&gt;components.json&lt;/code&gt; sends them to shadcn's own preview, and why.&lt;/li&gt;&lt;li&gt;&lt;code&gt;audit&lt;/code&gt; titles its motion group &amp;quot;Motion never says something false&amp;quot;, as the Principles page does.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The docs MCP's &lt;code&gt;theme_check&lt;/code&gt; says it checks each brand scope, as CLI 2.1.0 does.&lt;/li&gt;&lt;li&gt;Every item page opens with a sentence about the item. Twenty pages (Accordion, Avatar, Card, Checkbox, Collapsible, Command, Dialog, Drawer, DropdownMenu, Kbd, Popover, ScrollArea, Separator, Sheet, Skeleton, Toggle, ToggleGroup, ChartFrame, LocaleProvider, Surface) led with a short registry description, a helper's text, or nothing.&lt;/li&gt;&lt;li&gt;&lt;code&gt;suggest_components&lt;/code&gt; no longer names &lt;code&gt;sound&lt;/code&gt; for &amp;quot;which tools the agent may use&amp;quot;, &lt;code&gt;permission-prompt&lt;/code&gt; for &amp;quot;delete confirmation prompt&amp;quot;, or the PDF items for &amp;quot;a settings page for the agent&amp;quot;; a higher tier's list shows at most three items.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site, registry and repository&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The site's registry files, docs pages, &lt;code&gt;llms.txt&lt;/code&gt; and the docs MCP's data are built from source at each deploy rather than committed. The files served are the same, and a released version's files are checked against its frozen snapshot, so a deploy that would change them fails instead.&lt;/li&gt;&lt;li&gt;The public repository's README has a table of its dot-folders and &lt;code&gt;plugins/&lt;/code&gt;, saying which tool reads each.&lt;/li&gt;&lt;li&gt;The Next.js and TanStack Start starters' &lt;code&gt;crossSite()&lt;/code&gt; says it is the starter's own copy and where the Premium version installs, and is tested to decide as that one does.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For contributors&lt;/h3&gt;&lt;p&gt;After pulling, run &lt;code&gt;npm run generate&lt;/code&gt; (about ten seconds) before &lt;code&gt;typecheck&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt; or &lt;code&gt;dev&lt;/code&gt;: the generated files are no longer in git; &lt;code&gt;node scripts/generated.mjs --check&lt;/code&gt; says whether they are this checkout's, comparing &lt;code&gt;public/r&lt;/code&gt; and &lt;code&gt;site/&lt;/code&gt; with the snapshot and the docs data and the skill's references with a fresh generate. &lt;code&gt;upgrade-check.mjs --cli &amp;lt;path&amp;gt;&lt;/code&gt; runs a given CLI against the target, and a checkout a patch past its target runs its own; &lt;code&gt;fresh-app.mjs --monorepo&lt;/code&gt; and &lt;code&gt;upgrade-check.mjs --monorepo&lt;/code&gt; run shadcn's Base UI monorepo template, and &lt;code&gt;release:check&lt;/code&gt;'s full run includes both. CI runs the fresh-app and browser jobs on release pull requests and weekly, and &lt;code&gt;docs/RELEASING.md&lt;/code&gt; says how to release when CI can't run. &lt;code&gt;upgrade-check.mjs --to &amp;lt;version&amp;gt;&lt;/code&gt; takes a fixture to this checkout's registry and CLI (or a later release), and the full &lt;code&gt;release:check&lt;/code&gt; runs 3.0 → this version too; &lt;code&gt;upgrade-check.mjs --monorepo&lt;/code&gt; checks that the stylesheets the shared &lt;code&gt;candor.css&lt;/code&gt; imports are the target's.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.0.2</title>
      <link>https://candor.themethodic.com/changelog#4-0-2</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-0-2</guid>
      <pubDate>Wed, 11 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A patch release, with CLI 2.0.1 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.0.0 as before. CLI 2.0.1 is for a 3.x project moving to 4.0: it carries CLI 1.0.1's fixes to the 2.x line, for an app whose &lt;code&gt;components&lt;/code&gt; alias is a folder named &lt;code&gt;candor&lt;/code&gt; (&lt;code&gt;@/candor&lt;/code&gt;), for theme files you moved and recorded, and for a Candor file you changed that stays where it is. The Upgrading to 3.0 and 4.0 pages now say which codemods &lt;code&gt;migrate &amp;lt;version&amp;gt;&lt;/code&gt; runs, and Tabs' docs page opens with what Tabs is.&lt;/p&gt;&lt;p&gt;What to do: run the 4.0 upgrade with CLI 2.0.1 (&lt;code&gt;npx candor-ui@2 update --to 4.0.0&lt;/code&gt;, then &lt;code&gt;npx candor-ui@2 migrate 4.0.0&lt;/code&gt;), and have everyone on the project use it: 2.0.0 puts files where 2.0.1 doesn't, and a lockfile both have written can disagree with the files on disk. If 2.0.0 already put files in a &lt;code&gt;candor/&lt;/code&gt; folder inside your &lt;code&gt;candor&lt;/code&gt; alias's folder (&lt;code&gt;&amp;lt;app&amp;gt;/candor/candor/&lt;/code&gt;) and &lt;code&gt;candor-lock.json&lt;/code&gt; records them there, 2.0.1 goes on using that folder, so a project isn't switched back and forth between runs. &lt;code&gt;update --moved&lt;/code&gt; can't fold them back, since the lockfile's nested paths decide. To fold them into the alias's folder by hand: move the files from &lt;code&gt;&amp;lt;app&amp;gt;/candor/candor/&lt;/code&gt; to &lt;code&gt;&amp;lt;app&amp;gt;/candor/&lt;/code&gt;, change &lt;code&gt;@/candor/candor/&lt;/code&gt; to &lt;code&gt;@/candor/&lt;/code&gt; in your imports, replace &lt;code&gt;candor/candor/&lt;/code&gt; with &lt;code&gt;candor/&lt;/code&gt; in &lt;code&gt;candor-lock.json&lt;/code&gt;'s paths (each item's file keys and its &lt;code&gt;moved&lt;/code&gt; entries), then run &lt;code&gt;npx candor-ui@2 verify&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;CLI 2.0.1&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;A &lt;code&gt;components&lt;/code&gt; (or &lt;code&gt;lib&lt;/code&gt;) alias that is already Candor's folder isn't nested again&lt;/strong&gt; (Storywrite). Candor installs its files in a &lt;code&gt;candor/&lt;/code&gt; folder under each alias; where the alias's folder is itself named &lt;code&gt;candor&lt;/code&gt; (&lt;code&gt;@/candor&lt;/code&gt;, &lt;code&gt;~/candor&lt;/code&gt;), 2.0.0 put them in a second one (&lt;code&gt;web/candor/candor/layer.tsx&lt;/code&gt;), and &lt;code&gt;update&lt;/code&gt; couldn't match the files CLI 1.0.1 had placed in &lt;code&gt;web/candor/&lt;/code&gt; to the release's. &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt; and the lockfile now place them in the alias's own folder (&lt;code&gt;web/candor/thread.tsx&lt;/code&gt;, primitives in &lt;code&gt;web/candor/ui/&lt;/code&gt;), with their imports pointed there; &lt;code&gt;add&lt;/code&gt; gives shadcn local copies of the items placed that way. &lt;code&gt;candor-lock.json&lt;/code&gt; decides which way a project goes: files it records in a &lt;code&gt;candor/&lt;/code&gt; folder inside the alias's folder keep the nesting, and files it records directly in the folder keep them there; only a project whose lockfile records neither is decided by whether that &lt;code&gt;candor/&lt;/code&gt; folder exists.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A move &lt;code&gt;candor-lock.json&lt;/code&gt; records decides where a release's file goes, for &lt;code&gt;add&lt;/code&gt; as for &lt;code&gt;update&lt;/code&gt;.&lt;/strong&gt; With the theme's stylesheets moved out of &lt;code&gt;src/styles/&lt;/code&gt; and recorded, 2.0.0's &lt;code&gt;add&lt;/code&gt; (and &lt;code&gt;init&lt;/code&gt;, and the &lt;code&gt;add&lt;/code&gt; that &lt;code&gt;update&lt;/code&gt; runs for a release's new items) had shadcn write them again in &lt;code&gt;src/styles/&lt;/code&gt;, and &lt;code&gt;update&lt;/code&gt; put a release's new stylesheet there, where the moved &lt;code&gt;candor.css&lt;/code&gt; doesn't find it. Now a file you moved stays where you put it, and a new stylesheet goes beside the moved ones when every file the lockfile records in its folder was moved to the same place; the lockfile records that move too. The lockfile records each file where it is and keeps the moves (2.0.0 dropped them when it recorded an item again). Code files are not placed by a folder's move, since their imports would need pointing: &lt;code&gt;add&lt;/code&gt; of an item whose code file you moved still has shadcn write a fresh copy where it installs it, as 2.0.0 did, while the lockfile keeps your move; delete the fresh one.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --to 4.0.0&lt;/code&gt; takes the release's imports in a Candor file you changed that stays where it is&lt;/strong&gt; (a block's page that imports a renamed preset). 2.0.0 merged it against a base already pointed at the new places, so your copy kept its import of &lt;code&gt;github-kinds&lt;/code&gt; after the file had moved to &lt;code&gt;github-preset&lt;/code&gt; (or, where the release changed the lines around it, the merge stopped at a conflict). If a file 2.0.0 merged this way doesn't build, point that import at the preset's new name by hand.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate &amp;lt;version&amp;gt;&lt;/code&gt; names the release's codemods it doesn't run, and why.&lt;/strong&gt; It runs a codemod only when an entry of that release on an item &lt;code&gt;candor-lock.json&lt;/code&gt; records names it, so &lt;code&gt;strings-keys&lt;/code&gt; runs only for a project with an item it changes, as in 2.0.0. The line is &lt;code&gt;Not run: …&lt;/code&gt;, with &lt;code&gt;npx candor-ui migrate &amp;lt;codemod&amp;gt;&lt;/code&gt; to run one anyway. Nothing it runs or changes is different.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The upgrade pages&lt;/h3&gt;&lt;p&gt;The Upgrading to 3.0 and Upgrading to 4.0 pages, and the 4.0.0 notes above, said &lt;code&gt;migrate &amp;lt;version&amp;gt;&lt;/code&gt; runs each of the release's codemods that an entry on your items names, which read as if every codemod listed always runs. The pages now say it runs, in order, those of the release's codemods that an entry on one of your installed items names, lists the ones it leaves out, runs all of them where there's no &lt;code&gt;candor-lock.json&lt;/code&gt;, and that &lt;code&gt;npx candor-ui migrate &amp;lt;codemod&amp;gt;&lt;/code&gt; runs one anyway. The 3.0 page names CLI 1.0.1 or later, and the 4.0 page CLI 2.0.1 or later.&lt;/p&gt;&lt;h3&gt;CLI 1.0.1, for 2.x → 3.0&lt;/h3&gt;&lt;p&gt;CLI 1.0.1 shipped between kit releases, from a maintenance line (&lt;code&gt;npx candor-ui@1&lt;/code&gt;), for a 2.x project moving to 3.0. It fixes the same four things for that hop: Candor's files nested under a &lt;code&gt;candor&lt;/code&gt; alias folder, a recorded move of the theme undone by &lt;code&gt;migrate paths&lt;/code&gt; (and 3.0's new &lt;code&gt;tokens&lt;/code&gt; stylesheet installed in &lt;code&gt;src/styles/&lt;/code&gt;), the merge base of a file that stays where it is, and a &lt;code&gt;migrate 3.0.0&lt;/code&gt; that didn't say which codemods it skipped. Its notes are in &lt;code&gt;packages/cli/CHANGELOG.md&lt;/code&gt; on that line. Use it, not 1.0.0, for the 2.x → 3.0 upgrade.&lt;/p&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Tabs&lt;/strong&gt; (Pro): its docs page and Markdown opened with the description of &lt;code&gt;tabsListVariants&lt;/code&gt;, since the &lt;code&gt;Tabs&lt;/code&gt; component had no doc comment. It has one now; &lt;code&gt;npx candor-ui update tabs&lt;/code&gt; brings the comment.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.0.1</title>
      <link>https://candor.themethodic.com/changelog#4-0-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-0-1</guid>
      <pubDate>Wed, 11 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A patch release, with CLI 2.0.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.0.0 as before. Some item descriptions, the public README's &lt;code&gt;init --yes&lt;/code&gt; line, and comments in context-menu, schedule-list, details-list and knowledge-sources said Candor's primitives are on Radix; they have been on Base UI since 4.0.0. The Vite and TanStack starters' &lt;code&gt;components.json&lt;/code&gt; now names &lt;code&gt;base-nova&lt;/code&gt;, so &lt;code&gt;shadcn add&lt;/code&gt; there installs shadcn's Base UI components, as in the Next starter.&lt;/p&gt;&lt;p&gt;Nothing to do. The registry and docs carry the corrected descriptions, and &lt;code&gt;npx candor-ui@2 update&lt;/code&gt; brings the corrected comments for the items you have. If your app began as the Vite or TanStack starter at 4.0.0, you can set &lt;code&gt;style&lt;/code&gt; in its &lt;code&gt;components.json&lt;/code&gt; to &lt;code&gt;base-nova&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Candor UI 4.0.0</title>
      <link>https://candor.themethodic.com/changelog#4-0-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#4-0-0</guid>
      <pubDate>Wed, 11 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A major release, with CLI 2.0.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 4.0.0. Candor's primitives are built on Base UI (&lt;code&gt;@base-ui/react&lt;/code&gt;) in place of Radix, and take &lt;code&gt;render&lt;/code&gt; in place of &lt;code&gt;asChild&lt;/code&gt;. Each idea has one prop name across the kit: &lt;code&gt;busy&lt;/code&gt; for waiting, &lt;code&gt;onValueChange&lt;/code&gt; for a callback with the value, &lt;code&gt;headingLevel&lt;/code&gt;, &lt;code&gt;locked&lt;/code&gt; for a control that can't be used, &lt;code&gt;activeId&lt;/code&gt; with &lt;code&gt;onSelect&lt;/code&gt;, and &lt;code&gt;title&lt;/code&gt; for a visible heading. Candor's own tokens take the &lt;code&gt;--cd-&lt;/code&gt; prefix (&lt;code&gt;--cd-sunken&lt;/code&gt;, &lt;code&gt;--cd-warning&lt;/code&gt;), so an app's own &lt;code&gt;--warning&lt;/code&gt; can't collide with them, and its chart series are shadcn's &lt;code&gt;--chart-1&lt;/code&gt; to &lt;code&gt;--chart-5&lt;/code&gt;, with &lt;code&gt;--cd-chart-6&lt;/code&gt; for the sixth. CLI 2.0 runs the upgrade (&lt;code&gt;npx candor-ui@2 update --to 4.0.0&lt;/code&gt;, then &lt;code&gt;npx candor-ui@2 migrate 4.0.0&lt;/code&gt;) and no longer changes a 1.x or 2.x project, which keeps CLI 1. &lt;code&gt;page-header&lt;/code&gt; and &lt;code&gt;page-state&lt;/code&gt; join the free tier, the five presets are renamed &lt;code&gt;*-preset&lt;/code&gt;, and &lt;code&gt;layer&lt;/code&gt; replaces &lt;code&gt;render-prop&lt;/code&gt;, so the kit has 324 items: 73 free and 293 in Pro.&lt;/p&gt;&lt;h3&gt;Upgrading from 3.x&lt;/h3&gt;&lt;p&gt;Start from a committed tree, so you can see what each step changed. Then, from the app's folder (the one with &lt;code&gt;components.json&lt;/code&gt;):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Look first:&lt;/strong&gt; &lt;code&gt;npx candor-ui@2 update --to 4.0.0 --dry-run&lt;/code&gt; prints what 4.0 changes for the items in &lt;code&gt;candor-lock.json&lt;/code&gt;, with the files it would move (the presets' new names), the npm packages it would install (&lt;code&gt;@base-ui/react&lt;/code&gt;) and the merges it would make, and writes nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;code&gt;npx candor-ui@2 update --to 4.0.0&lt;/code&gt; installs &lt;code&gt;@base-ui/react&lt;/code&gt; with your package manager when &lt;code&gt;package.json&lt;/code&gt; doesn't list it (&lt;code&gt;--no-deps&lt;/code&gt; names the command instead), into the package that holds Candor's primitives (in shadcn's monorepo, the shared ui package, not the app), moves each renamed preset's file (&lt;code&gt;github-kinds.ts&lt;/code&gt; to &lt;code&gt;github-preset.ts&lt;/code&gt; …) and points your imports at it, then updates every item, merging your changes into Candor's as &lt;code&gt;update&lt;/code&gt; always has.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Migrate:&lt;/strong&gt; &lt;code&gt;npx candor-ui@2 migrate 4.0.0&lt;/code&gt; runs each of 4.0's codemods that an entry on your installed items names, in this order: &lt;code&gt;as-child&lt;/code&gt;, &lt;code&gt;props&lt;/code&gt;, &lt;code&gt;strings-keys&lt;/code&gt;, &lt;code&gt;tokens&lt;/code&gt;. They change Candor's components only: shadcn's own components in &lt;code&gt;components/ui/&lt;/code&gt; and your own elements stay as they are. Each runs under its own heading, says what it changed, and lists what it couldn't under &amp;quot;Left for you&amp;quot;. Candor's own files aren't rewritten, since &lt;code&gt;update&lt;/code&gt; brings them; in one you've changed, which &lt;code&gt;update&lt;/code&gt;'s merge keeps, each old name or &lt;code&gt;asChild&lt;/code&gt; a codemod finds is listed under &amp;quot;Left for you&amp;quot; with &lt;code&gt;file:line&lt;/code&gt;, for you to change. &lt;code&gt;--dry-run&lt;/code&gt; shows it first.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Finish and check:&lt;/strong&gt; make the changes marked &amp;quot;by hand&amp;quot; below, then type-check (&lt;code&gt;npx tsc --noEmit&lt;/code&gt;) and build. &lt;code&gt;npx candor-ui@2 theme check&lt;/code&gt; reports a token name 4.0 renamed that is still in your CSS as an error, naming &lt;code&gt;migrate tokens&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;code&gt;update&lt;/code&gt;, when it moves files, and &lt;code&gt;migrate&lt;/code&gt; read your source with the project's own TypeScript 5. On TypeScript 7, which has no JavaScript API yet, install 5 for the run and put 7 back after; candor-ui never installs it itself.&lt;/p&gt;&lt;p&gt;Every change, by its id in &lt;code&gt;scripts/breaking.json&lt;/code&gt; (the same entries &lt;code&gt;update --to 4.0.0&lt;/code&gt; prints, and the [Upgrading to 4.0](https://candor.themethodic.com/upgrading-to-4) page lists):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;as-child&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;as-child&lt;/code&gt;): Candor's primitives take &lt;code&gt;render&lt;/code&gt;, not &lt;code&gt;asChild&lt;/code&gt;: &lt;code&gt;&amp;lt;Button render={&amp;lt;a href=&amp;quot;/docs&amp;quot; /&amp;gt;}&amp;gt;Read the docs&amp;lt;/Button&amp;gt;&lt;/code&gt;. An &lt;code&gt;asChild&lt;/code&gt; on one of them fails the type check, and the part draws its own element with the child inside it. The codemod rewrites each one on Candor's components, adds &lt;code&gt;nativeButton={false}&lt;/code&gt; where a Candor part that takes it (Button, and the triggers and closes of Dialog, Popover, Select, Tabs and the others) renders a link, a span or a div, and lists an &lt;code&gt;asChild&lt;/code&gt; it can't follow (no element child, or a value that isn't &lt;code&gt;true&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;primitives-base-ui&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;, and by hand): every one of Candor's 51 primitives is built on Base UI. The codemod renames TooltipProvider's &lt;code&gt;delayDuration&lt;/code&gt;, &lt;code&gt;skipDelayDuration&lt;/code&gt; and &lt;code&gt;disableHoverableContent&lt;/code&gt; to &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt; and &lt;code&gt;disableHoverablePopup&lt;/code&gt;. By hand: a dialog's or popover's &lt;code&gt;onOpenAutoFocus&lt;/code&gt; and &lt;code&gt;onCloseAutoFocus&lt;/code&gt; are &lt;code&gt;initialFocus&lt;/code&gt; and &lt;code&gt;finalFocus&lt;/code&gt; (an element, a ref, or a function that returns one); an &lt;code&gt;onEscapeKeyDown&lt;/code&gt; or &lt;code&gt;onInteractOutside&lt;/code&gt; handler moves into the root's &lt;code&gt;onOpenChange(open, details)&lt;/code&gt;, calling &lt;code&gt;details.cancel()&lt;/code&gt; where you prevented the default; and a style that selects &lt;code&gt;data-state&lt;/code&gt; on them (&lt;code&gt;data-[state=open]&lt;/code&gt;) selects Base UI's attributes instead (&lt;code&gt;data-open&lt;/code&gt;, &lt;code&gt;data-closed&lt;/code&gt;, &lt;code&gt;data-checked&lt;/code&gt; …). A project without &lt;code&gt;@base-ui/react&lt;/code&gt; doesn't build; &lt;code&gt;update&lt;/code&gt; installs it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;direction-moved&lt;/code&gt;&lt;/strong&gt; (by hand): LocaleProvider hands the text direction to Base UI's DirectionProvider, and Candor's locale file no longer passes Radix's &lt;code&gt;Direction&lt;/code&gt; through. &lt;code&gt;TextDirection&lt;/code&gt; and &lt;code&gt;directionOf&lt;/code&gt; are unchanged; code of yours that used Radix's &lt;code&gt;Direction&lt;/code&gt; imports it from &lt;code&gt;radix-ui&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-busy&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;): Combobox's, DataTable's, PromptSuggestions' and ImportReview's &lt;code&gt;loading&lt;/code&gt;, PermissionMode's and MemoryMode's &lt;code&gt;pending&lt;/code&gt;, ClarifyingQuestions' &lt;code&gt;submitting&lt;/code&gt;, WorkflowEditor's &lt;code&gt;saving&lt;/code&gt;, CommandPalette's &lt;code&gt;searching&lt;/code&gt;, AssigneePicker's &lt;code&gt;assigning&lt;/code&gt;, ChangeSetReview's &lt;code&gt;applying&lt;/code&gt;, ShipReview's &lt;code&gt;shipping&lt;/code&gt;, DataImport's &lt;code&gt;reading&lt;/code&gt;, DegradedPanel's &lt;code&gt;retrying&lt;/code&gt; and ChartFrame's &lt;code&gt;refreshing&lt;/code&gt; are &lt;code&gt;busy&lt;/code&gt;, with the same boolean. ChartFrame marks its plot &lt;code&gt;aria-busy&lt;/code&gt; while it is. DataTable's &lt;code&gt;state={{ kind: &amp;quot;loading&amp;quot; }}&lt;/code&gt;, StopAll's &lt;code&gt;inFlight&lt;/code&gt;, ThreadHeader's &lt;code&gt;working&lt;/code&gt; and DocumentProgressQueue's &lt;code&gt;retrying&lt;/code&gt; (a list of ids) are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-on-value-change&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;, and by hand): the &lt;code&gt;onChange&lt;/code&gt; of Composer, DictationButton, PermissionMode, MemoryMode, InstructionsEditor, ModelSettings, ModelPicker, MessageBranches, ColumnMapper, RunScrubber, SoundSetting, CodeEditor and ReviewLadder is &lt;code&gt;onValueChange&lt;/code&gt;, with the same value. An &lt;code&gt;onChange&lt;/code&gt; on an element of your own, such as an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, stays. By hand: &lt;code&gt;composer.onChange&lt;/code&gt; read from the props useCandorChat, useAgUi or useClaudeAgent return is &lt;code&gt;composer.onValueChange&lt;/code&gt; (&lt;code&gt;&amp;lt;Composer {...composer} /&amp;gt;&lt;/code&gt; keeps working), and useDictation's &lt;code&gt;onChange&lt;/code&gt; option is &lt;code&gt;onValueChange&lt;/code&gt;. The type check finds both. NotificationPreferences' and ToolPermissions' &lt;code&gt;onChange&lt;/code&gt;, which report one row's change, are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-heading-level&lt;/code&gt;&lt;/strong&gt; (no codemod: nothing to rename): every prop that sets a heading's level is &lt;code&gt;headingLevel&lt;/code&gt; and takes 1 to 6. A level you pass today still type-checks; code of yours that passes the prop's type to something narrower needs its own type widened.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-locked&lt;/code&gt;&lt;/strong&gt; (by hand): DictationButton's &lt;code&gt;disabled&lt;/code&gt; is &lt;code&gt;locked&lt;/code&gt;, the reason the person is shown: &lt;code&gt;locked={streaming ? &amp;quot;Wait for the reply to finish.&amp;quot; : undefined}&lt;/code&gt;, in your own words. &lt;code&gt;migrate&lt;/code&gt; lists each one under &amp;quot;Left for you&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-active-id&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;): Tree's &lt;code&gt;selectedId&lt;/code&gt; is &lt;code&gt;activeId&lt;/code&gt;, and Plan's &lt;code&gt;activeStepId&lt;/code&gt; and &lt;code&gt;onSelectStep&lt;/code&gt; are &lt;code&gt;activeId&lt;/code&gt; and &lt;code&gt;onSelect&lt;/code&gt;, as in RunTree, SessionList and the other lists.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-title&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;): PromptSuggestions' &lt;code&gt;label&lt;/code&gt;, the heading above the suggestions, is &lt;code&gt;title&lt;/code&gt;. The words under &lt;code&gt;strings.promptSuggestions.label&lt;/code&gt; are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;props-base-ui-names&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;props&lt;/code&gt;, and by hand): CandorConfig's &lt;code&gt;tooltip&lt;/code&gt; takes &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt; and &lt;code&gt;disableHoverablePopup&lt;/code&gt; where it took &lt;code&gt;delayDuration&lt;/code&gt;, &lt;code&gt;skipDelayDuration&lt;/code&gt; and &lt;code&gt;disableHoverableContent&lt;/code&gt;, and gains &lt;code&gt;closeDelay&lt;/code&gt;; the codemod renames them in a &lt;code&gt;tooltip: { … }&lt;/code&gt; object in a file that imports CandorProvider or CandorConfig. By hand: CommandPalette's &lt;code&gt;onCloseAutoFocus&lt;/code&gt; is &lt;code&gt;finalFocus&lt;/code&gt;, which returns where focus goes (&lt;code&gt;finalFocus={() =&amp;gt; el}&lt;/code&gt;, or &lt;code&gt;false&lt;/code&gt; to leave it); &lt;code&gt;migrate&lt;/code&gt; lists each one under &amp;quot;Left for you&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;strings-change-diff&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;): ChangeDiff's strings take its name: the &lt;code&gt;metadataDiff&lt;/code&gt; namespace is &lt;code&gt;changeDiff&lt;/code&gt;, and the &lt;code&gt;metadataDiffStrings&lt;/code&gt; table is &lt;code&gt;changeDiffStrings&lt;/code&gt;. Words given under &lt;code&gt;strings.metadataDiff&lt;/code&gt; aren't read until they move.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;preset-rename&lt;/code&gt;&lt;/strong&gt; (no codemod: &lt;code&gt;update&lt;/code&gt; makes the moves): github-kinds, hubspot-kinds, jira-kinds, linear-kinds and salesforce-kinds are github-preset, hubspot-preset, jira-preset, linear-preset and salesforce-preset, since they hold nouns as well as kinds. Their exports keep their names.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;tokens-cd-prefix&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;tokens&lt;/code&gt;, and by hand): 23 of Candor's colour roles take &lt;code&gt;--cd-&lt;/code&gt; (&lt;code&gt;--sunken&lt;/code&gt; is &lt;code&gt;--cd-sunken&lt;/code&gt;, &lt;code&gt;--warning&lt;/code&gt; is &lt;code&gt;--cd-warning&lt;/code&gt;, and so on for &lt;code&gt;--chrome&lt;/code&gt;, &lt;code&gt;--faint-foreground&lt;/code&gt;, &lt;code&gt;--border-strong&lt;/code&gt;, &lt;code&gt;--primary-hover&lt;/code&gt;, the &lt;code&gt;-weak&lt;/code&gt; and &lt;code&gt;-text&lt;/code&gt; pairs, &lt;code&gt;--on-success&lt;/code&gt;, &lt;code&gt;--on-destructive&lt;/code&gt;, &lt;code&gt;--surface-agent&lt;/code&gt;, &lt;code&gt;--surface-user&lt;/code&gt; and &lt;code&gt;--text-provisional&lt;/code&gt;). &lt;code&gt;--series-1&lt;/code&gt; to &lt;code&gt;--series-5&lt;/code&gt; are &lt;code&gt;--chart-1&lt;/code&gt; to &lt;code&gt;--chart-5&lt;/code&gt;, and &lt;code&gt;--series-6&lt;/code&gt; is &lt;code&gt;--cd-chart-6&lt;/code&gt;. Nothing fails to compile: a brand file that sets an old name no longer reaches Candor, and an app's shadcn chart colours now restyle Candor's charts too. shadcn's own tokens and the Tailwind classes (&lt;code&gt;bg-sunken&lt;/code&gt;, &lt;code&gt;text-warning-text&lt;/code&gt;) don't change. The codemod renames them in your stylesheets and, in your source, where a string reads or sets one: inside &lt;code&gt;var()&lt;/code&gt;, in Tailwind's arbitrary values (&lt;code&gt;bg-[var(--sunken)]&lt;/code&gt;), as a style object's key and in &lt;code&gt;setProperty&lt;/code&gt;. Other strings that look like a token, such as a script's &lt;code&gt;--chrome&lt;/code&gt; flag, stay. By hand: a file that sets both &lt;code&gt;--series-N&lt;/code&gt; and &lt;code&gt;--chart-N&lt;/code&gt; is listed under &amp;quot;Left for you&amp;quot;, for you to choose the colour. The codemod can't tell a variable your app defines for itself from Candor's, so it renames those too: if your app had its own &lt;code&gt;--warning&lt;/code&gt; (or another of these names), rename yours back after migrating. &lt;code&gt;npx candor-ui@2 theme check&lt;/code&gt;, run before migrating, lists each place your CSS sets or reads one of these names, with its file and line, and &lt;code&gt;migrate tokens --dry-run&lt;/code&gt; lists every rename it would make.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Also:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;A Radix app keeps its own primitives.&lt;/strong&gt; shadcn's components in &lt;code&gt;components/ui/&lt;/code&gt; and the &lt;code&gt;radix-ui&lt;/code&gt; package stay yours; Candor's Base UI primitives sit beside them in &lt;code&gt;components/candor/ui/&lt;/code&gt;, so the app carries both libraries. In a test Next.js app, six Radix primitives were 57.4 KB of client JavaScript (gzip), and the same six on Base UI added 68.3 KB. A Candor dialog, popover, select or tooltip opened inside or beside the app's own Radix dialog takes the pointer, focus and Escape (&lt;code&gt;foundation/layer&lt;/code&gt;, checked in Chromium and WebKit).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Stored styles are data, not source.&lt;/strong&gt; No codemod reaches a theme saved in a database or a CMS: rename its tokens once, where it is stored.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;3.x stays installable.&lt;/strong&gt; &lt;code&gt;https://candor.themethodic.com/r/v/3.0.0/&amp;lt;name&amp;gt;.json&lt;/code&gt; serves every item as 3.0.0 shipped it, with the same licence check, and &lt;code&gt;npx candor-ui add &amp;lt;item&amp;gt; --version 3.0.0&lt;/code&gt; installs from there. Your licence covers 4.0 as it does every version.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A 2.x project upgrades to 3.0 first,&lt;/strong&gt; with CLI 1: &lt;code&gt;npx candor-ui@1 update --to 3.0.0&lt;/code&gt;, then &lt;code&gt;npx candor-ui@1 migrate 3.0.0&lt;/code&gt; ([Upgrading to 3.0](https://candor.themethodic.com/upgrading-to-3)). CLI 2.0 names those commands and changes nothing in a 2.x project.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Primitives on Base UI&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Candor's API is kept&lt;/strong&gt; where Base UI's differs: &lt;code&gt;side&lt;/code&gt;, &lt;code&gt;align&lt;/code&gt; and the other placement props on the content part, Accordion's and ToggleGroup's &lt;code&gt;type=&amp;quot;single&amp;quot; | &amp;quot;multiple&amp;quot;&lt;/code&gt; with string values, Checkbox's &lt;code&gt;checked=&amp;quot;indeterminate&amp;quot;&lt;/code&gt;, Select's string value with &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; for none (SelectValue shows the chosen item's text before the list has been opened), Slider's &lt;code&gt;number[]&lt;/code&gt; with &lt;code&gt;onValueCommit&lt;/code&gt;, Tabs' &lt;code&gt;activationMode&lt;/code&gt;, menu items' &lt;code&gt;onSelect&lt;/code&gt; (where &lt;code&gt;preventDefault()&lt;/code&gt; keeps the menu open), and a checkbox or radio menu item closing the menu once ticked (&lt;code&gt;closeOnClick={false}&lt;/code&gt; keeps it open). Accordion keeps arrow-key movement between headings. An &lt;code&gt;onClick&lt;/code&gt; that calls &lt;code&gt;preventDefault()&lt;/code&gt; on a dialog's close part still keeps it open.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;What you'll notice:&lt;/strong&gt; Escape closes a submenu before its menu; Tab, not ArrowDown, enters a navigation menu's panel, and its panels open in one shared box (&lt;code&gt;viewport={false}&lt;/code&gt; only sets &lt;code&gt;data-viewport&lt;/code&gt;); and a dialog opened from inside another doesn't close on an outside click. Their state shows in Base UI's attributes (&lt;code&gt;data-open&lt;/code&gt;, &lt;code&gt;data-checked&lt;/code&gt;, &lt;code&gt;data-pressed&lt;/code&gt; …), which the kit's own classes, the forced-colours styles and the motion families read.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Size:&lt;/strong&gt; the 51 ui modules are 186.4 KB gzip, from 131.3 KB on Radix.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Firefox:&lt;/strong&gt; the layer and browser checks ran in Chromium and WebKit for this release; Firefox didn't run.&lt;/li&gt;&lt;li&gt;The free &lt;code&gt;layer&lt;/code&gt; item (&lt;code&gt;foundation/layer&lt;/code&gt;) holds what makes Candor's layers work inside another library's modal dialog; &lt;code&gt;render-prop&lt;/code&gt; (&lt;code&gt;withRender&lt;/code&gt;, &lt;code&gt;RenderProp&lt;/code&gt;) is removed.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components and the free tier&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;page-header&lt;/code&gt; and &lt;code&gt;page-state&lt;/code&gt; are free&lt;/strong&gt; (MIT), each with a docs example. &lt;code&gt;page-state&lt;/code&gt; holds the &lt;code&gt;ListState&lt;/code&gt; type, so the free item doesn't import the Pro &lt;code&gt;data&lt;/code&gt;, which declares the same type.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Registry categories take the source folders' names:&lt;/strong&gt; an item's &lt;code&gt;categories&lt;/code&gt; in &lt;code&gt;/r/&amp;lt;name&amp;gt;.json&lt;/code&gt; say &lt;code&gt;foundation&lt;/code&gt; where they said &lt;code&gt;lib&lt;/code&gt;, &lt;code&gt;parts&lt;/code&gt; where they said &lt;code&gt;blocks&lt;/code&gt;, and &lt;code&gt;blocks&lt;/code&gt; where they said &lt;code&gt;blocks-full&lt;/code&gt;. The docs' group titles are the same. &lt;code&gt;locale&lt;/code&gt; and &lt;code&gt;locked&lt;/code&gt; keep their install paths.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; holds a locked control still by every route.&lt;/strong&gt; A locked Checkbox, Switch or Radio no longer changes when its label is clicked or its form is reset, and a locked Select's or Menu's trigger no longer opens on a press or an arrow key.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tooltips describe their trigger&lt;/strong&gt; to screen readers (&lt;code&gt;aria-describedby&lt;/code&gt;) while open, so a reason given only in a tooltip, such as a locked permission's, is read out. A new &lt;code&gt;describes&lt;/code&gt; prop on Tooltip turns it off; &lt;code&gt;Locked&lt;/code&gt; does, since it describes the control itself.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;standardCards&lt;/code&gt;&lt;/strong&gt; keep their English export and gain &lt;code&gt;standardCardsStrings&lt;/code&gt; and &lt;code&gt;useStandardCards()&lt;/code&gt;, so the cards' labels and check messages can be translated.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DictationButton&lt;/strong&gt; says &amp;quot;Transcribing…&amp;quot; while it transcribes, and is &lt;code&gt;aria-disabled&lt;/code&gt; rather than &lt;code&gt;disabled&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;BulletBar's&lt;/strong&gt; met target uses the success colour, not a chart series.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Layers in a dialog that clips its content:&lt;/strong&gt; inside a scrolling dialog, Candor's popovers, menus and tooltips show in the browser's top layer, so the dialog doesn't clip them. The known limit: a Radix layer opened from inside one of them is drawn under it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks and templates (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;About 840 strings&lt;/strong&gt; in eleven blocks and four templates now go through their string tables: page titles, empty states, errors, forms, attribute text and the approve-from-anywhere email copy (&lt;code&gt;approvalEmailStrings&lt;/code&gt;, and &lt;code&gt;approvalEmail(r, t)&lt;/code&gt; takes an optional translator). The project workspace's amounts and the support copilot's pass rate go through the locale's formatters. Server-side sentences (there's no LocaleProvider there) and brand props stay typed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Breaking: the card maps are hooks.&lt;/strong&gt; Each block's and template's map of standard cards is built from its string table by a hook (&lt;code&gt;useCostCards()&lt;/code&gt;, &lt;code&gt;useDataCards()&lt;/code&gt;, &lt;code&gt;useEvalCards()&lt;/code&gt;, &lt;code&gt;useEvalDashCards()&lt;/code&gt;, &lt;code&gt;useKbCards()&lt;/code&gt;, &lt;code&gt;useOpsCards()&lt;/code&gt;, &lt;code&gt;useRunCards()&lt;/code&gt;, &lt;code&gt;useSupportCards()&lt;/code&gt;, &lt;code&gt;useCopilotCards()&lt;/code&gt;), so the cards' labels and &lt;code&gt;check&lt;/code&gt; messages follow the locale. The module constants (&lt;code&gt;costCards&lt;/code&gt; and the rest) are gone: code that imported one calls the hook inside a component instead.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ChangeSetReview's keyboard hint&lt;/strong&gt; takes its separators and key pairs from its strings (&lt;code&gt;hintEither&lt;/code&gt;, &lt;code&gt;hintItem&lt;/code&gt;, &lt;code&gt;hintSeparator&lt;/code&gt;), so a translation can change them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;setAddress()&lt;/code&gt; in three templates:&lt;/strong&gt; the approvals inbox, the support copilot and the project workspace take the router's address through &lt;code&gt;setAddress()&lt;/code&gt; and &lt;code&gt;useAddress()&lt;/code&gt;, as the ops console does. The project workspace reads it, so it now follows a move between pages.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 4.0.0&lt;/h3&gt;&lt;p&gt;The package's version is the kit's again (3.0's was 3.0.1). It depends on &lt;code&gt;@base-ui/react&lt;/code&gt; in place of &lt;code&gt;radix-ui&lt;/code&gt;, and exports &lt;code&gt;page-header&lt;/code&gt; and &lt;code&gt;page-state&lt;/code&gt; with the other free items. The free items' changes above are in this version; in a project that uses the package, &lt;code&gt;npx candor-ui@2 migrate 4.0.0&lt;/code&gt; runs every 4.0 codemod (there is no &lt;code&gt;candor-lock.json&lt;/code&gt; to choose from).&lt;/p&gt;&lt;h3&gt;CLI 2.0.0&lt;/h3&gt;&lt;p&gt;2.0 because it drops support for kit 1.x and 2.x projects. It works with Candor 3.0 and later; &lt;code&gt;npx candor-ui@1&lt;/code&gt; stays on npm for a 1.x or 2.x project, which &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;migrate&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; send there without changing anything.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Removed:&lt;/strong&gt; the 15 &lt;code&gt;v3-*&lt;/code&gt; lint and audit rules and audit's &amp;quot;What 3.0 changes&amp;quot; group; the 2.x → 3.0 codemods (&lt;code&gt;orgdata&lt;/code&gt;, &lt;code&gt;metadata-diff&lt;/code&gt;, &lt;code&gt;card&lt;/code&gt;, &lt;code&gt;terms&lt;/code&gt;, &lt;code&gt;paths&lt;/code&gt;, &lt;code&gt;refusal&lt;/code&gt;); &lt;code&gt;migrate --for&lt;/code&gt; and &lt;code&gt;update --no-move&lt;/code&gt;; and the 2.x branches in &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;doctor&lt;/code&gt; and the &lt;code&gt;@candor-ui/react&lt;/code&gt; findings.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Kept:&lt;/strong&gt; &lt;code&gt;strings-keys&lt;/code&gt; and &lt;code&gt;motion-aliases&lt;/code&gt;, since a 3.0 project can still have what they change; and &lt;code&gt;update&lt;/code&gt;'s moves, for a release that renames an item.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate 4.0.0&lt;/code&gt;&lt;/strong&gt;, new, runs &lt;code&gt;as-child&lt;/code&gt;, &lt;code&gt;props&lt;/code&gt;, &lt;code&gt;strings-keys&lt;/code&gt; and &lt;code&gt;tokens&lt;/code&gt;, each on Candor's components only. &lt;code&gt;as-child&lt;/code&gt;, &lt;code&gt;props&lt;/code&gt; and &lt;code&gt;tokens&lt;/code&gt; are new; &lt;code&gt;strings-keys&lt;/code&gt; gains &lt;code&gt;metadataDiff&lt;/code&gt; → &lt;code&gt;changeDiff&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update&lt;/code&gt; installs the npm packages&lt;/strong&gt; the new versions declare that &lt;code&gt;package.json&lt;/code&gt; doesn't list, with the project's package manager, as &lt;code&gt;add&lt;/code&gt; does: a 3.0 app gets &lt;code&gt;@base-ui/react&lt;/code&gt;. &lt;code&gt;--no-deps&lt;/code&gt; names the command instead, &lt;code&gt;--dry-run&lt;/code&gt; says what it would run, and a failed install exits 1.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update&lt;/code&gt; moves the renamed presets&lt;/strong&gt; (&lt;code&gt;github-kinds&lt;/code&gt; to &lt;code&gt;github-preset&lt;/code&gt; and the other four) and points your imports at them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;init --yes&lt;/code&gt; sets up a Base UI project&lt;/strong&gt; (&lt;code&gt;--base base&lt;/code&gt;, shadcn's nova preset), as &lt;code&gt;shadcn init&lt;/code&gt; does by default.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme check&lt;/code&gt;&lt;/strong&gt; against a 4.x kit reports a 3.x token name, set or read with &lt;code&gt;var()&lt;/code&gt;, as an error that names &lt;code&gt;migrate tokens&lt;/code&gt;, and token errors now fail the check.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; and &lt;code&gt;doctor&lt;/code&gt;&lt;/strong&gt; say that Candor's primitives are built on Base UI: on a Base UI project they're the app's own library, and on a Radix or React Aria one they install in &lt;code&gt;components/candor/ui/&lt;/code&gt; with &lt;code&gt;@base-ui/react&lt;/code&gt;, beside the app's. The 2.x note that they install as Radix versions is gone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --to 4.0.0&lt;/code&gt;&lt;/strong&gt; ends its list of breaking changes with a link to the Upgrading to 4.0 page.&lt;/li&gt;&lt;li&gt;Fixes: with items named, &lt;code&gt;update --to&lt;/code&gt;'s heading names them, not &amp;quot;the items in candor-lock.json&amp;quot;; &lt;code&gt;update --to&lt;/code&gt; a version that is not released yet for an item the lockfile doesn't record says its version is unknown and how to give it; a snapshot whose breaking entries couldn't be read is named, not dropped without a word; the line after &lt;code&gt;update&lt;/code&gt; installs a Candor item says &amp;quot;the version this update moved to&amp;quot;, not &amp;quot;the version you asked for with --version&amp;quot;; and a registry that still serves an item under its old name updates it in place.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate&lt;/code&gt; fixes:&lt;/strong&gt; &lt;code&gt;tokens&lt;/code&gt; renames a token in source only inside &lt;code&gt;var()&lt;/code&gt;, Tailwind's arbitrary values, a style object's key and &lt;code&gt;setProperty&lt;/code&gt; (it had renamed any string that looked like one, such as a &lt;code&gt;--chrome&lt;/code&gt; flag); &lt;code&gt;as-child&lt;/code&gt; reads &lt;code&gt;.js&lt;/code&gt; and &lt;code&gt;.mjs&lt;/code&gt; files as well as &lt;code&gt;.jsx&lt;/code&gt; and &lt;code&gt;.tsx&lt;/code&gt;; in a monorepo, the codemods read the shared ui package's source, and &lt;code&gt;tokens&lt;/code&gt; reads the stylesheet &lt;code&gt;components.json&lt;/code&gt; names, wherever it is; and &lt;code&gt;as-child&lt;/code&gt; adds &lt;code&gt;nativeButton={false}&lt;/code&gt; on every Candor part whose Base UI part takes it, not only Button.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; and &lt;code&gt;migrate&lt;/code&gt; refuse a 2.x project&lt;/strong&gt; and name CLI 1, as &lt;code&gt;update&lt;/code&gt; does: &lt;code&gt;add&lt;/code&gt; without &lt;code&gt;--version&lt;/code&gt;, and &lt;code&gt;migrate&lt;/code&gt; with no lockfile, working the version out from what is installed.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Upgrading to 4.0&lt;/strong&gt;, new at &lt;code&gt;/upgrading-to-4&lt;/code&gt; (and &lt;code&gt;/upgrading-to-4.md&lt;/code&gt;): the commands, then every entry of the 4.0 list with what breaks, where it shows, what to do and its codemod, built from the same list &lt;code&gt;update&lt;/code&gt; prints. &lt;code&gt;/upgrading-to-3&lt;/code&gt; stays for 2.x projects.&lt;/li&gt;&lt;li&gt;The Design page and the Theme docs show the &lt;code&gt;--cd-&lt;/code&gt; names and the chart series on &lt;code&gt;--chart-*&lt;/code&gt;. The docs pages for the presets are at their new names, and the old addresses redirect; &lt;code&gt;/docs/render-prop&lt;/code&gt; goes to the upgrade page.&lt;/li&gt;&lt;li&gt;The README, the install notes for coding agents and Get started say that &lt;code&gt;init --yes&lt;/code&gt; sets up Base UI, and that Candor's primitives are built on it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Theme builder&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;A theme saved from 3.x loads:&lt;/strong&gt; the builder reads a downloaded theme's 3.x token names (&lt;code&gt;--sunken&lt;/code&gt;, &lt;code&gt;--series-1&lt;/code&gt;) as their 4.0 names.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For contributors&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;'s &amp;quot;Both primitive worlds&amp;quot; is &amp;quot;Base UI primitives&amp;quot;. &lt;code&gt;scripts/fresh-app.mjs --radix&lt;/code&gt; builds a shadcn Radix app and runs the layer checks (&lt;code&gt;tests/browser/layers.mjs&lt;/code&gt;) in it.&lt;/li&gt;&lt;li&gt;&lt;code&gt;node scripts/upgrade-check.mjs --from 3.0.0&lt;/code&gt; upgrades a 3.0 fixture project with &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;migrate&lt;/code&gt; and builds it, in the normal flow, on Base UI and in a Radix app; &lt;code&gt;release:check&lt;/code&gt; runs it with &lt;code&gt;--fresh&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;tests/templates/strings.test.tsx&lt;/code&gt; fails on typed English in any block or template, with an empty allowlist.&lt;/li&gt;&lt;li&gt;A test fails when a &lt;code&gt;scripts/breaking.json&lt;/code&gt; 4.0 entry isn't named in this section and on the upgrade page.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 3.0.0</title>
      <link>https://candor.themethodic.com/changelog#3-0-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#3-0-0</guid>
      <pubDate>Tue, 10 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A major release, with CLI 1.0.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 3.0.1. Candor's files install in folders of their own (&lt;code&gt;components/candor/&lt;/code&gt;, &lt;code&gt;components/candor/ui/&lt;/code&gt; and &lt;code&gt;lib/candor/&lt;/code&gt;), so they no longer sit among your app's files. The app's nouns move from &lt;code&gt;TermsProvider&lt;/code&gt; into &lt;code&gt;LocaleProvider&lt;/code&gt;, where they become arguments of its messages, with plural forms and gendered selects. The names 2.x marked for removal are gone. &lt;code&gt;npx candor-ui@1 update --to 3.0.0&lt;/code&gt; carries a 2.x project across: it moves Candor's files, points your imports at them and updates, and &lt;code&gt;npx candor-ui@1 migrate 3.0.0&lt;/code&gt; then runs the release's codemods. No item is new and &lt;code&gt;metadata-diff&lt;/code&gt; is renamed &lt;code&gt;change-diff&lt;/code&gt;; the free &lt;code&gt;terms&lt;/code&gt; item is removed, so the kit goes from 325 to 324 items: 71 free and 293 in Pro.&lt;/p&gt;&lt;h3&gt;Upgrading from 2.x&lt;/h3&gt;&lt;p&gt;Start from a committed tree, so you can see what each step changed. Then, from the app's folder (the one with &lt;code&gt;components.json&lt;/code&gt;):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Look first:&lt;/strong&gt; &lt;code&gt;npx candor-ui@1 update --to 3.0.0 --dry-run&lt;/code&gt; prints what 3.0 changes for the items in &lt;code&gt;candor-lock.json&lt;/code&gt;, with the moves and merges the update would make, and writes nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;code&gt;npx candor-ui@1 update --to 3.0.0&lt;/code&gt; moves Candor's files to &lt;code&gt;components/candor/&lt;/code&gt; and &lt;code&gt;lib/candor/&lt;/code&gt;, copies Candor's ui primitives to &lt;code&gt;components/candor/ui/&lt;/code&gt;, points the imports in your project at the new places, records the moves in &lt;code&gt;candor-lock.json&lt;/code&gt;, and then updates every item, merging your changes into Candor's as &lt;code&gt;update&lt;/code&gt; always has. &lt;code&gt;components/ui/&lt;/code&gt; stays: from now on it is yours, and candor-ui doesn't update it. An item 3.0 no longer has (&lt;code&gt;terms&lt;/code&gt;) is listed, left where it is and dropped from &lt;code&gt;candor-lock.json&lt;/code&gt;. &lt;code&gt;--no-move&lt;/code&gt; keeps CLI 0.15's behaviour, which stops and names the moves instead of making them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Migrate:&lt;/strong&gt; &lt;code&gt;npx candor-ui@1 migrate 3.0.0&lt;/code&gt; runs each of 3.0's codemods that an entry on your installed items names, in this order: &lt;code&gt;metadata-diff&lt;/code&gt;, &lt;code&gt;paths&lt;/code&gt;, &lt;code&gt;orgdata&lt;/code&gt;, &lt;code&gt;card&lt;/code&gt;, &lt;code&gt;terms&lt;/code&gt;, &lt;code&gt;strings-keys&lt;/code&gt;, &lt;code&gt;refusal&lt;/code&gt;, &lt;code&gt;motion-aliases&lt;/code&gt;. Each runs under its own heading, says what it changed, and lists what it couldn't under &amp;quot;Left for you&amp;quot;. &lt;code&gt;--dry-run&lt;/code&gt; shows it first.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Finish and check:&lt;/strong&gt; make the changes marked &amp;quot;by hand&amp;quot; below, then type-check (&lt;code&gt;npx tsc --noEmit&lt;/code&gt;) and build. On a project whose &lt;code&gt;candor-lock.json&lt;/code&gt; records 3.x, &lt;code&gt;npx candor-ui lint&lt;/code&gt; reports a name 3.0 removed that is still in your code as an error, naming its codemod.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;code&gt;update&lt;/code&gt;, when it moves files, and &lt;code&gt;migrate&lt;/code&gt; read your source with the project's own TypeScript 5. On TypeScript 7, which has no JavaScript API yet, install 5 for the run and put 7 back after; candor-ui never installs it itself.&lt;/p&gt;&lt;p&gt;Every change, by its id in &lt;code&gt;scripts/breaking.json&lt;/code&gt; (the same entries &lt;code&gt;update --to 3.0.0&lt;/code&gt; prints, and the [Upgrading to 3.0](https://candor.themethodic.com/upgrading-to-3) page lists):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;paths&lt;/code&gt;&lt;/strong&gt; (codemod: &lt;code&gt;update --to 3.0.0&lt;/code&gt; makes the moves; &lt;code&gt;migrate paths --for 3.0.0&lt;/code&gt; makes them on their own): imports of an item at its 2.x path (&lt;code&gt;@/components/thread&lt;/code&gt;, &lt;code&gt;@/lib/chat&lt;/code&gt;) stop resolving once its file has moved.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;metadata-diff&lt;/code&gt;&lt;/strong&gt; (codemod: &lt;code&gt;update&lt;/code&gt; moves the file, then &lt;code&gt;migrate metadata-diff&lt;/code&gt; renames the import and the tag): &lt;code&gt;MetadataDiff&lt;/code&gt; is removed and the item is renamed &lt;code&gt;change-diff&lt;/code&gt;, so it installs as &lt;code&gt;components/candor/change-diff.tsx&lt;/code&gt;. Import &lt;code&gt;ChangeDiff&lt;/code&gt;; the props are the same. Before the update, &lt;code&gt;migrate metadata-diff&lt;/code&gt; refuses without &lt;code&gt;--for 3.0.0&lt;/code&gt;, since 2.x's &lt;code&gt;add&lt;/code&gt; still installs &lt;code&gt;metadata-diff.tsx&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;orgdata&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;orgdata&lt;/code&gt;): the &lt;code&gt;orgData&lt;/code&gt; inline node is removed. A block built as &lt;code&gt;{ kind: &amp;quot;orgData&amp;quot;, … }&lt;/code&gt; fails the type check; in untyped data (a server's JSON, stored messages) nothing is drawn where the node was, though the message's plain-text copy keeps its text. Use &lt;code&gt;kind: &amp;quot;measured&amp;quot;&lt;/code&gt;; the fields are the same.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;card&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;card&lt;/code&gt;): card-registry's &lt;code&gt;Card&lt;/code&gt;, its first name for &lt;code&gt;RegistryCard&lt;/code&gt;, is removed. Import &lt;code&gt;RegistryCard&lt;/code&gt;; the props are the same. shadcn's own &lt;code&gt;Card&lt;/code&gt; is not affected.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;terms&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;terms&lt;/code&gt;): &lt;code&gt;TermsProvider&lt;/code&gt;, &lt;code&gt;useTerms&lt;/code&gt;, &lt;code&gt;capitalise&lt;/code&gt;, the &lt;code&gt;Terms&lt;/code&gt; type and the &lt;code&gt;terms&lt;/code&gt; item are removed. The app's nouns are set on &lt;code&gt;LocaleProvider&lt;/code&gt; as &lt;code&gt;nouns&lt;/code&gt;, or as &lt;code&gt;CandorProvider&lt;/code&gt;'s &lt;code&gt;config.nouns&lt;/code&gt;, and fill &lt;code&gt;{environment}&lt;/code&gt;, &lt;code&gt;{Environment}&lt;/code&gt;, &lt;code&gt;{account}&lt;/code&gt; and &lt;code&gt;{product}&lt;/code&gt; in every message. &lt;code&gt;useNouns()&lt;/code&gt; and &lt;code&gt;startOf()&lt;/code&gt; replace &lt;code&gt;useTerms()&lt;/code&gt; and &lt;code&gt;capitalise()&lt;/code&gt;, &lt;code&gt;NounTable&lt;/code&gt; and &lt;code&gt;Nouns&lt;/code&gt; replace &lt;code&gt;Terms&lt;/code&gt;, and the presets are &lt;code&gt;githubNouns&lt;/code&gt;, &lt;code&gt;hubspotNouns&lt;/code&gt;, &lt;code&gt;jiraNouns&lt;/code&gt; and &lt;code&gt;linearNouns&lt;/code&gt;. The codemod rewrites each of these and lists what it can't follow (a re-export under the old name, &lt;code&gt;terms&lt;/code&gt; through an untyped spread); then delete the installed &lt;code&gt;terms&lt;/code&gt; file, whose path the codemod names, once nothing imports it. Your 2.x words work as they are; add plural forms where a message counts them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;message-thinking&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;): Message's working line reads only &lt;code&gt;message.working&lt;/code&gt;. An override of &lt;code&gt;message.thinking&lt;/code&gt; alone shows Candor's own &amp;quot;Working&amp;quot; again. The codemod renames the key, unless &lt;code&gt;working&lt;/code&gt; is already there.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;answering-approvals-strings&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;strings-keys&lt;/code&gt;): &lt;code&gt;useAnsweringApprovals&lt;/code&gt;' words are read only under &lt;code&gt;answeringApprovals&lt;/code&gt; in LocaleProvider's &lt;code&gt;strings&lt;/code&gt;. An override under &lt;code&gt;useAnsweringApprovals&lt;/code&gt; shows Candor's own sentence again when an answer fails to send. The codemod moves it, in an object given as &lt;code&gt;strings&lt;/code&gt; or typed &lt;code&gt;StringOverrides&lt;/code&gt; or &lt;code&gt;CandorConfig&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;block-refusal-export&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;refusal&lt;/code&gt;): the &lt;code&gt;Refusal&lt;/code&gt; re-export from the stores of plan-build-review, run-console, agent-ops-console and project-workspace is removed. Import &lt;code&gt;Refusal&lt;/code&gt; from the server foundation, &lt;code&gt;@/lib/candor/candor-server&lt;/code&gt; in a default install; it is the same class.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;motion-aliases&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;motion-aliases&lt;/code&gt;): the 2.2 motion tokens &lt;code&gt;--cd-pop-from&lt;/code&gt; and &lt;code&gt;--cd-motion-shake&lt;/code&gt; are no longer read, and &lt;code&gt;data-motion=&amp;quot;expressive&amp;quot;&lt;/code&gt; no longer sets their presets. &lt;code&gt;--cd-pop-from&lt;/code&gt; becomes &lt;code&gt;--cd-motion-pop-scale&lt;/code&gt;, which applies from the expressive level only. &lt;code&gt;--cd-motion-shake&lt;/code&gt; has no single replacement, so the codemod lists it under &amp;quot;Left for you&amp;quot;: set the refuse family's &lt;code&gt;--cd-motion-refuse-distance&lt;/code&gt;, &lt;code&gt;-dur&lt;/code&gt; and &lt;code&gt;-ease&lt;/code&gt;, or its level, &lt;code&gt;--cd-motion-refuse&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;legacy-animations&lt;/code&gt;&lt;/strong&gt; (codemod &lt;code&gt;motion-aliases&lt;/code&gt;): the 2.2 &lt;code&gt;animate-*&lt;/code&gt; utilities (&lt;code&gt;animate-shimmer&lt;/code&gt;, &lt;code&gt;-pulse-dot&lt;/code&gt;, &lt;code&gt;-rise-in&lt;/code&gt;, &lt;code&gt;-caret&lt;/code&gt;, &lt;code&gt;-collapse-down&lt;/code&gt;, &lt;code&gt;-collapse-up&lt;/code&gt;, &lt;code&gt;-pop-in&lt;/code&gt;, &lt;code&gt;-pop-out&lt;/code&gt;, &lt;code&gt;-tick-draw&lt;/code&gt;, &lt;code&gt;-fill&lt;/code&gt;, &lt;code&gt;-shake&lt;/code&gt;, &lt;code&gt;-attention&lt;/code&gt;, &lt;code&gt;-attention-wait&lt;/code&gt;, &lt;code&gt;-nudge&lt;/code&gt;) are removed, with the unprefixed keyframes only they ran. A class such as &lt;code&gt;animate-pop-in&lt;/code&gt; stops animating, and &lt;code&gt;animation: pop-in …&lt;/code&gt; finds no keyframes. The codemod moves classes to the motion families' &lt;code&gt;cd-*&lt;/code&gt; utilities and renames keyframes where the frames are the same; it lists &lt;code&gt;animate-attention-wait&lt;/code&gt;, &lt;code&gt;animate-shimmer&lt;/code&gt; and the &lt;code&gt;pop-out&lt;/code&gt;, &lt;code&gt;collapse-*&lt;/code&gt; and &lt;code&gt;shake&lt;/code&gt; keyframes with what to do for each. The &lt;code&gt;shimmer&lt;/code&gt; keyframes stay, for &lt;code&gt;shimmer-text&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;attention-kinds&lt;/code&gt;&lt;/strong&gt; (by hand): &lt;code&gt;AttentionKind&lt;/code&gt; gains &lt;code&gt;reply&lt;/code&gt; and &lt;code&gt;silent&lt;/code&gt;. A &lt;code&gt;Record&amp;lt;AttentionKind, number&amp;gt;&lt;/code&gt; built by hand needs &lt;code&gt;reply: 0, silent: 0&lt;/code&gt;, and an exhaustive &lt;code&gt;switch&lt;/code&gt; needs both cases or a &lt;code&gt;default&lt;/code&gt;. Code that only reads &lt;code&gt;counts.approval&lt;/code&gt; and the like changes nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;attention-sound-when&lt;/code&gt;&lt;/strong&gt; (by hand): &lt;code&gt;useAttention&lt;/code&gt;'s sound plays only while the window isn't in front of the person, unless you pass &lt;code&gt;when: &amp;quot;always&amp;quot;&lt;/code&gt;, 2.x's behaviour. Nothing fails to compile, so check every &lt;code&gt;useAttention&lt;/code&gt; with a &lt;code&gt;sound&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;block-viewer-of&lt;/code&gt;&lt;/strong&gt; (by hand): the blocks' and templates' &lt;code&gt;viewerOf(request)&lt;/code&gt; is removed. Use &lt;code&gt;getViewer(request)&lt;/code&gt; or &lt;code&gt;viewerName(request)&lt;/code&gt; from &lt;code&gt;@/lib/candor/candor-server&lt;/code&gt;; both are async and answer null when nobody is signed in, where &lt;code&gt;viewerOf&lt;/code&gt; gave the demo person.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;block-context-of&lt;/code&gt;&lt;/strong&gt; (by hand): &lt;code&gt;contextOf(request)&lt;/code&gt; in audit-data-controls' and approvals-inbox's stores is removed. Use &lt;code&gt;signedInContext(request)&lt;/code&gt; from the same store: it is async and answers null when nobody is signed in.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;inbox-post&lt;/code&gt;&lt;/strong&gt; (by hand): approvals-inbox's &lt;code&gt;post(body)&lt;/code&gt; is removed. Use &lt;code&gt;usePost()&lt;/code&gt; from the same file in a component; it says its errors in LocaleProvider's words.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;block-db-connect&lt;/code&gt;&lt;/strong&gt; (by hand): the fifteen blocks' and templates' &lt;code&gt;db/connect.ts&lt;/code&gt; files are removed; each store opens the shared pool through &lt;code&gt;database()&lt;/code&gt; from &lt;code&gt;@/lib/candor/candor-database&lt;/code&gt;. If you swapped the driver or the URL in &lt;code&gt;db/connect.ts&lt;/code&gt;, give your database to &lt;code&gt;setDatabase()&lt;/code&gt; once at startup instead. &lt;code&gt;update&lt;/code&gt; leaves your old &lt;code&gt;db/connect.ts&lt;/code&gt; in place, with its imports pointed at the new places; delete it once nothing imports it.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Also:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Stored &lt;code&gt;orgData&lt;/code&gt; messages are data, not source.&lt;/strong&gt; No codemod reaches a database or a saved conversation: change their &lt;code&gt;kind&lt;/code&gt; from &lt;code&gt;orgData&lt;/code&gt; to &lt;code&gt;measured&lt;/code&gt; once, where they are stored.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;2.x stays installable.&lt;/strong&gt; &lt;code&gt;https://candor.themethodic.com/r/v/2.10.0/&amp;lt;name&amp;gt;.json&lt;/code&gt; serves every item as 2.10.0 shipped it, with the same licence check, and &lt;code&gt;npx candor-ui add &amp;lt;item&amp;gt; --version 2.10.0&lt;/code&gt; installs from there. Your licence covers 3.0 as it does every version.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Monorepos need CLI 1.0.&lt;/strong&gt; 3.0 installs Candor's primitives in the app (&lt;code&gt;components/candor/ui/&lt;/code&gt;), not in the shared ui package, and only CLI 1.0 follows that.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; at 3.0 on a 2.x project stops&lt;/strong&gt; (CLI 1.0) and names &lt;code&gt;update --to 3.0.0&lt;/code&gt;, so a 3.0 item never lands among 2.x files. To add to a 2.x project without upgrading, pass &lt;code&gt;--version 2.10.0&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OrgSmith's pack is no longer built here:&lt;/strong&gt; &lt;code&gt;public/orgsmith&lt;/code&gt; is gone from the product build, and OrgSmith uses the &lt;code&gt;v2.10.0&lt;/code&gt; tag's copy until its own repository exists. No &lt;code&gt;@candor&lt;/code&gt; item changes because of it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Install paths&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Candor's files are in folders of their own.&lt;/strong&gt; A component installs at &lt;code&gt;components/candor/&amp;lt;name&amp;gt;.tsx&lt;/code&gt;, a ui primitive at &lt;code&gt;components/candor/ui/&amp;lt;name&amp;gt;.tsx&lt;/code&gt;, and a shared helper or type at &lt;code&gt;lib/candor/&amp;lt;name&amp;gt;.ts&lt;/code&gt; (types are in &lt;code&gt;@/lib/candor/chat&lt;/code&gt;). The server foundation is &lt;code&gt;lib/candor/candor-server.ts&lt;/code&gt; and &lt;code&gt;components/candor/candor-sign-in.tsx&lt;/code&gt;. Blocks, templates, the theme's stylesheets and the sounds keep the places they had. The aliases come from your &lt;code&gt;components.json&lt;/code&gt;, so a project with its own &lt;code&gt;components&lt;/code&gt; or &lt;code&gt;lib&lt;/code&gt; alias gets the same folders under it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Candor's imports name Candor's files.&lt;/strong&gt; The files Candor installs import each other by their installed names (&lt;code&gt;@/components/candor/message&lt;/code&gt;), so a &lt;code&gt;components/message.tsx&lt;/code&gt; of your own no longer captures an import meant for Candor's.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The kit's source moved into new folders&lt;/strong&gt; (&lt;code&gt;lib/&lt;/code&gt; to &lt;code&gt;foundation/&lt;/code&gt;, the small parts in &lt;code&gt;blocks/&lt;/code&gt; to &lt;code&gt;parts/&lt;/code&gt;, &lt;code&gt;locked&lt;/code&gt; into &lt;code&gt;ui/&lt;/code&gt;). Item names, the docs' groups and the registry's categories are the same as in 2.x; what changes for you is only where the files install, above.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Locale: the app's nouns&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Nouns are message arguments.&lt;/strong&gt; &lt;code&gt;LocaleProvider&lt;/code&gt; takes &lt;code&gt;nouns&lt;/code&gt; (&lt;code&gt;CandorConfig.nouns&lt;/code&gt; in CandorProvider), and every message that names one (&lt;code&gt;{environment}&lt;/code&gt;, &lt;code&gt;{account}&lt;/code&gt;, &lt;code&gt;{product}&lt;/code&gt;) is filled with the app's word, in the form the message's &lt;code&gt;count&lt;/code&gt; picks; &lt;code&gt;{Environment}&lt;/code&gt; starts a sentence with the &lt;code&gt;environment&lt;/code&gt; value a component passes, or else with the app's noun. Nested providers merge noun by noun.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A noun can have plural forms&lt;/strong&gt; (&lt;code&gt;{ one: &amp;quot;workspace&amp;quot;, other: &amp;quot;workspaces&amp;quot; }&lt;/code&gt;); when &lt;code&gt;environment&lt;/code&gt; has them and &lt;code&gt;environments&lt;/code&gt; isn't set, &lt;code&gt;environments&lt;/code&gt; defaults to its &lt;code&gt;other&lt;/code&gt; form, and an &lt;code&gt;environments&lt;/code&gt; you set still wins. A noun can also have a &lt;code&gt;gender&lt;/code&gt; that a select message chooses its case by (&lt;code&gt;{ select: &amp;quot;environment&amp;quot;, cases: { feminine: &amp;quot;…&amp;quot;, other: &amp;quot;…&amp;quot; } }&lt;/code&gt;), and a &lt;code&gt;start&lt;/code&gt; form for languages where upper-casing the first letter isn't how a sentence starts.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;useNouns()&lt;/code&gt;&lt;/strong&gt; gives each noun's singular form for your own code, and &lt;strong&gt;&lt;code&gt;startOf(text, locale?)&lt;/code&gt;&lt;/strong&gt; upper-cases the first letter as the locale writes it. Both come from &lt;code&gt;locale&lt;/code&gt;; &lt;code&gt;fill-strings&lt;/code&gt; (free, and safe on the server) has the types, &lt;code&gt;nounDefaults&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;pick&lt;/code&gt; and &lt;code&gt;englishStrings(table, { nouns })&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;An override that writes a noun's placeholder no longer needs it passed:&lt;/strong&gt; &lt;code&gt;{ environmentBand: { environmentsIn: &amp;quot;{Environments} in {account}&amp;quot; } }&lt;/code&gt;. New keys, if you translate these components: &lt;code&gt;environmentConnect.formLabel&lt;/code&gt;, &lt;code&gt;runLog.environment&lt;/code&gt;, &lt;code&gt;accessRequest.environmentLabel&lt;/code&gt; and &lt;code&gt;auditLog.system&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 1.0.0&lt;/h3&gt;&lt;p&gt;1.0 because its commands and lockfile have been stable since 0.12; it works with any kit release from 1.0 on. &lt;code&gt;update --to 3.0.0&lt;/code&gt; and &lt;code&gt;migrate 3.0.0&lt;/code&gt; need it. Use &lt;code&gt;npx candor-ui@1&lt;/code&gt; to stay on it.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update&lt;/code&gt; makes a release's moves itself:&lt;/strong&gt; where a release installs an item's files somewhere else, it moves them (copying ui primitives), points the imports in your project at the new places, records the moves in &lt;code&gt;candor-lock.json&lt;/code&gt;, and then updates. &lt;code&gt;--dry-run&lt;/code&gt; lists the moves with the merges; &lt;code&gt;--no-move&lt;/code&gt; stops and names them, as 0.15 did.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate &amp;lt;version&amp;gt;&lt;/code&gt;&lt;/strong&gt;, new, runs that release's codemods for the items your project has, in order.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate terms&lt;/code&gt;&lt;/strong&gt; rewrites to LocaleProvider's &lt;code&gt;nouns&lt;/code&gt;, where 0.15's listed the uses; &lt;strong&gt;&lt;code&gt;strings-keys&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;refusal&lt;/code&gt;&lt;/strong&gt; are new codemods; &lt;strong&gt;&lt;code&gt;migrate paths&lt;/code&gt;&lt;/strong&gt; takes its destinations from the release's own install targets.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;On a 3.x project&lt;/strong&gt;, &lt;code&gt;lint&lt;/code&gt; and &lt;code&gt;audit&lt;/code&gt; make a removed name an error naming its codemod (what a codemod lists rather than rewrites, &lt;code&gt;--cd-motion-shake&lt;/code&gt;, stays a warning), and drop the &lt;code&gt;v3-paths&lt;/code&gt; and &lt;code&gt;v3-attention-*&lt;/code&gt; notes. &lt;code&gt;theme check&lt;/code&gt; against a 3.0 kit makes &lt;code&gt;--cd-pop-from&lt;/code&gt; and &lt;code&gt;--cd-motion-shake&lt;/code&gt; errors.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; at 3.0 on a 2.x project&lt;/strong&gt; stops and names &lt;code&gt;update --to 3.0.0&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A plain &lt;code&gt;update&lt;/code&gt; stays within the major you're on:&lt;/strong&gt; without &lt;code&gt;--to&lt;/code&gt;, it moves your items to the newest release in the major &lt;code&gt;candor-lock.json&lt;/code&gt; records, the way &lt;code&gt;add&lt;/code&gt; stays at the locked version, and when a newer major is out it prints one line naming it and the &lt;code&gt;npx candor-ui@1 update --to &amp;lt;version&amp;gt; --dry-run&lt;/code&gt; that shows its breaking changes. To cross, pass &lt;code&gt;--to 3.0.0&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; and &lt;code&gt;doctor&lt;/code&gt; on Base UI and React Aria&lt;/strong&gt; say that from 3.0 Candor's primitives install in &lt;code&gt;components/candor/ui/&lt;/code&gt;, beside your own in &lt;code&gt;components/ui/&lt;/code&gt;, and no longer name your files as replaced; on React Aria this is a note, not a fix. A project on 2.x keeps the 2.x warning.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;doctor&lt;/code&gt; beside &lt;code&gt;@candor-ui/react&lt;/code&gt;&lt;/strong&gt; gives each import's move at 3.0's paths (&lt;code&gt;@/components/candor/thread&lt;/code&gt;), names &lt;code&gt;LocaleProvider&lt;/code&gt;'s &lt;code&gt;nouns&lt;/code&gt; from &lt;code&gt;@/components/candor/locale&lt;/code&gt; in place of &lt;code&gt;TermsProvider&lt;/code&gt;, and counts a copied &lt;code&gt;components/candor/locale.tsx&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;lint&lt;/code&gt; and &lt;code&gt;audit&lt;/code&gt; link their 3.0 rules to the Upgrading to 3.0 page.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Upgrading to 3.0&lt;/strong&gt;, new at &lt;code&gt;/upgrading-to-3&lt;/code&gt; (and &lt;code&gt;/upgrading-to-3.md&lt;/code&gt;): the commands, then every entry of the 3.0 list with what breaks, where it shows, what to do and its codemod, built from the same list &lt;code&gt;update&lt;/code&gt; prints.&lt;/li&gt;&lt;li&gt;The Locale page shows the app's nouns, with plural forms and a gendered select; the Terms page is gone, and &lt;code&gt;/docs/terms&lt;/code&gt; redirects to Locale. CandorProvider's example sets &lt;code&gt;config.nouns&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The Design page's motion section says what 3.0 removed and links to the upgrade page.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 3.0.1&lt;/h3&gt;&lt;p&gt;This release's package is 3.0.1, not 3.0.0: 3.0.0 was published by mistake before the release and withdrawn, and npm doesn't reuse a version.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The free items' removals above are in this version: &lt;code&gt;TermsProvider&lt;/code&gt;, &lt;code&gt;useTerms&lt;/code&gt;, &lt;code&gt;capitalise&lt;/code&gt; and &lt;code&gt;Terms&lt;/code&gt; (use &lt;code&gt;LocaleProvider&lt;/code&gt;'s &lt;code&gt;nouns&lt;/code&gt;, &lt;code&gt;useNouns&lt;/code&gt; and &lt;code&gt;startOf&lt;/code&gt;), the &lt;code&gt;orgData&lt;/code&gt; node, card-registry's &lt;code&gt;Card&lt;/code&gt; and &lt;code&gt;message.thinking&lt;/code&gt;. In a project that uses the package, &lt;code&gt;npx candor-ui@1 migrate 3.0.0&lt;/code&gt; runs every 3.0 codemod (there is no &lt;code&gt;candor-lock.json&lt;/code&gt; to choose from), and &lt;code&gt;terms&lt;/code&gt; and &lt;code&gt;card&lt;/code&gt; rewrite imports from &lt;code&gt;@candor-ui/react&lt;/code&gt; as they do from Candor's installed files.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For contributors&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The source folders are &lt;code&gt;src/registry/foundation/&lt;/code&gt; (was &lt;code&gt;lib/&lt;/code&gt;) and &lt;code&gt;src/registry/parts/&lt;/code&gt; (was &lt;code&gt;blocks/&lt;/code&gt;), with &lt;code&gt;locked&lt;/code&gt; in &lt;code&gt;ui/&lt;/code&gt;; &lt;code&gt;internal/release-3.0/arch4-moves.mjs&lt;/code&gt; is the record of the moves.&lt;/li&gt;&lt;li&gt;OrgSmith's pack is &lt;code&gt;packages/orgsmith&lt;/code&gt;, a private package that installs &lt;code&gt;@candor&lt;/code&gt; as a buyer does; the build makes one registry.&lt;/li&gt;&lt;li&gt;&lt;code&gt;node scripts/upgrade-check.mjs --from 2.10.0&lt;/code&gt; upgrades a 2.10 fixture project with &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;migrate&lt;/code&gt; and builds it, in the normal flow, the 0.15 flow and on Base UI; &lt;code&gt;release:check&lt;/code&gt; runs it.&lt;/li&gt;&lt;li&gt;A test fails when a &lt;code&gt;scripts/breaking.json&lt;/code&gt; 3.0 entry isn't named in this section.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.10.0</title>
      <link>https://candor.themethodic.com/changelog#2-10-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-10-0</guid>
      <pubDate>Tue, 10 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The road to 3.0, and work an agent proposes that a person edits, promotes or passes on. 2.10 is the last 2.x minor and breaks nothing: each item's registry entry now lists what 3.0 changes in it, &lt;code&gt;npx candor-ui update --to 3.0.0&lt;/code&gt; prints those changes for the items your project has, &lt;code&gt;npx candor-ui migrate&lt;/code&gt; makes the ones a codemod can, and &lt;code&gt;lint&lt;/code&gt;, &lt;code&gt;audit&lt;/code&gt; and development warnings point at the code they touch. Ten items are new: a workflow editor for an automation an agent proposes, a connect flow for an outside service, an environment promotion, an escalation outside the app, an assignee picker, a per-document progress queue, keyboard review for any list, a search trace, a proposal with the alternatives the agent weighed, and &lt;code&gt;fill-strings&lt;/code&gt;, moved out of &lt;code&gt;locale&lt;/code&gt; so server code can fill strings. All are Pro except &lt;code&gt;fill-strings&lt;/code&gt;, which is free, so the kit grows from 315 to 325 items: 72 free and 294 in Pro. The sidebar can collapse to an icon rail, the Premium blocks and templates take more of their words from LocaleProvider, and the theme builder gains colour-vision views, a compare view and brand scopes. With CLI 0.15.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.10.0. Nothing is removed and no prop is renamed. A few behaviours change for code you already have; each is in &amp;quot;What to do&amp;quot; below and again in its section.&lt;/p&gt;&lt;h3&gt;What to do&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Everyone, before 3.0:&lt;/strong&gt; run &lt;code&gt;npx candor-ui update --to 3.0.0&lt;/code&gt;. It prints what 3.0 changes for the items in your &lt;code&gt;candor-lock.json&lt;/code&gt;, where each change shows and its migration, and changes nothing. &lt;code&gt;useAttention&lt;/code&gt;'s sound default is on that list, and no compiler catches it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Everyone updating, &lt;code&gt;fill-strings&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;locale&lt;/code&gt;, which every project has, and every Premium block and template now import the new free item &lt;code&gt;fill-strings&lt;/code&gt; (&lt;code&gt;lib/fill-strings.ts&lt;/code&gt;). &lt;code&gt;npx candor-ui update&lt;/code&gt; (CLI 0.15) installs it with them and records it in &lt;code&gt;candor-lock.json&lt;/code&gt;. With &lt;code&gt;--no-deps&lt;/code&gt; it only names it: run &lt;code&gt;npx candor-ui add fill-strings&lt;/code&gt;, since the project doesn't compile without it. If installing it would move an item you didn't name (the shared tokens), &lt;code&gt;update&lt;/code&gt; stops before writing anything and says which items to update together.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tests that fail on console output:&lt;/strong&gt; in development, Candor now logs a warning once per page for code 3.0 changes: &lt;code&gt;useAttention&lt;/code&gt; given a &lt;code&gt;sound&lt;/code&gt; that is on (&lt;code&gt;enabled: true&lt;/code&gt;) without &lt;code&gt;when&lt;/code&gt;, a message with an &lt;code&gt;orgData&lt;/code&gt; inline node, and &lt;code&gt;MetadataDiff&lt;/code&gt;. Nothing is logged in production. Pass &lt;code&gt;when: &amp;quot;always&amp;quot;&lt;/code&gt; to keep 2.x's behaviour (or &lt;code&gt;&amp;quot;away&amp;quot;&lt;/code&gt;, 3.0's default), change &lt;code&gt;kind: &amp;quot;orgData&amp;quot;&lt;/code&gt; to &lt;code&gt;kind: &amp;quot;measured&amp;quot;&lt;/code&gt; (&lt;code&gt;npx candor-ui migrate orgdata&lt;/code&gt;), and use &lt;code&gt;ChangeDiff&lt;/code&gt; from the same file in place of &lt;code&gt;MetadataDiff&lt;/code&gt;, by hand on 2.x (as you move to 3.0, &lt;code&gt;npx candor-ui migrate metadata-diff --for 3.0.0&lt;/code&gt; does it and moves the file). &lt;code&gt;MetadataDiff&lt;/code&gt; is now a small component around &lt;code&gt;ChangeDiff&lt;/code&gt;, so &lt;code&gt;MetadataDiff === ChangeDiff&lt;/code&gt; is false.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Your own string overrides, ahead of 3.0:&lt;/strong&gt; 3.0 reads only &lt;code&gt;message.working&lt;/code&gt; (2.9's new key for Message's working line) and only &lt;code&gt;answeringApprovals&lt;/code&gt; for &lt;code&gt;useAnsweringApprovals&lt;/code&gt;' words. Move an override of &lt;code&gt;message.thinking&lt;/code&gt;, or one under &lt;code&gt;useAnsweringApprovals&lt;/code&gt;, to the new key now; 2.9 and later already read it first. &lt;code&gt;candor-ui lint&lt;/code&gt; points at both.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium blocks and templates, the 2.7 shims:&lt;/strong&gt; 3.0 removes &lt;code&gt;viewerOf&lt;/code&gt;, &lt;code&gt;contextOf&lt;/code&gt;, the approvals inbox's &lt;code&gt;post&lt;/code&gt;, the stores' &lt;code&gt;Refusal&lt;/code&gt; re-exports and &lt;code&gt;db/connect.ts&lt;/code&gt;. &lt;code&gt;candor-ui lint&lt;/code&gt; names each use in your own code and what to use instead.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DataTable&lt;/code&gt;'s column picker:&lt;/strong&gt; the last visible column's box is &lt;code&gt;Locked&lt;/code&gt; with its reason (&amp;quot;At least one column stays shown.&amp;quot;) instead of &lt;code&gt;disabled&lt;/code&gt;, so it carries &lt;code&gt;aria-disabled&lt;/code&gt;. A test that expects it &lt;code&gt;toBeDisabled()&lt;/code&gt; should check &lt;code&gt;aria-disabled&lt;/code&gt; instead. If you translate DataTable, add the new &lt;code&gt;lastColumn&lt;/code&gt; string.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;EnvironmentConnect&lt;/code&gt;, &lt;code&gt;McpConnect&lt;/code&gt; and &lt;code&gt;ConsentCeremony&lt;/code&gt; while busy:&lt;/strong&gt; Test connection, Connect and the grant button are &lt;code&gt;Locked&lt;/code&gt; with a reason instead of &lt;code&gt;disabled&lt;/code&gt; while a test runs or the connection or consent is being saved, so they carry &lt;code&gt;aria-disabled&lt;/code&gt; and stay in the tab order. A test that expects them &lt;code&gt;toBeDisabled()&lt;/code&gt; while busy should check &lt;code&gt;aria-disabled&lt;/code&gt; instead. If you translate them, add the new strings &lt;code&gt;waitTest&lt;/code&gt; and &lt;code&gt;waitSave&lt;/code&gt; (&lt;code&gt;environmentConnect&lt;/code&gt;), &lt;code&gt;waitConnect&lt;/code&gt; (&lt;code&gt;mcpConnect&lt;/code&gt;) and &lt;code&gt;waitRecord&lt;/code&gt; (&lt;code&gt;consentCeremony&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AgentScreen&lt;/code&gt;:&lt;/strong&gt; both views now keep the frame in a new &lt;code&gt;agent-screen-body&lt;/code&gt; element (&lt;code&gt;display: contents&lt;/code&gt; when collapsed). If your CSS or tests reach the collapsed view's frame as a direct child of the section, go through &lt;code&gt;[data-slot=&amp;quot;agent-screen-body&amp;quot;]&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Base UI projects, &lt;code&gt;Locked&lt;/code&gt;, &lt;code&gt;AppSidebar&lt;/code&gt;, &lt;code&gt;ToolPermissions&lt;/code&gt; and &lt;code&gt;RestoreDialog&lt;/code&gt;:&lt;/strong&gt; in a shadcn project on Base UI, every control &lt;code&gt;Locked&lt;/code&gt; with a reason drew a button inside a button, an extra tab stop and a hydration error. Released versions have this, 2.8.0 included, and &lt;code&gt;Locked&lt;/code&gt; is free. shadcn's rewrite of &lt;code&gt;asChild&lt;/code&gt; to &lt;code&gt;render&lt;/code&gt; drops &lt;code&gt;asChild&lt;/code&gt; when its child is a variable, so the tooltip's own button went round the control. AppSidebar's collapsed rail and person menu, ToolPermissions' locked modes and RestoreDialog's trigger had the same problem. Run &lt;code&gt;npx candor-ui update locked app-sidebar tool-permissions restore-dialog&lt;/code&gt;. Radix projects and &lt;code&gt;@candor-ui/react&lt;/code&gt; are not affected.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Theme builder, a component's density:&lt;/strong&gt; files from earlier versions wrote a component's density under &lt;code&gt;:root:not([data-density])&lt;/code&gt;, so &lt;code&gt;data-density&lt;/code&gt; on the component, or on a container around it, didn't win over it. Those files open as before; download your theme again to get the new selector.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt; without a reason:&lt;/strong&gt; its &lt;code&gt;className&lt;/code&gt; now goes on the control; before, it was dropped. If you pass &lt;code&gt;className&lt;/code&gt; to a &lt;code&gt;Locked&lt;/code&gt; whose &lt;code&gt;reason&lt;/code&gt; can be empty, check the control's layout.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AppSidebar&lt;/code&gt;:&lt;/strong&gt; a count and the usage percentage are formatted in LocaleProvider's locale, and a counted item's tooltip comes from the new &lt;code&gt;labelCount&lt;/code&gt; string. If you translate AppSidebar, add &lt;code&gt;labelCount&lt;/code&gt;, and &lt;code&gt;collapse&lt;/code&gt; and &lt;code&gt;expand&lt;/code&gt; if you use the new rail.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium, the agent ops console with a router:&lt;/strong&gt; if you followed 2.9's advice and changed the console to read your router's address, &lt;code&gt;update&lt;/code&gt;'s merge conflicts on those lines. Keep 2.10's, which read the address through &lt;code&gt;useAddress()&lt;/code&gt;, and call the new &lt;code&gt;setAddress()&lt;/code&gt; beside &lt;code&gt;setNavigate()&lt;/code&gt; with the router's path and query (in Next.js, from &lt;code&gt;usePathname()&lt;/code&gt; and &lt;code&gt;useSearchParams()&lt;/code&gt; in an effect).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium, words you edited in blocks' and templates' files:&lt;/strong&gt; much of their typed text now comes from a string table per block. If you changed that text in the files, keep the new lines and give your words to LocaleProvider's &lt;code&gt;strings&lt;/code&gt; under the block's name. Some English is still typed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium, the project workspace's downloads:&lt;/strong&gt; a file is fetched before it is saved. If you serve the files another way than the template's &lt;code&gt;api/file&lt;/code&gt;, answer with &lt;code&gt;content-type: text/markdown&lt;/code&gt;; anything else is shown as a failure and nothing is saved.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The Vite and TanStack Start starters:&lt;/strong&gt; their &lt;code&gt;collapsible.tsx&lt;/code&gt; used &lt;code&gt;animate-collapse-*&lt;/code&gt;, which 3.0 removes. If you started from either, replace your copy with the starter's, which uses the reveal motion family.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CLI, &lt;code&gt;lint --strict&lt;/code&gt; in CI:&lt;/strong&gt; CLI 0.15's 3.0 warnings don't fail &lt;code&gt;--strict&lt;/code&gt;, so CI on an unchanged project stays green. They are printed and counted separately (&lt;code&gt;breaking&lt;/code&gt; in &lt;code&gt;--json&lt;/code&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;New (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;workflow-editor&lt;/code&gt;&lt;/strong&gt;, an automation an agent proposes and a person edits before it runs: a trigger (an event in your app, a schedule in &lt;code&gt;schedule-editor&lt;/code&gt;'s shape, or a person starting it) and steps and If/Else conditions built from the fields your app lists. Then and Else rejoin at the next node. The proposal is labelled as the agent's, and everything the person changes is marked against it. Problems your app finds show on the node they're about and lock Save, saying why. Nothing is saved until Save, which calls back with the definition and its change hash for your server to check; while a save is pending, edits make no change and the editor says the workflow is being saved. An edit is announced once, by the status line. Keyboard throughout, with the hint's joins as strings (&lt;code&gt;hintEither&lt;/code&gt;, &lt;code&gt;hintCombo&lt;/code&gt;, &lt;code&gt;hintSeparator&lt;/code&gt;, &lt;code&gt;hintItem&lt;/code&gt;), a list view for screen readers, and a graph view laid out by &lt;code&gt;graph-layout&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;integration-connect&lt;/code&gt;&lt;/strong&gt; connects an outside service through the provider's sign-in or an API key, with the access it asks for in plain words (needed access listed as needed; optional access starts unticked). It runs a connection test and shows what the test found, or that it couldn't run and why, and says what the integration can and can't reach, or that it hasn't been described. An API key is used to test and to connect, then cleared from the field. Disconnect asks first, saying what stops and what stays.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;environment-promotion&lt;/code&gt;&lt;/strong&gt; promotes a configuration from one environment to another with the diff, who asked, who approved and when, which approvals are missing, and what can and can't be rolled back. Nothing is promoted without a decision: Promote stays locked, saying why, while approvals are missing, the target has changed since the diff, or nothing differs, and for production until the person ticks that they've read the change. The tick is for the change it was given on: when the diff or &lt;code&gt;hash&lt;/code&gt; changes, or the target goes stale, it is cleared and the card says why. Approvals are counted by person: each &lt;code&gt;by&lt;/code&gt; once, and never the requester's own (&lt;code&gt;requestedBy.name&lt;/code&gt;); entries that don't count stay in the list, marked with why, so use the same name for a person in &lt;code&gt;by&lt;/code&gt; and &lt;code&gt;requestedBy&lt;/code&gt;. Pass your server's change hash as &lt;code&gt;hash&lt;/code&gt;; it comes back to &lt;code&gt;onPromote&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;escalation&lt;/code&gt;&lt;/strong&gt; hands a case off outside the app by a page, an email or a ticket. Before sending it shows who each way reaches now and exactly what will be sent (recipients, subject, message, attachments, and what isn't sent). A message an agent drafted says so and can be edited, and no way is chosen for the person. A new &lt;code&gt;message&lt;/code&gt; from the agent replaces the subject and message if the person hasn't edited them; if they have, their text stays and the card says the message was redrafted, with &amp;quot;Use the new draft&amp;quot;. Once your server records the send, pass it as &lt;code&gt;sent&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;assignee-picker&lt;/code&gt;&lt;/strong&gt; chooses a person or an agent for a task. Each shows the load and availability your app passes, and what you don't pass reads as not known. Nothing is sorted, suggested or pre-chosen.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;document-progress-queue&lt;/code&gt;&lt;/strong&gt; shows per-document progress for a batch: queued, working with its stage, done, or failed with the reason and Retry. The summary counts states and documents finished and never shows time left or a percentage; pass &lt;code&gt;adding&lt;/code&gt; while documents are still arriving. Screen readers hear failures and the batch finishing, not every document's step.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;use-keyboard-review&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;useKeyboardReview&lt;/code&gt; gives any list of rows a person keeps or drops keyboard review: J/K or the arrows move, Y keeps, N drops, U undoes and returns to the row. The keys are strings under &lt;code&gt;keyboardReview&lt;/code&gt;, so a translation can match its words, and each row lists them in &lt;code&gt;aria-keyshortcuts&lt;/code&gt;. A decision made on a row that has since changed is cleared. Spread &lt;code&gt;rowProps(i)&lt;/code&gt; on each row and put &lt;code&gt;listRef&lt;/code&gt; on the list; row versions are worked out once per &lt;code&gt;items&lt;/code&gt; and &lt;code&gt;versionOf&lt;/code&gt;, so pass a &lt;code&gt;versionOf&lt;/code&gt; that keeps its identity.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;search-trace&lt;/code&gt;&lt;/strong&gt; shows a search an agent ran as a tool-call row (title, status, duration, a count of searches and sources read). Opened, it lists each query as the agent ran it, with each source's title and domain under it, as text and never a link; the domain is read with the URL parser, so a host hidden in a user name shows the real host. A line says how many more sources the agent read only when the tool says so. Pass the &lt;code&gt;ToolCall&lt;/code&gt; with &lt;code&gt;queries&lt;/code&gt; beside it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;proposal&lt;/code&gt;&lt;/strong&gt; shows one action an agent proposes with the alternatives it weighed beside it, each with its confidence through &lt;code&gt;ConfidenceMark&lt;/code&gt; (&amp;quot;unknown&amp;quot; when the agent didn't say) and its reason introduced as &amp;quot;Its reasoning, not checked:&amp;quot; (&lt;code&gt;proposal.reasonLabel&lt;/code&gt;). Nothing is chosen for the person: Accept and Edit are locked, saying why, until they pick, and Accept calls back with that option. Edit appears with &lt;code&gt;onEdit&lt;/code&gt;, &amp;quot;None of these&amp;quot; with &lt;code&gt;onDecline&lt;/code&gt;. With &lt;code&gt;locked&lt;/code&gt;, &amp;quot;None of these&amp;quot; is locked with the same reason as Accept and Edit.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Integration connect, environment promotion and escalation wait for your app: after your handler resolves, Connect, Disconnect, Promote and Send stay locked, saying they are waiting for your app, until you pass &lt;code&gt;sent&lt;/code&gt;, a new &lt;code&gt;state&lt;/code&gt; or an &lt;code&gt;error&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Changed (free unless marked):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;fill-strings&lt;/code&gt;&lt;/strong&gt; (new, free): &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;pick&lt;/code&gt; and &lt;code&gt;englishStrings(table)&lt;/code&gt; in a module without &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt;, so server code can fill a component's strings. &lt;code&gt;locale&lt;/code&gt; imports it and still exports &lt;code&gt;fill&lt;/code&gt; and &lt;code&gt;pick&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Locked&lt;/code&gt;:&lt;/strong&gt; without a reason, &lt;code&gt;className&lt;/code&gt; goes on the control instead of being dropped. In a Base UI project, a locked control is one button again, not a button inside the tooltip's button; AppSidebar's collapsed rail and person menu, ToolPermissions' locked modes and RestoreDialog's trigger (Pro) are fixed the same way.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AppSidebar&lt;/code&gt;&lt;/strong&gt; (Pro): the optional &lt;code&gt;rail&lt;/code&gt; prop lets a person collapse the sidebar to its icons on a wide screen; each label becomes a tooltip, and accessible names, the current page, counts and tab order don't change. Keep the choice by storing what &lt;code&gt;onCollapsedChange&lt;/code&gt; gives you and passing it back as &lt;code&gt;defaultCollapsed&lt;/code&gt;. In a sheet it always shows its labels. Without &lt;code&gt;rail&lt;/code&gt;, nothing changes. Counts and the usage percentage are formatted in the locale.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AppLayout&lt;/code&gt;&lt;/strong&gt; (Pro): the sidebar's column follows the rail's width.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ChangeSetReview&lt;/code&gt;&lt;/strong&gt; (Pro) runs on &lt;code&gt;useKeyboardReview&lt;/code&gt;; its keys, focus and decisions behave as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DataTable&lt;/code&gt;&lt;/strong&gt; (Pro): the column picker's last visible column is &lt;code&gt;Locked&lt;/code&gt; with the reason (new string &lt;code&gt;lastColumn&lt;/code&gt;) instead of disabled.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;EnvironmentConnect&lt;/code&gt;, &lt;code&gt;McpConnect&lt;/code&gt; and &lt;code&gt;ConsentCeremony&lt;/code&gt;&lt;/strong&gt; (Pro): while a test runs, or the connection or consent is being saved, Test connection, Connect and the grant button are &lt;code&gt;Locked&lt;/code&gt;, saying why (&amp;quot;Wait for the test to finish.&amp;quot;, &amp;quot;Wait for the connection to be saved.&amp;quot;, &amp;quot;Wait for the connection to finish.&amp;quot;, &amp;quot;Wait while your consent is recorded.&amp;quot;), instead of disabled. A press while busy does nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AgentScreen&lt;/code&gt;&lt;/strong&gt; (Pro): changing between collapsed and expanded keeps the frame's element, so a video no longer restarts and a MediaStream isn't reattached (new &lt;code&gt;agent-screen-body&lt;/code&gt; slot).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;StopAll&lt;/code&gt; and &lt;code&gt;RunScrubber&lt;/code&gt;&lt;/strong&gt; (Pro): Play, and RunScrubber's Replay, are no longer mirrored in right-to-left.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Development warnings&lt;/strong&gt;, once per page and never in production, for what 3.0 changes: &lt;code&gt;useAttention&lt;/code&gt; (Pro) given a &lt;code&gt;sound&lt;/code&gt; that is on (&lt;code&gt;enabled: true&lt;/code&gt;) without &lt;code&gt;when&lt;/code&gt;, as the CLI's lint rule does (3.0 plays sounds only while the person is away unless you pass &lt;code&gt;when: &amp;quot;always&amp;quot;&lt;/code&gt;), a message with an &lt;code&gt;orgData&lt;/code&gt; node (use &lt;code&gt;measured&lt;/code&gt;), and &lt;code&gt;MetadataDiff&lt;/code&gt; (Pro; use &lt;code&gt;ChangeDiff&lt;/code&gt;). The deprecation notes on &lt;code&gt;orgData&lt;/code&gt; and &lt;code&gt;MetadataDiff&lt;/code&gt; said 2.0; they say 3.0.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Strings:&lt;/strong&gt; AppSidebar's, WorkflowEditor's, DocumentProgressQueue's, SearchTrace's and IntegrationConnect's separators and colons are strings a translation can change.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PermissionMode&lt;/code&gt;, &lt;code&gt;Diagram&lt;/code&gt; and &lt;code&gt;Dictation&lt;/code&gt;&lt;/strong&gt; (Pro) are now optimised by the React Compiler.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks and templates (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;fill-strings&lt;/code&gt;:&lt;/strong&gt; every block and template now imports &lt;code&gt;fill-strings&lt;/code&gt;. &lt;code&gt;npx candor-ui update&lt;/code&gt; installs it with them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Words through LocaleProvider:&lt;/strong&gt; more of the typed English comes from a string table per block: prompts, deny reasons, placeholders, tool titles, the support copilot's customer page, the approvals inbox's Rules page and the ops console's top line. New tables &lt;code&gt;agentAdmin&lt;/code&gt;, &lt;code&gt;approvalGatedChange&lt;/code&gt;, &lt;code&gt;approveFromAnywhere&lt;/code&gt;, &lt;code&gt;auditDataControls&lt;/code&gt;, &lt;code&gt;costGuard&lt;/code&gt;, &lt;code&gt;evalDashboard&lt;/code&gt;, &lt;code&gt;evalReviewLoop&lt;/code&gt;, &lt;code&gt;humanHandoff&lt;/code&gt;, &lt;code&gt;knowledgeBase&lt;/code&gt; and &lt;code&gt;planBuildReview&lt;/code&gt;; &lt;code&gt;runConsole&lt;/code&gt;, &lt;code&gt;agentOpsConsole&lt;/code&gt;, &lt;code&gt;approvalsInbox&lt;/code&gt;, &lt;code&gt;projectWorkspace&lt;/code&gt; and &lt;code&gt;supportCopilot&lt;/code&gt; gain keys. Some English is still typed. &lt;code&gt;approvalsInboxStrings&lt;/code&gt; lives in the approvals inbox's &lt;code&gt;agents.ts&lt;/code&gt; and is still exported from &lt;code&gt;shell.tsx&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Tool titles&lt;/strong&gt; take the block's translator as an optional third argument (English without it). Cost guard's also takes the locale's number format as a fourth, and its budget is written in the locale, reading &amp;quot;$5&amp;quot; for a whole amount.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Agent ops console:&lt;/strong&gt; with a router given to &lt;code&gt;setNavigate()&lt;/code&gt;, call the new &lt;code&gt;setAddress()&lt;/code&gt; with the router's path and query, and the sidebar's current page, the sign-in check, &lt;code&gt;?run=&lt;/code&gt; and &lt;code&gt;?prompt=&lt;/code&gt; follow each move without a page load. When the section unmounts it forgets the router's address, so after a move out of the section and back it reads the browser's until your router reports again.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Project workspace:&lt;/strong&gt; a file download is fetched first. Signed out (a 401, or a redirect to your sign-in) goes to sign-in; a refusal or a lost connection is shown in one sentence under the top bar, and nothing is saved.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Starters&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Vite and TanStack Start starters' Collapsible uses the reveal motion family instead of &lt;code&gt;animate-collapse-*&lt;/code&gt;, which 3.0 removes.&lt;/li&gt;&lt;li&gt;The starters carry Candor 2.10.0's components, without the search tags.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.15.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --to&lt;/code&gt;&lt;/strong&gt; prints the breaking changes between each installed item's version and the version you update to: what breaks, where it shows, the migration, and the &lt;code&gt;migrate&lt;/code&gt; codemod if there is one, each in the words of the release you update to, so a corrected entry reaches a project on an older 2.x. &lt;code&gt;npx candor-ui update --to 3.0.0&lt;/code&gt; shows what 3.0 asks of your project and changes nothing; run it before 3.0 is released.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate &amp;lt;codemod&amp;gt;&lt;/code&gt;&lt;/strong&gt;, new, with &lt;code&gt;orgdata&lt;/code&gt;, &lt;code&gt;metadata-diff&lt;/code&gt;, &lt;code&gt;motion-aliases&lt;/code&gt;, &lt;code&gt;card&lt;/code&gt;, &lt;code&gt;terms&lt;/code&gt; and &lt;code&gt;paths&lt;/code&gt;. Each prints what it changed and lists what it couldn't, with &lt;code&gt;--dry-run&lt;/code&gt; to look first. It reads your source with your project's own TypeScript 5. Your installed Candor files are left to &lt;code&gt;update&lt;/code&gt;; without &lt;code&gt;candor-lock.json&lt;/code&gt;, files named like Candor's in the folders Candor installs to (such as &lt;code&gt;lib/chat.ts&lt;/code&gt;) are left alone and named, and if the registry's public lists can't be read, nothing is changed. &lt;code&gt;terms&lt;/code&gt; lists the uses and changes nothing, since 3.0's form isn't designed yet. &lt;code&gt;card&lt;/code&gt; and &lt;code&gt;metadata-diff&lt;/code&gt; leave shadcn's &lt;code&gt;Card&lt;/code&gt;, or another module's export of the same name, alone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;migrate paths&lt;/code&gt; and &lt;code&gt;migrate metadata-diff&lt;/code&gt; move files&lt;/strong&gt; (into &lt;code&gt;components/candor/&lt;/code&gt; and &lt;code&gt;lib/candor/&lt;/code&gt;, and &lt;code&gt;metadata-diff.tsx&lt;/code&gt; to &lt;code&gt;change-diff.tsx&lt;/code&gt;), rewrite the imports that name them, and record the moves in &lt;code&gt;candor-lock.json&lt;/code&gt;, so &lt;code&gt;update&lt;/code&gt; follows them. Both run only as part of the move to 3.0: on a 2.x project they refuse unless you name the release, &lt;code&gt;npx candor-ui migrate metadata-diff --for 3.0.0&lt;/code&gt; and &lt;code&gt;npx candor-ui migrate paths --for 3.0.0&lt;/code&gt;, followed by &lt;code&gt;npx candor-ui update --to 3.0.0&lt;/code&gt;, once 3.0 is released. Until then &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; install to the old places and names; on 2.x, import &lt;code&gt;ChangeDiff&lt;/code&gt; by hand. &lt;code&gt;paths&lt;/code&gt; copies the ui primitives rather than moving them. In a monorepo, files in a shared package (shadcn's monorepo template) move within that package and every workspace package's imports are followed; names through package.json &lt;code&gt;#&lt;/code&gt; imports are followed too. Nothing is removed until its new copy is written, a failed write puts everything back, and a name it can't resolve is listed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;lint&lt;/code&gt; and &lt;code&gt;audit&lt;/code&gt;&lt;/strong&gt; warn about what 3.0 removes in your own source and CSS, and name the codemod for each, including the &lt;code&gt;message.thinking&lt;/code&gt; strings key, strings under &lt;code&gt;useAnsweringApprovals&lt;/code&gt;, and the blocks' and templates' &lt;code&gt;viewerOf&lt;/code&gt;, &lt;code&gt;Refusal&lt;/code&gt; from a store, &lt;code&gt;db/connect.ts&lt;/code&gt;, &lt;code&gt;contextOf&lt;/code&gt; and the approvals inbox's &lt;code&gt;post&lt;/code&gt;, each saying what to use instead. These warnings don't fail &lt;code&gt;lint --strict&lt;/code&gt;; they are counted separately (&lt;code&gt;breaking&lt;/code&gt; in &lt;code&gt;--json&lt;/code&gt;). What 2.x can't take yet (Terms, the new install paths, &lt;code&gt;AttentionKind&lt;/code&gt;'s new kinds) prints as notes, which never fail.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update&lt;/code&gt;&lt;/strong&gt; installs the Candor items a new version needs, as &lt;code&gt;add&lt;/code&gt; would, and records them; &lt;code&gt;--no-deps&lt;/code&gt; only names them, as before, and &lt;code&gt;update&lt;/code&gt; exits 1 when one wasn't installed. If installing them would move an item you didn't name, it stops before writing anything and says what to update together.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update --moved&lt;/code&gt;&lt;/strong&gt; accepts a renamed item's new file name (&lt;code&gt;metadata-diff.tsx&lt;/code&gt; → &lt;code&gt;change-diff.tsx&lt;/code&gt;), and a move recorded in &lt;code&gt;candor-lock.json&lt;/code&gt; is looked at before the path the file was installed at.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Aliases through package.json &lt;code&gt;imports&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;#components&lt;/code&gt;), and a monorepo app whose &lt;code&gt;ui&lt;/code&gt; alias points into a shared package (shadcn's monorepo template): &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;add --dry-run&lt;/code&gt; work out what shadcn writes themselves, instead of running a shadcn preview per item. In such a monorepo, a &lt;code&gt;--path&lt;/code&gt; naming a file still uses shadcn's preview. Checked against real shadcn 4.23.0 installs into shadcn's monorepo template (Radix and Base UI) and three &lt;code&gt;#&lt;/code&gt; projects: the files are the same.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The README&lt;/strong&gt; says what type-checks in shadcn's monorepo template. With the template's own &lt;code&gt;components.json&lt;/code&gt; the installed items don't type-check, which is shadcn's output for Candor's import form. The workaround: before &lt;code&gt;init&lt;/code&gt;, set the app's &lt;code&gt;ui&lt;/code&gt; alias to &lt;code&gt;@/components/ui&lt;/code&gt;, and give the app's tsconfig &lt;code&gt;&amp;quot;lib&amp;quot;: [&amp;quot;es2023&amp;quot;, &amp;quot;DOM&amp;quot;, &amp;quot;DOM.Iterable&amp;quot;]&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;suggest_components&lt;/code&gt;&lt;/strong&gt; leaves out a hook or helper the task doesn't ask for or name when the components in the answer cover what it was found by, or cover more of the task; it no longer lists &lt;code&gt;use-answering-approvals&lt;/code&gt; beside the approval components at the Pro tier, or beside &lt;code&gt;citation&lt;/code&gt; for &amp;quot;citations for an answer&amp;quot;. Ask for it by name, or say &amp;quot;hook&amp;quot;, to have it listed. A block or template that covers the whole task keeps its place in the six-item answer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;At a tier,&lt;/strong&gt; &lt;code&gt;suggest_components&lt;/code&gt; no longer answers with an item found by one incidental word when the rest of the task is what a higher tier's items do, and a no-item answer names the higher tier's items. Where Candor has nothing for the task at any tier (&amp;quot;no rich-text editor&amp;quot;), a higher tier's items are called related, not &amp;quot;Candor has this in Pro&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;search_docs&lt;/code&gt;&lt;/strong&gt; finds items by the words people use for them (&amp;quot;modal&amp;quot;, &amp;quot;login&amp;quot;, &amp;quot;404&amp;quot;, &amp;quot;onboarding&amp;quot;, &amp;quot;signup&amp;quot;), from the same &lt;code&gt;@keywords&lt;/code&gt; tags. A keyword is used only for a word no item says itself, so other searches rank as before. PermissionPrompt's description says what it is for, so searches for approving a tool call find it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The new items have search tags,&lt;/strong&gt; and the evaluation set has a task for each (forty in all).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New pattern:&lt;/strong&gt; &amp;quot;Let an agent propose an automation&amp;quot; (&lt;code&gt;/patterns/agent-proposed-automation&lt;/code&gt;): one rules function used as &lt;code&gt;validate&lt;/code&gt; in the editor and on the server, and a save route that recomputes the hash.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Screens:&lt;/strong&gt; a new Environment promotion screen; Human handoff gains a layout for escalating outside the app; Sign-in and first run names IntegrationConnect; Extraction review's queue adds DocumentProgressQueue, AssigneePicker and useKeyboardReview.&lt;/li&gt;&lt;li&gt;An indented code sample in a doc comment shows as a code block. Examples that play a sound pass &lt;code&gt;when&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Theme builder&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Colour-vision views:&lt;/strong&gt; the View control adds protanopia, deuteranopia, tritanopia and achromatopsia, each labelled as a simulation, its strip saying what it models and what it can't show. The achromatopsia view shows lightness as typical sight judges it; with rods alone, reds look darker and blue-greens lighter.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Compare,&lt;/strong&gt; beside View, puts a second copy of the canvas next to your theme: Candor's default, your theme in another mode, or another brand scope. Side by side on a wide canvas, one above the other on a narrow one; they scroll together.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Brand scopes&lt;/strong&gt; let one &lt;code&gt;candor-brand.css&lt;/code&gt; hold more than one brand. Add one in Start → Brand scopes and choose which you're editing in the bar over the canvas; each is checked on its own. A scope's own choices are colour, type, radius and density; motion, sound and component settings are shared. The file writes each scope under &lt;code&gt;[data-brand=&amp;quot;&amp;lt;name&amp;gt;&amp;quot;]&lt;/code&gt;: put &lt;code&gt;data-brand=&amp;quot;&amp;lt;name&amp;gt;&amp;quot;&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or any element, and text inside it takes the scope's font, size, tracking, text colour and ground (in the base layer, so a class on that element still wins). Menus, popovers, tooltips and dialogs open in a portal at the end of &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, so they take a scope only when &lt;code&gt;data-brand&lt;/code&gt; is on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;; the file, DESIGN.md, the agent brief and the builder say so. &lt;code&gt;data-density&lt;/code&gt; on the scope's element, or on a container around it, wins over the scope's density. A scope wins over lines kept as written from an opened file, with &lt;code&gt;data-brand&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; as on any other element. Every &lt;code&gt;@import&lt;/code&gt; is written before every &lt;code&gt;@font-face&lt;/code&gt;, so a scope's font from a stylesheet loads beside a base font file.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A component's density&lt;/strong&gt; is written as &lt;code&gt;[data-slot=&amp;quot;…&amp;quot;]:not([data-density], [data-density] *)&lt;/code&gt;, so &lt;code&gt;data-density&lt;/code&gt; on the component, or on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or any container around it, wins over it. Files from earlier versions open as before.&lt;/li&gt;&lt;li&gt;Below 672 px the View control has its own row, so its options are no longer cut short.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Tokens and theming&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The token manifest lists the new items' &lt;code&gt;data-slot&lt;/code&gt; names and AgentScreen's &lt;code&gt;agent-screen-body&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The home page's &amp;quot;New in 2.10&amp;quot; link opens this section.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Registry&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The 3.0 list:&lt;/strong&gt; each item's registry entry carries the changes 3.0 makes to it (&lt;code&gt;meta.breaking&lt;/code&gt;): what breaks, where it shows, the migration, and the &lt;code&gt;candor-ui migrate&lt;/code&gt; codemod when there is one. Sixteen changes in all, including the removals Candor's deprecation notes already announced (&lt;code&gt;message.thinking&lt;/code&gt;, the blocks' and templates' 2.7 shims, &lt;code&gt;useAnsweringApprovals&lt;/code&gt;' string key). &lt;code&gt;candor-ui update --to 3.0.0&lt;/code&gt; reads them for the items your project has.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Search tags out of installed files:&lt;/strong&gt; the files Candor installs no longer contain the &lt;code&gt;@keywords&lt;/code&gt; and &lt;code&gt;@job&lt;/code&gt; doc tags, which are search metadata for the docs MCP (it still reads them from the source).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 2.10.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The free items' changes above (&lt;code&gt;fill-strings&lt;/code&gt;, &lt;code&gt;locale&lt;/code&gt; importing it, &lt;code&gt;Locked&lt;/code&gt;'s &lt;code&gt;className&lt;/code&gt;, the &lt;code&gt;orgData&lt;/code&gt; development warning in &lt;code&gt;message-content&lt;/code&gt;, PermissionPrompt's description) are in this version.&lt;/li&gt;&lt;li&gt;The package no longer ships the &lt;code&gt;@keywords&lt;/code&gt; and &lt;code&gt;@job&lt;/code&gt; doc tags.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For contributors&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;npm run release:check&lt;/code&gt; runs the shadcn differential after the CLI build (25 to 40 s) and fails if the repo's shadcn is outside the CLI's pin; &lt;code&gt;--quick&lt;/code&gt; skips it. &lt;code&gt;RELEASING.md&lt;/code&gt; lists it and what &lt;code&gt;--quick&lt;/code&gt; skips.&lt;/li&gt;&lt;li&gt;&lt;code&gt;scripts/breaking.json&lt;/code&gt; is the 3.0 list (its shape is in its &lt;code&gt;$comment&lt;/code&gt;). A test fails when an item's source announces a 3.0 removal with no entry, and the CLI's tests map every entry to a lint rule.&lt;/li&gt;&lt;li&gt;&lt;code&gt;check:compiler&lt;/code&gt;'s allowed list names its files, so a known skip in a new file fails.&lt;/li&gt;&lt;li&gt;&lt;code&gt;doc-facts&lt;/code&gt; fails on a typed item count in the npm READMEs.&lt;/li&gt;&lt;li&gt;&lt;code&gt;npm run agents&lt;/code&gt; writes nothing until every check passes.&lt;/li&gt;&lt;li&gt;A kit test fails if a registry, block or template file gives &lt;code&gt;asChild&lt;/code&gt; anything but a single JSX element, since shadcn's Base UI rewrite drops it otherwise.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.9.0</title>
      <link>https://candor.themethodic.com/changelog#2-9-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-9-0</guid>
      <pubDate>Tue, 10 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Documents, record changes, code and comments an agent produced, each reviewed in parts before anything applies; the agent's screen while it works. Fifteen items are new: a document viewer and an extraction review, a change set review and a reconcile table, a code listing and a small code editor, a comment thread and presence, a view of a computer-use agent's screen, a graph view, a model picker and connected sources for the composer, and two pieces moved out of code the blocks pasted (&lt;code&gt;use-answering-approvals&lt;/code&gt;, &lt;code&gt;format-elapsed&lt;/code&gt;). All are Pro except &lt;code&gt;format-elapsed&lt;/code&gt;, which is free, so the kit grows from 300 to 315 items: 71 free and 284 in Pro. Premium templates load no database code until a route opens it, take your router, and fill their container. The CLI works out Base UI, Tailwind prefix and right-to-left installs itself. With CLI 0.14.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.9.0. Nothing is removed and no prop is renamed. A few behaviours change for code you already have; each is in &amp;quot;What to do&amp;quot; below and again in its section.&lt;/p&gt;&lt;h3&gt;What to do&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Premium templates, data routes:&lt;/strong&gt; changes to a template's data routes now go in &lt;code&gt;handlers.ts&lt;/code&gt;. Twelve routes moved their code, unchanged, into a new &lt;code&gt;handlers.ts&lt;/code&gt; beside &lt;code&gt;route.ts&lt;/code&gt; (approvals inbox: &lt;code&gt;api/requests&lt;/code&gt;, &lt;code&gt;api/history&lt;/code&gt;, &lt;code&gt;api/rules&lt;/code&gt;; agent ops console: &lt;code&gt;api/ops&lt;/code&gt;, &lt;code&gt;api/runs&lt;/code&gt;, &lt;code&gt;api/settings&lt;/code&gt;; support copilot: &lt;code&gt;api/customer&lt;/code&gt;, &lt;code&gt;api/desk&lt;/code&gt;, &lt;code&gt;api/quality&lt;/code&gt;, &lt;code&gt;api/thread&lt;/code&gt;; project workspace: &lt;code&gt;api/workspace&lt;/code&gt;, &lt;code&gt;api/file&lt;/code&gt;). If you changed one of those &lt;code&gt;route.ts&lt;/code&gt; files, &lt;code&gt;update&lt;/code&gt;'s merge will conflict: move your changes into &lt;code&gt;handlers.ts&lt;/code&gt; and keep the new &lt;code&gt;route.ts&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium templates, your own server code:&lt;/strong&gt; code of yours that reads a template's store must call &lt;code&gt;openPostgresWhenSet()&lt;/code&gt; from the template's &lt;code&gt;db/postgres.ts&lt;/code&gt; at the top of the module. With DATABASE_URL set (or &lt;code&gt;setDatabase()&lt;/code&gt;), the store now refuses, with a sentence, rather than run on memory. On serverless hosting each route is its own function, so don't rely on a template route having run first. Calling it more than once changes nothing; without DATABASE_URL it opens nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium blocks and templates, &lt;code&gt;use-answering-approvals&lt;/code&gt;:&lt;/strong&gt; run &lt;code&gt;npx candor-ui add use-answering-approvals&lt;/code&gt;. Ten blocks and three templates import it, and &lt;code&gt;update&lt;/code&gt; names it but doesn't install it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium templates, layout:&lt;/strong&gt; template shells fill their container, not the window; each template's new &lt;code&gt;layout.tsx&lt;/code&gt; sets &lt;code&gt;h-dvh&lt;/code&gt;. If you render a shell in your own page or layout, give its parent a height. If you already have &lt;code&gt;app/&amp;lt;template&amp;gt;/layout.tsx&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; keeps yours and writes the new one beside it as &lt;code&gt;layout.tsx.candor-2.9.0&lt;/code&gt;: add the &lt;code&gt;h-dvh&lt;/code&gt; wrapper to yours.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium templates, &lt;code&gt;setNavigate()&lt;/code&gt;:&lt;/strong&gt; new and optional. If you give it your router, also read the address from the router where the template reads &lt;code&gt;window.location&lt;/code&gt;: the ops console's current page, its sign-in check, &lt;code&gt;?run=&lt;/code&gt; and &lt;code&gt;?prompt=&lt;/code&gt;, and the project workspace's &lt;code&gt;?project=&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The Next.js starter's &lt;code&gt;/api/chat&lt;/code&gt;&lt;/strong&gt; now refuses a POST another site's page sent, as &lt;code&gt;/api/agent&lt;/code&gt; does. If you started from the starter, add &lt;code&gt;if (crossSite(request)) return crossSiteRefused()&lt;/code&gt; as the first line of your &lt;code&gt;/api/chat&lt;/code&gt; POST, importing it from &lt;code&gt;app/_lib/cross-site.ts&lt;/code&gt;. The Next.js and TanStack Start agent routes answer 403 to another site's page; if your app is served from more than one origin, list the others in &lt;code&gt;CANDOR_TRUSTED_ORIGINS&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Message&lt;/code&gt;'s working line&lt;/strong&gt; says &amp;quot;Working&amp;quot; before anything of a reply arrives, under the new key &lt;code&gt;message.working&lt;/code&gt;. If you overrode &lt;code&gt;message.thinking&lt;/code&gt; for that line, move your text to &lt;code&gt;message.working&lt;/code&gt;; the old override still works until 3.0. Reasoning still says &amp;quot;Thinking&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;codeEditor.hint&lt;/code&gt;:&lt;/strong&gt; in CodeEditor, and in InstructionsEditor, which is built on it, Esc, then Shift+Tab now leaves the field backwards, and the hint says so. If you translate &lt;code&gt;codeEditor.hint&lt;/code&gt;, update your text.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;RunTree&lt;/code&gt; with &lt;code&gt;graphView&lt;/code&gt;:&lt;/strong&gt; the root element is always a wrapper, with &lt;code&gt;data-slot=&amp;quot;run-tree&amp;quot;&lt;/code&gt; and your &lt;code&gt;className&lt;/code&gt;, around the switch and the tree, even before the work branches. If your CSS or tests expect the tree itself as the root when &lt;code&gt;graphView&lt;/code&gt; is set, point them inside the wrapper. Without &lt;code&gt;graphView&lt;/code&gt; the root is the tree, as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DataTable&lt;/code&gt; now depends on &lt;code&gt;locked&lt;/code&gt;:&lt;/strong&gt; its Previous and Next page buttons are &lt;code&gt;Locked&lt;/code&gt; with a reason instead of &lt;code&gt;disabled&lt;/code&gt;. When you update it, &lt;code&gt;update&lt;/code&gt; names &lt;code&gt;locked&lt;/code&gt; if your project doesn't have it; run the &lt;code&gt;add&lt;/code&gt; command it gives. If you translate DataTable, add the new &lt;code&gt;firstPage&lt;/code&gt; and &lt;code&gt;lastPage&lt;/code&gt; strings.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CLI, &lt;code&gt;add&lt;/code&gt; without a terminal&lt;/strong&gt; (a coding agent, CI, a pipe): if a file of yours differs from the one the add would write and &lt;code&gt;--overwrite&lt;/code&gt; isn't given, &lt;code&gt;add&lt;/code&gt; installs nothing, names the files and exits 1, and &lt;code&gt;add --dry-run&lt;/code&gt; says the add would stop and exits 1. A &lt;code&gt;utils.ts&lt;/code&gt; from before shadcn 4.23 is such a file, and a file that differs only by trailing spaces now counts as different. Add &lt;code&gt;--overwrite&lt;/code&gt;, or run &lt;code&gt;add&lt;/code&gt; at a terminal.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-tokens.css&lt;/code&gt; beside &lt;code&gt;candor.css&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;candor.css&lt;/code&gt; now imports &lt;code&gt;candor-tokens.css&lt;/code&gt; instead of carrying its own copy. Keep &lt;code&gt;styles/candor-tokens.css&lt;/code&gt; beside &lt;code&gt;candor.css&lt;/code&gt; (&lt;code&gt;npx candor-ui add tokens&lt;/code&gt; if it's missing; &lt;code&gt;doctor&lt;/code&gt; says so). If your CSS imports both files, remove the &lt;code&gt;candor-tokens.css&lt;/code&gt; import.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AppLayout&lt;/code&gt;:&lt;/strong&gt; on a narrow frame the panel's sheet now draws its own label and Close in a row above the panel. If your panel has its own close button, pass &lt;code&gt;panelCloses&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;New (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;document-viewer&lt;/code&gt;&lt;/strong&gt; shows a document's pages, which your app renders (an image URL, or a canvas or other element per page; Candor bundles no PDF engine), with labelled regions over them in the page's own units. Regions an agent proposed are drawn dashed and named as the agent's. Arrow keys or J and K move between regions, Enter selects, and &lt;code&gt;onRegionSelect&lt;/code&gt; reports it. It has zoom and page turning, and a page still drawing or one that couldn't be drawn says so (with Try again through &lt;code&gt;onRetry&lt;/code&gt;). Draw only the page on screen by rendering it when &lt;code&gt;onPageChange&lt;/code&gt; names it. (KIT-15)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;extraction-review&lt;/code&gt;&lt;/strong&gt; puts the fields an agent extracted beside the document, each with its value, its confidence and basis, and where it came from; selecting a field selects its region, and the other way round. Nothing starts accepted. A changed value is marked &amp;quot;Changed by you&amp;quot; with the agent's value kept beside it, and &lt;code&gt;onSubmit&lt;/code&gt; gets exactly the fields the person accepted or changed. Pass &lt;code&gt;requireAll&lt;/code&gt; to wait for every field. A decision belongs to the value it was made on: if a re-extraction or streamed values change a field the person had accepted or changed, the field is open again, says why, and isn't sent until they decide again. Send review is locked while a review is on its way and after it is sent, until a decision changes. (KIT-15)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;change-set-review&lt;/code&gt;&lt;/strong&gt; lets a person review many record edits an agent proposes and keep or drop each one; none starts kept. It filters by kind, pages a large set, works from the keyboard (arrows, and K and D, which come from the strings &lt;code&gt;keepKey&lt;/code&gt; and &lt;code&gt;dropKey&lt;/code&gt;) and counts what's kept. It shows what can and can't be undone from your app's &lt;code&gt;undo&lt;/code&gt;. Apply calls &lt;code&gt;onApply(kept, hash)&lt;/code&gt; with exactly the kept edits and their &lt;code&gt;changeHash&lt;/code&gt;, so your server applies only what was approved. The hash is named &lt;code&gt;sha256:&lt;/code&gt; only when it comes from the default &lt;code&gt;changeHash&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;reconcile-table&lt;/code&gt;&lt;/strong&gt; shows rows from two sources side by side: rows that match, rows found in only one source, and rows that conflict, with the differing fields marked and both values shown. Each row offers the resolve actions your app lists, and nothing is resolved for the person; a row reads as resolved once you record it through &lt;code&gt;resolution&lt;/code&gt;. A summary says what's left. (KIT-16)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;code-listing&lt;/code&gt;&lt;/strong&gt; shows code to read, with line numbers that aren't copied with it, the language named, Copy, and lines that wrap by default (a switch scrolls them sideways instead). It can mark ranges of lines with your reason, and with &lt;code&gt;previous&lt;/code&gt; it switches between the code and its changes line by line. (KIT-24)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;code-editor&lt;/code&gt;&lt;/strong&gt; is a small code field with line numbers, Tab indenting and your validation message tied to its line. Esc, then Tab or Shift+Tab, leaves the field. It is not a full editor; for autocomplete and linting, follow the code editor pattern to embed CodeMirror or Monaco. (KIT-24)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;comment-thread&lt;/code&gt;&lt;/strong&gt;, a discussion anchored to one thing in your app (a plan step, a diff line, a form field, an output), between people and agents. Pass the anchor's kind, id, label and a short quote; when your server finds the thing has changed or gone, pass &lt;code&gt;status&lt;/code&gt; and the thread says so. Comments, replies, resolve and reopen with who and when, edit and delete of the viewer's own comments (the confirmation says what stays visible), unread marks, arrow-key navigation, and a screen-reader announcement for a new comment. Every action calls your server and shows as sending until the data you pass back has it. (KIT-19)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;presence&lt;/code&gt;&lt;/strong&gt;, who is looking at the same thing now, people and agents, from your presence data: viewing, editing, or idle since a time. A state you don't report shows as unknown, and &lt;code&gt;null&lt;/code&gt; says who's here isn't known. Pass &lt;code&gt;updatedAt&lt;/code&gt; and presence older than &lt;code&gt;staleAfter&lt;/code&gt; is stamped &amp;quot;As of 10:42&amp;quot;. Put it in &lt;code&gt;ThreadHeader&lt;/code&gt;'s &lt;code&gt;actions&lt;/code&gt; or &lt;code&gt;CommentThread&lt;/code&gt;'s &lt;code&gt;presence&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;agent-screen&lt;/code&gt;&lt;/strong&gt;, a live view of a computer-use or browser agent's screen, from an image per frame, a video URL or a MediaStream your app passes. It says who has control, with Take over and Hand back. Pause and Stop say what happens to the step in flight in your words (&lt;code&gt;pauseNote&lt;/code&gt;, &lt;code&gt;stopNote&lt;/code&gt;), or that you haven't said. The agent's current action is shown as text and is the frame's text alternative. Nothing is drawn while connecting. With &lt;code&gt;frameAt&lt;/code&gt;, a frame older than &lt;code&gt;staleAfter&lt;/code&gt; is stamped &amp;quot;No new frame since 10:42&amp;quot;. Recording says what it records before it starts and stays marked while it runs.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;graph-layout&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;graph-view&lt;/code&gt;&lt;/strong&gt;, the layered layout and drawing behind the graph views below, for your own graphs. (KIT-22)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;model-picker&lt;/code&gt;&lt;/strong&gt;, a model menu for Composer's &lt;code&gt;tools&lt;/code&gt; slot from ModelSettings' &lt;code&gt;ModelOption&lt;/code&gt; list, grouped by vendor with cost. A model whose zero-retention terms aren't attested stays listed, says so and can't be picked; nothing is chosen for the person. It stays controlled as &lt;code&gt;locked&lt;/code&gt; comes and goes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;composer-sources&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;useComposerSources(sources, { onSignIn })&lt;/code&gt; puts MCP connections in the @ menu under &amp;quot;Connected sources&amp;quot;: connected, needs sign-in (choosing it calls &lt;code&gt;onSignIn&lt;/code&gt;), or unavailable with your reason.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;use-answering-approvals&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;useAnsweringApprovals(respond)&lt;/code&gt; keeps a permission prompt from being answered twice; when an answer fails to send, the prompt can be answered again and &lt;code&gt;failed&lt;/code&gt; gives a sentence to show. Premium blocks and templates use it, and a failed answer is no longer an unhandled rejection.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Chat (free unless marked):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Message&lt;/code&gt;:&lt;/strong&gt; before anything of a streaming reply arrives, the line says &amp;quot;Working&amp;quot; instead of &amp;quot;Thinking&amp;quot;, with a neutral icon. The new key is &lt;code&gt;message.working&lt;/code&gt;; an override of &lt;code&gt;message.thinking&lt;/code&gt; still works until 3.0. Reasoning still says &amp;quot;Thinking&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;composer&lt;/code&gt;:&lt;/strong&gt; an @ option can carry a &lt;code&gt;status&lt;/code&gt;, be &lt;code&gt;unavailable&lt;/code&gt; with a reason (shown, can't be chosen), or call &lt;code&gt;onChoose&lt;/code&gt; in place of inserting. Existing mentions are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;format-elapsed&lt;/code&gt;&lt;/strong&gt; (new, free): &lt;code&gt;formatElapsed&lt;/code&gt; now lives in a free lib with no &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt;, so server code can call it; importing it from &lt;code&gt;streaming-text&lt;/code&gt; still works. &lt;code&gt;useFormat&lt;/code&gt; is now optimised by the React Compiler.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Toaster&lt;/code&gt;:&lt;/strong&gt; the toasts that stay slide on the move family's &lt;code&gt;cd-move&lt;/code&gt;, so brand motion tokens apply.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;mcp-input&lt;/code&gt; and &lt;code&gt;sound&lt;/code&gt;:&lt;/strong&gt; their first doc comment is no longer dropped on install.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Work and review (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Plan&lt;/code&gt; and &lt;code&gt;RunTree&lt;/code&gt;:&lt;/strong&gt; with &lt;code&gt;graphView&lt;/code&gt;, when steps run side by side, a List / Graph switch shows the same work as a graph laid out from the dependencies the data already has; arrow keys move between steps. The switch is opt-in and the list stays the default, so apps that don't set &lt;code&gt;graphView&lt;/code&gt; see no new control. With &lt;code&gt;graphView&lt;/code&gt;, RunTree's root is the wrapper from the first render, so collapsed groups and focus are kept when a second agent starts. &lt;code&gt;RunNode&lt;/code&gt; gains an optional &lt;code&gt;dependsOn&lt;/code&gt;. Plan numbers its steps in the locale's digits. (KIT-22)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Diagram&lt;/code&gt;:&lt;/strong&gt; pass &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;edges&lt;/code&gt; instead of Mermaid &lt;code&gt;source&lt;/code&gt; and Candor draws the diagram without loading Mermaid, laid out from the edges. A node with &lt;code&gt;column&lt;/code&gt; and &lt;code&gt;row&lt;/code&gt; stays where you put it. &lt;code&gt;source&lt;/code&gt; is now optional. (KIT-22)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;instructions-editor&lt;/code&gt;&lt;/strong&gt; is built on &lt;code&gt;code-editor&lt;/code&gt;: it numbers its lines and says which line an unknown variable is on when they share one. Its props are unchanged. The unknown-variable message is read politely with the field instead of as an alert.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;artifact-panel&lt;/code&gt;&lt;/strong&gt; previews tables: pass &lt;code&gt;table&lt;/code&gt; with CSV or TSV text, or columns and rows. It shows the first 100 rows (set &lt;code&gt;previewRows&lt;/code&gt;), says how many more there are (&lt;code&gt;totalRows&lt;/code&gt; if you send only the start), and keeps the raw text, showing the same first rows, one toggle away. The &lt;code&gt;Artifact&lt;/code&gt; type's description is back. (KIT-24)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;selection-actions&lt;/code&gt;:&lt;/strong&gt; with &lt;code&gt;onRewrite&lt;/code&gt;, the toolbar offers your &lt;code&gt;rewrites&lt;/code&gt; (improve, shorten, tone) and, with &lt;code&gt;describeEdit&lt;/code&gt;, a box for the person's own words. The result shows as a read-only ProseDiff, labelled AI-generated, with Keep and Discard of equal weight; nothing is replaced until Keep (&lt;code&gt;onKeep&lt;/code&gt; gets the original, the revision, what was asked and the selection's Range). Discard aborts a rewrite on its way. Closing the rewrite panel gives focus back.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ApprovalRequest&lt;/code&gt;, &lt;code&gt;RunLog&lt;/code&gt; and &lt;code&gt;FailureClusters&lt;/code&gt;&lt;/strong&gt; take &lt;code&gt;headingLevel&lt;/code&gt; (2 to 6, default 3, as before).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Focus:&lt;/strong&gt; AgentScreen, ReconcileTable and SelectionActions keep keyboard focus when a pressed control is replaced. AgentScreen's Resume icon isn't mirrored in right-to-left.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;CommentThread&lt;/code&gt;:&lt;/strong&gt; an @ option that carries an &lt;code&gt;entity&lt;/code&gt; types its label like any other.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Data and lists (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;data-table&lt;/code&gt; column resizing&lt;/strong&gt; with &lt;code&gt;resizable&lt;/code&gt;: drag a header's edge, or focus it and use the arrow keys (Shift for bigger steps, Home for the narrowest); double-click gives the column its own width back; right-to-left follows the edge. Each column keeps to its &lt;code&gt;minWidth&lt;/code&gt; or the table's &lt;code&gt;minColumnWidth&lt;/code&gt; (64 px). Pass &lt;code&gt;columnWidths&lt;/code&gt; and save what &lt;code&gt;onColumnWidthsChange&lt;/code&gt; reports to keep the widths between visits. The resize handle has &lt;code&gt;aria-valuemax&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;data-table&lt;/code&gt; footer aggregates.&lt;/strong&gt; A column's &lt;code&gt;aggregate&lt;/code&gt; (&lt;code&gt;count&lt;/code&gt;, &lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;average&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;) adds a footer row formatted through LocaleProvider (&lt;code&gt;aggregateFormat&lt;/code&gt; takes Intl.NumberFormat options). Each cell says which rows it covers: in memory, every row matching the search and filters; in server mode, &amp;quot;this page&amp;quot; unless your server sends &lt;code&gt;aggregateTotals&lt;/code&gt;. A page's sum is never shown as the total. Blanks are counted and said.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;data-table&lt;/code&gt; pinned columns:&lt;/strong&gt; &lt;code&gt;pin: &amp;quot;start&amp;quot; | &amp;quot;end&amp;quot;&lt;/code&gt; keeps a column in view while the table scrolls sideways, in right-to-left too.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;data-table&lt;/code&gt; columns an agent fills,&lt;/strong&gt; with &lt;code&gt;agent: { by, state, inputs?, onRetry? }&lt;/code&gt;: the header names the model or tool and what it reads; each cell waits, shows its value as text with an AI-generated mark, or says &amp;quot;Couldn't fill&amp;quot; with the reason (and Try again with &lt;code&gt;onRetry&lt;/code&gt;). Cells still on their way are left out of the footer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Pagers:&lt;/strong&gt; ChangeSetReview's, ReconcileTable's and DataTable's Previous and Next page are &lt;code&gt;Locked&lt;/code&gt; with a reason instead of &lt;code&gt;disabled&lt;/code&gt; (new strings &lt;code&gt;firstPage&lt;/code&gt;, &lt;code&gt;lastPage&lt;/code&gt;). DataTable now depends on &lt;code&gt;locked&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Charts and &lt;code&gt;SpendBreakdown&lt;/code&gt;:&lt;/strong&gt; pass &lt;code&gt;onRetry&lt;/code&gt; and an error state shows Try again, as lists do.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;RunLog&lt;/code&gt; and &lt;code&gt;SpendBreakdown&lt;/code&gt;:&lt;/strong&gt; a run's cost and the spend total are written in LocaleProvider's locale, as billing amounts are. A cost under a cent is shown, not rounded to $0.00. Whole amounts read without decimals (&amp;quot;$3&amp;quot;), and the total gains no floating-point digits.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Other (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AppLayout&lt;/code&gt;:&lt;/strong&gt; on a narrow frame the panel's sheet shows the panel's label and Close in a row above the panel, so Close no longer covers the panel's first row. If your panel has its own close button, pass &lt;code&gt;panelCloses&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;NumberInput&lt;/code&gt;:&lt;/strong&gt; range checks are your app's; check the number you get from &lt;code&gt;onValueChange&lt;/code&gt;. The doc comment now says so.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks and templates (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Each template's store loads no database code.&lt;/strong&gt; Postgres is opened by &lt;code&gt;openPostgresWhenSet()&lt;/code&gt; in the template's new &lt;code&gt;db/postgres.ts&lt;/code&gt;, which every route file calls, and each data route's code is in a &lt;code&gt;handlers.ts&lt;/code&gt; beside its &lt;code&gt;route.ts&lt;/code&gt;. Installed with DATABASE_URL set, a template uses Postgres as before. If you added a route that reads a template's store, call &lt;code&gt;openPostgresWhenSet()&lt;/code&gt; in it: a server with DATABASE_URL set now refuses, with a sentence, rather than keep that route's data in memory. Every template route that loads the store is tested to open the database.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Your router.&lt;/strong&gt; Each template navigates through one function you can point at your router with &lt;code&gt;setNavigate()&lt;/code&gt;. Left alone, it loads the page as before. Each template's sign-in page moves on through the template's &lt;code&gt;go()&lt;/code&gt;, so the router covers signing in too; the server foundation's &lt;code&gt;DemoSignIn&lt;/code&gt; takes &lt;code&gt;onSignedIn(next)&lt;/code&gt; for this. The project workspace's downloads are links.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Shells fill their container&lt;/strong&gt; instead of the window. A new &lt;code&gt;layout.tsx&lt;/code&gt; in each template keeps a standalone install filling the window; inside your own layout, give their container a height.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Approvals answered once.&lt;/strong&gt; The blocks and templates use &lt;code&gt;useAnsweringApprovals&lt;/code&gt;, so a permission prompt can't be answered twice and a failed answer can be sent again; add &lt;code&gt;use-answering-approvals&lt;/code&gt; when you update.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Headings:&lt;/strong&gt; the approvals inbox's request page, the agent ops console's Runs page and the support copilot's Quality page no longer put an extra h2 above ApprovalRequest, RunLog and FailureClusters; they pass &lt;code&gt;headingLevel={2}&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Words through LocaleProvider:&lt;/strong&gt; the sign-in pages' brand and the run console's and support copilot's prompt notes (new keys under &lt;code&gt;approvalsInbox&lt;/code&gt;, &lt;code&gt;agentOpsConsole&lt;/code&gt;, &lt;code&gt;supportCopilot&lt;/code&gt;, &lt;code&gt;projectWorkspace&lt;/code&gt;, &lt;code&gt;runConsole&lt;/code&gt;), and three more template words (the ops console gains &lt;code&gt;team&lt;/code&gt; under &lt;code&gt;agentOpsConsole&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Support copilot:&lt;/strong&gt; the customer switch shows the new customer's thread at once.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Project workspace&lt;/strong&gt; uses AppLayout's &lt;code&gt;panelCloses&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Starters&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Next.js and TanStack Start agent routes refuse requests another site's page sent (403); set &lt;code&gt;CANDOR_TRUSTED_ORIGINS&lt;/code&gt; to allow particular sites. The Next.js starter's &lt;code&gt;/api/chat&lt;/code&gt; refuses them too: if you started from the starter, add &lt;code&gt;if (crossSite(request)) return crossSiteRefused()&lt;/code&gt; as the first line of your &lt;code&gt;/api/chat&lt;/code&gt; POST, importing it from &lt;code&gt;app/_lib/cross-site.ts&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The starters' chats ignore a second press of Allow or Deny made before the screen updates.&lt;/li&gt;&lt;li&gt;The starters carry Candor 2.9.0's components.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.14.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Base UI, Tailwind prefix and right-to-left in-process.&lt;/strong&gt; On a Base UI style, &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;add --dry-run&lt;/code&gt; work out shadcn's &lt;code&gt;asChild&lt;/code&gt; → &lt;code&gt;render&lt;/code&gt; rewrite themselves, using your project's own &lt;code&gt;typescript&lt;/code&gt;, instead of running a shadcn preview per item. With no TypeScript, or only TypeScript 7 (which has no JavaScript API), those items use shadcn's preview as before. Projects with a Tailwind &lt;code&gt;prefix&lt;/code&gt; or &lt;code&gt;rtl: true&lt;/code&gt; are worked out in-process the same way. &lt;code&gt;tsx: false&lt;/code&gt;, &lt;code&gt;cssVariables: false&lt;/code&gt;, and aliases through package.json imports or a workspace package still use shadcn's preview; the README says why for each. Checked against real shadcn 4.23 installs of the &lt;code&gt;asChild&lt;/code&gt; items into a Base UI project and of every item into right-to-left and Tailwind-prefixed projects: the files are byte-identical.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt; without a terminal&lt;/strong&gt; (a coding agent, CI, a pipe): shadcn can't ask before replacing a file of yours that differs, so it stopped part-way. &lt;code&gt;add&lt;/code&gt; now checks first: if a file differs and &lt;code&gt;--overwrite&lt;/code&gt; isn't given, it installs nothing, names the files and exits 1, and &lt;code&gt;add --dry-run&lt;/code&gt; says the add would stop and exits 1. A &lt;code&gt;utils.ts&lt;/code&gt; from before shadcn 4.23 is such a file. Add &lt;code&gt;--overwrite&lt;/code&gt;, or run &lt;code&gt;add&lt;/code&gt; at a terminal. A file that differs only by trailing spaces now counts as different, because shadcn would ask about it. Without RSC (&lt;code&gt;rsc: false&lt;/code&gt;), a file that differs only by its &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt; line counts as the same, and when nothing else differs &lt;code&gt;add&lt;/code&gt; runs shadcn with &lt;code&gt;--overwrite&lt;/code&gt;, which changes at most that line, so it doesn't stop to ask.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;shadcn runs in the CLI's process group,&lt;/strong&gt; as in 0.13, so a kill to that group (&lt;code&gt;timeout -s KILL&lt;/code&gt;, a coding tool's timeout) stops shadcn too.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add --diff&lt;/code&gt; and &lt;code&gt;add --view&lt;/code&gt;&lt;/strong&gt; at a version other than the newest no longer point components.json at the snapshot for the run; shadcn's first line names a temporary file. The path after &lt;code&gt;--diff&lt;/code&gt; or &lt;code&gt;--view&lt;/code&gt; is now passed to shadcn as their value; before, it was taken for an item name.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;update&lt;/code&gt;:&lt;/strong&gt; when the new version of an item needs another your project doesn't have, &lt;code&gt;update&lt;/code&gt; names it with the &lt;code&gt;add&lt;/code&gt; command, even if the old version needed it too (a theme whose &lt;code&gt;candor-tokens.css&lt;/code&gt; was never installed).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;doctor&lt;/code&gt;:&lt;/strong&gt; a &lt;code&gt;candor.css&lt;/code&gt; that imports &lt;code&gt;candor-tokens.css&lt;/code&gt; without that file beside it is a fix (&lt;code&gt;npx candor-ui add tokens&lt;/code&gt;), and if you moved &lt;code&gt;candor.css&lt;/code&gt;, the fix says to move the file beside it. Your CSS importing &lt;code&gt;candor-tokens.css&lt;/code&gt; as well as &lt;code&gt;candor.css&lt;/code&gt; is a note.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;lint&lt;/code&gt;&lt;/strong&gt; knows the new components.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;suggest_components&lt;/code&gt;&lt;/strong&gt; reads the words people use for an item and the tasks it answers from the item's own doc comment (&lt;code&gt;@keywords&lt;/code&gt;, &lt;code&gt;@job&lt;/code&gt;), compiled by &lt;code&gt;npm run docs&lt;/code&gt; into the docs data, instead of tables in the server. The items new in 2.9 carry tags, and the evaluation set has a task for each new job.&lt;/li&gt;&lt;li&gt;It no longer says Candor has no document or PDF viewer; a PDF or extraction task gets &lt;code&gt;document-viewer&lt;/code&gt; and &lt;code&gt;extraction-review&lt;/code&gt;. When a block or template answers the task, a hook or helper comes after it, so &amp;quot;an approvals inbox&amp;quot; lists the template again (ask for the hook by name, or say &amp;quot;hook&amp;quot;, to have it listed). Tasks about deploys suggest the approvals inbox and the approval-gated change. &amp;quot;next to&amp;quot; in a task no longer matches items that say &amp;quot;next&amp;quot;. A confirm-dialog task lists its four items in ranking order, and signup and 404 tasks no longer suggest &lt;code&gt;account-state&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New patterns:&lt;/strong&gt; &amp;quot;Document review&amp;quot; (render a PDF's pages with pdf.js in your app, review the extracted values beside them, and hash what was accepted with &lt;code&gt;changeHash&lt;/code&gt;, checking the hash on your server); &amp;quot;Apply only the record edits a person kept&amp;quot; (&lt;code&gt;/patterns/apply-reviewed-change-set&lt;/code&gt;: send the kept ids and the hash, rebuild the edits from the server's own copy, recompute the hash, check for drift, apply all or nothing); &amp;quot;Comments on agent work&amp;quot; (anchor threads to a run, plan or diff, decide on the server whether the thing has changed, and what is left to your app); &amp;quot;Show a computer-use or browser agent's screen&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New screen,&lt;/strong&gt; &amp;quot;Extraction review&amp;quot;, with three layouts: fields beside the page, a queue of documents, and in the conversation. Screens list the other new items where they fit.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Patterns updated:&lt;/strong&gt; PDF rendering points at &lt;code&gt;document-viewer&lt;/code&gt;; the code editor pattern starts from &lt;code&gt;code-editor&lt;/code&gt; and names &lt;code&gt;code-listing&lt;/code&gt;; the offline pattern uses PageState's &lt;code&gt;offline&lt;/code&gt; kind.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Tokens and theming&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor.css&lt;/code&gt; imports &lt;code&gt;candor-tokens.css&lt;/code&gt;,&lt;/strong&gt; the file every item installs, instead of carrying its own copy; the resolved CSS is unchanged. Keep &lt;code&gt;styles/candor-tokens.css&lt;/code&gt; beside &lt;code&gt;candor.css&lt;/code&gt;. If your CSS imports both files, remove the &lt;code&gt;candor-tokens.css&lt;/code&gt; import.&lt;/li&gt;&lt;li&gt;The token manifest lists the new items' &lt;code&gt;data-slot&lt;/code&gt; names.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The template demos work in browsers without the Navigation API, and their sign-in keeps the demo's data in every browser. The site build no longer needs a plugin to leave out the templates' database code.&lt;/li&gt;&lt;li&gt;The home page's &amp;quot;New in 2.9&amp;quot; link opens this section. The Accessibility page says what was checked for 2.9 (the browser suites; the 400% pass was 2.8's) and that copy fields wrap unless given &lt;code&gt;truncate&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Roadmap: the Later column keeps &amp;quot;A shared task board&amp;quot;; the computer-use view shipped as &lt;code&gt;agent-screen&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Registry&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Each item's description comes from the item's own doc comment. Before, the first &lt;code&gt;/**&lt;/code&gt; comment in the file was taken, so some items were described by a field's or helper's words.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 2.9.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The free items' changes above (&lt;code&gt;Message&lt;/code&gt;'s working line, &lt;code&gt;composer&lt;/code&gt;'s option states, &lt;code&gt;format-elapsed&lt;/code&gt;, &lt;code&gt;Toaster&lt;/code&gt;, &lt;code&gt;mcp-input&lt;/code&gt; and &lt;code&gt;sound&lt;/code&gt;) are in this version. &lt;code&gt;formatElapsed&lt;/code&gt; comes from &lt;code&gt;format-elapsed&lt;/code&gt;, and importing it from &lt;code&gt;streaming-text&lt;/code&gt; still works.&lt;/li&gt;&lt;li&gt;Both stylesheets are built with &lt;code&gt;candor.css&lt;/code&gt;'s imports inlined; the CSS is the same.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For contributors&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Search tags:&lt;/strong&gt; &lt;code&gt;@keywords&lt;/code&gt; and &lt;code&gt;@job&lt;/code&gt; in an item's doc comment feed the docs MCP; if you add or rename an item, tag it there. The tags are documented in &lt;code&gt;scripts/build-docs.mjs&lt;/code&gt;'s header.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;One contrast implementation,&lt;/strong&gt; &lt;code&gt;packages/cli/src/contrast.ts&lt;/code&gt; (ARCH-12).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;packages/cli/scripts/shadcn-differential.mjs&lt;/code&gt;&lt;/strong&gt; compares the CLI's rewrites with shadcn's own on every registry code file in six project shapes; the weekly shadcn canary runs it against shadcn@latest. The canary workflow's token only reads the repository.&lt;/li&gt;&lt;li&gt;&lt;code&gt;blobToken()&lt;/code&gt; treats &lt;code&gt;[SENSITIVE]&lt;/code&gt; as no token for every caller.&lt;/li&gt;&lt;li&gt;Tests cover the registry function's Blob wiring and the docs MCP's caching.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.8.0</title>
      <link>https://candor.themethodic.com/changelog#2-8-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-8-0</guid>
      <pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The work under the kit: Candor's tokens published as data, docs kept for every release, a CLI that works out shadcn's files itself, &lt;code&gt;@candor-ui/react&lt;/code&gt; as the trial path, a site where each page downloads only its own code, and the four Premium templates running on the site with sample data. Blocks and templates keep server errors on the server and refuse requests another site's page sent. Forms, admin and list components get the fixes from the 2.7 review. One item is new, &lt;code&gt;candor-provider&lt;/code&gt; (Pro), so the kit grows from 299 to 300 items: 70 free, 269 Pro. With CLI 0.13.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.8.0. Nothing is removed and no prop is renamed. A few behaviours change for code you already have; each is in &amp;quot;What to do&amp;quot; below and again in its section.&lt;/p&gt;&lt;h3&gt;What to do&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;NumberInput&lt;/strong&gt; is now a text field with the spin button role. If you read the native field's &lt;code&gt;valueAsNumber&lt;/code&gt;, or its &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt; or &lt;code&gt;step&lt;/code&gt; attributes from the DOM, read &lt;code&gt;onValueChange&lt;/code&gt; instead.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ScheduleEditor:&lt;/strong&gt; if you overrode the &lt;code&gt;ruleWeekday&lt;/code&gt; string, add &lt;code&gt;{days}&lt;/code&gt; to your text.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CopyField&lt;/strong&gt; now wraps a long value instead of cutting it off. For the old one-line look, set &lt;code&gt;truncate&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CLI:&lt;/strong&gt; &lt;code&gt;add --dry-run&lt;/code&gt; exits 1 where the add itself would stop. A script that relied on the dry run always exiting 0 should check its message. &lt;code&gt;doctor&lt;/code&gt; exits 1 when &lt;code&gt;@candor-ui/react&lt;/code&gt; is installed beside Pro or Premium items, or with a licence key set.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Premium blocks and templates:&lt;/strong&gt; run &lt;code&gt;npx candor-ui update&lt;/code&gt; for your blocks, templates and the server foundation. Block files now ship as components and libs, so the update shows changes in every block file. Routes that change something now answer 403 to a request another site's page sent, from another origin or a sibling subdomain, unless it's listed in &lt;code&gt;CANDOR_TRUSTED_ORIGINS&lt;/code&gt;; if your app is served from more than one origin, list the others there. Errors that aren't a &lt;code&gt;Refusal&lt;/code&gt; show a fixed sentence with a 500. If you call &lt;code&gt;demoSessionRoutes()&lt;/code&gt;'s DELETE yourself, pass it the request.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Routes that changed something on GET now need a POST.&lt;/strong&gt; human-handoff's inbox with &lt;code&gt;?visit=1&lt;/code&gt; only reads; mark it seen with POST &lt;code&gt;{ action: &amp;quot;seen&amp;quot;, at }&lt;/code&gt;. approve-from-anywhere's run page no longer resumes runs on GET; send POST &lt;code&gt;{ action: &amp;quot;carry-on&amp;quot; }&lt;/code&gt;. If you call these routes yourself, send the POST.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A block installed in a project whose tsconfig alias isn't &lt;code&gt;@&lt;/code&gt;&lt;/strong&gt; (for example &lt;code&gt;~/*&lt;/code&gt;) didn't build. Run &lt;code&gt;npx candor-ui add &amp;lt;block&amp;gt; --overwrite&lt;/code&gt; to install it again with your aliases.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Diagram:&lt;/strong&gt; if you added it before, run &lt;code&gt;npm install mermaid&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;components.json without a &lt;code&gt;&amp;quot;lib&amp;quot;&lt;/code&gt; alias:&lt;/strong&gt; add one under &lt;code&gt;aliases&lt;/code&gt;, pointing at the folder of your &lt;code&gt;utils&lt;/code&gt; alias (&lt;code&gt;&amp;quot;lib&amp;quot;: &amp;quot;@/lib&amp;quot;&lt;/code&gt;). &lt;code&gt;candor-ui init&lt;/code&gt; adds it when &lt;code&gt;tsconfig.json&lt;/code&gt;'s paths confirm the folder, and &lt;code&gt;doctor&lt;/code&gt; says when it's missing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A nested &lt;code&gt;TooltipProvider&lt;/code&gt;&lt;/strong&gt; now takes the outer one's timing for any setting it leaves out. If you nest one to reset the delay, pass &lt;code&gt;delayDuration={0}&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;audit-data-controls:&lt;/strong&gt; a prepared export downloads only for a signed-in owner, and exporting from the page or through the agent is owner-only too. With Postgres, run the new migration &lt;code&gt;0001_exports_random_id.sql&lt;/code&gt;. If your own &lt;code&gt;AuditDataRepo&lt;/code&gt; assigns export ids, make them unguessable (&lt;code&gt;newExportId()&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Signed-out requests to block routes get 401, not 400.&lt;/strong&gt; Every block route checks who is signed in before it reads the request.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;plan-build-review, run-console, agent-ops-console:&lt;/strong&gt; a write that lost a race answers 409 with a sentence saying to try again, not a 500. If you catch &lt;code&gt;Refusal&lt;/code&gt; around these stores, these conflicts now reach your handler.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;New:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-provider&lt;/code&gt; (Pro):&lt;/strong&gt; wraps an app in Candor's locale, terms, entity kinds, agent roles, cards and tooltip timing from one config object. The config is plain data, so a root layout or a coding agent can write it, and every field is optional; a field left out keeps its default or what an outer provider set. Kinds, roles and cards with their own icons or renderers go in as the &lt;code&gt;kinds&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt; and &lt;code&gt;cards&lt;/code&gt; props. Install it with &lt;code&gt;npx candor-ui add candor-provider&lt;/code&gt;, then replace the nested providers at your app's root with &lt;code&gt;&amp;lt;CandorProvider config={…}&amp;gt;&lt;/code&gt;. It isn't in &lt;code&gt;@candor-ui/react&lt;/code&gt;. &lt;code&gt;ChartSizeProvider&lt;/code&gt; isn't included; nest it yourself. It always renders its six providers, so your app stays mounted when the config gains or loses a setting (a locale or tooltip preference that loads after the first render), and a setting you leave out passes through what an outer provider set.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Chat (free unless marked):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;How long the agent thought.&lt;/strong&gt; The AG-UI adapter's replies carry &lt;code&gt;thoughtFor&lt;/code&gt;, shown by &lt;code&gt;Reasoning&lt;/code&gt; as &amp;quot;Reasoning · 4s&amp;quot;, measured from the agent's own &lt;code&gt;REASONING_START&lt;/code&gt; and &lt;code&gt;REASONING_END&lt;/code&gt; timestamps and formatted in your LocaleProvider's locale. An agent that sends no timestamps shows no time. &lt;code&gt;fromAgUiEvents&lt;/code&gt; takes &lt;code&gt;formatDuration&lt;/code&gt; if you format it yourself; without it, the time reads as &lt;code&gt;formatElapsed&lt;/code&gt; does (&amp;quot;0.4s&amp;quot;, &amp;quot;1.6s&amp;quot;, &amp;quot;42s&amp;quot;, &amp;quot;2m 5s&amp;quot;), always rounded down. The AI SDK and Claude Agent SDK adapters don't set it, because neither protocol says when reasoning started.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The working line counts.&lt;/strong&gt; &lt;code&gt;ShimmerLabel&lt;/code&gt; and &lt;code&gt;Reasoning&lt;/code&gt; take &lt;code&gt;startedAt&lt;/code&gt; (when the request went out), and the working line then counts the time since, live: &amp;quot;Thinking · 4.2s&amp;quot;. A &lt;code&gt;Message&lt;/code&gt; can carry &lt;code&gt;startedAt&lt;/code&gt; too; until the reply's first words arrive it shows &amp;quot;Thinking&amp;quot;, counting up from &lt;code&gt;startedAt&lt;/code&gt; when it's given. Without &lt;code&gt;startedAt&lt;/code&gt; nothing counts. The live count is hidden from screen readers, so Reasoning's button stays &amp;quot;Thinking&amp;quot; while the count runs instead of changing its name ten times a second. &lt;code&gt;streaming-text&lt;/code&gt; is now a client component and exports &lt;code&gt;formatElapsed&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PermissionPrompt&lt;/code&gt;&lt;/strong&gt; takes &lt;code&gt;headingLevel&lt;/code&gt; (2 to 6, default 3).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;CopyField&lt;/code&gt;&lt;/strong&gt; shows its whole value, wrapping long commands, keys and URLs, so it can be read on a phone or at 400% zoom. For the old one-line look, set &lt;code&gt;truncate&lt;/code&gt;: the value still reads in full to screen readers and on focus.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;SourceList&lt;/code&gt; (Pro):&lt;/strong&gt; source chips wrap long labels instead of cutting them off. Source popovers have a name.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;LocaleProvider&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;format.date(value, style, { timeZone })&lt;/code&gt; shows a time in the given IANA zone instead of the provider's, for a time that belongs to a place. With a &lt;code&gt;locale&lt;/code&gt; set it renders the final text on the server. A zone the browser doesn't know shows the ISO form in UTC instead of throwing. &lt;code&gt;{ weekday: true }&lt;/code&gt; puts the short day name in front (&amp;quot;Tue, 10 Nov 2026, 9:00&amp;quot;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;RelativeTime&lt;/code&gt;&lt;/strong&gt; and the working line's timer: a time mounted between ticks, or after the clock went back, shows the current time.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;TooltipProvider&lt;/code&gt;&lt;/strong&gt; takes an outer TooltipProvider's timing for any setting it leaves out, instead of resetting to tooltips that open at once. If you nest one to reset the delay, pass &lt;code&gt;delayDuration={0}&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;CardRegistryProvider&lt;/code&gt;&lt;/strong&gt;'s &lt;code&gt;cards&lt;/code&gt; is optional; left out, the cards of a provider above still apply.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Forms (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Combobox&lt;/code&gt;:&lt;/strong&gt; a choice no longer reads as the placeholder when the current &lt;code&gt;options&lt;/code&gt; don't include it. It keeps the label it had when chosen, or is counted (&amp;quot;1 chosen&amp;quot;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;NumberInput&lt;/code&gt;&lt;/strong&gt; is now a text field with the spin button role, read and shown in LocaleProvider's locale (&amp;quot;1,5&amp;quot; in German; Arabic-Indic and Persian digits). A form still gets plain digits (&amp;quot;1.5&amp;quot;). A value changed from outside replaces what was typed. With a negative &lt;code&gt;min&lt;/code&gt;, phones show the full keyboard, which has a minus. Stepping from empty goes to 0, or the nearest end of the range. An arrow key pressed at the limit says why to screen readers. If you read the native field's &lt;code&gt;valueAsNumber&lt;/code&gt; or used &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt; or &lt;code&gt;step&lt;/code&gt; attributes from the DOM, read &lt;code&gt;onValueChange&lt;/code&gt; instead. A form reset clears typed text that isn't a number, and an uncontrolled field goes back to &lt;code&gt;defaultValue&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Field&lt;/code&gt;:&lt;/strong&gt; a &lt;code&gt;group&lt;/code&gt; with a function child now renders it. A group's radios and checkboxes are &lt;code&gt;aria-invalid&lt;/code&gt; while there's an error, and a required group's legend says &amp;quot;(required)&amp;quot; to screen readers. The error is in a polite live region, so an error that appears or changes as the person works is read out. Errors that arrive with a submit (&lt;code&gt;attempt&lt;/code&gt; goes up) are shown and describe their control, but are not put in each field's live region, so a screen reader hears them once, from FormErrorSummary and the focus move. Pass &lt;code&gt;attempt&lt;/code&gt; to get this.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PasswordInput&lt;/code&gt;:&lt;/strong&gt; the Caps Lock note is announced when it appears. A shown password is hidden again when its form is submitted, so the browser doesn't save it as text.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;OneTimeCode&lt;/code&gt;:&lt;/strong&gt; digits typed in Arabic-Indic or Persian script are kept. The boxes run left to right in right-to-left pages. The highlighted box follows the caret.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Admin and billing (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ScheduleEditor&lt;/code&gt;:&lt;/strong&gt; a time zone the browser doesn't know no longer breaks the editor; it says the next runs can't be worked out. New &lt;code&gt;weekdays&lt;/code&gt; sets the days &amp;quot;Every weekday&amp;quot; means, and the rule names them. If you overrode &lt;code&gt;ruleWeekday&lt;/code&gt;, add &lt;code&gt;{days}&lt;/code&gt; to your text. &lt;code&gt;nextRuns&lt;/code&gt; takes the same days as an optional fifth argument. Without &lt;code&gt;now&lt;/code&gt;, the next runs move on as each one passes. The next runs are formatted through the locale formatter in the schedule's own time zone; the text is unchanged. With &lt;code&gt;weekdays={[]}&lt;/code&gt;, an &amp;quot;Every weekday&amp;quot; rule reads &amp;quot;No working days are set, so it never runs&amp;quot; (new string &lt;code&gt;scheduleEditor.ruleWeekdayNone&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ApiKeys&lt;/code&gt;:&lt;/strong&gt; a new key's secret is no longer read aloud by screen readers. Focus moves to the &amp;quot;won't be shown again&amp;quot; note, and back to Create key afterwards. An expired key says &amp;quot;expired&amp;quot;, checked against the page's clock, so a key that expires while the page is open says so; the server shows &amp;quot;expiry &amp;lt;date&amp;gt;&amp;quot;, so hydration matches (new string &lt;code&gt;apiKeys.expiry&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Webhooks&lt;/code&gt;:&lt;/strong&gt; each webhook takes an optional &lt;code&gt;label&lt;/code&gt;. Set it for Slack, Discord or any URL that carries a token, and the URL stays off the screen and out of screen readers. URLs without a label now wrap.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ScheduleList&lt;/code&gt;, &lt;code&gt;ApiKeys&lt;/code&gt;, &lt;code&gt;Webhooks&lt;/code&gt;:&lt;/strong&gt; while a revoke, delete or remove is under way, Keep it is marked unavailable, looks locked and says why. After a delete, focus moves to the list's heading instead of dropping to the page; Keep it returns focus to the row's control.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ScheduleList&lt;/code&gt;:&lt;/strong&gt; an open job menu is named &amp;quot;More for &amp;lt;job&amp;gt;&amp;quot; again.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;EnvironmentConnect&lt;/code&gt;:&lt;/strong&gt; with &lt;code&gt;requireTest&lt;/code&gt; and no &lt;code&gt;onTest&lt;/code&gt;, Connect says no test can run here.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;InvoiceHistory&lt;/code&gt;:&lt;/strong&gt; the &amp;quot;Not ready&amp;quot; reason is read by screen readers. &lt;strong&gt;&lt;code&gt;BillingDetails&lt;/code&gt;:&lt;/strong&gt; the country error is tied to the country field.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Billing:&lt;/strong&gt; &lt;code&gt;formatMoney&lt;/code&gt; ignores spaces around the currency code, so &lt;code&gt;&amp;quot;eur &amp;quot;&lt;/code&gt; shows as €12.50.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Lists, logs and tables (Pro):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;onRetry&lt;/code&gt;&lt;/strong&gt; on SessionList, ApprovalQueue, NotificationCenter, RunLog, AuditLog, Inbox, MembersTable, KnowledgeSources, AgentRoster, ReviewQueue, TraceViewer, ResultTable, VersionHistory, EvalScorecard, FailureClusters, InvoiceHistory, DataTable, ApiKeys, DeviceSessions, ScheduleList and Webhooks. Under an error &lt;code&gt;state&lt;/code&gt; they show Try again, but only when you pass it, so pass it only when it loads the list again.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Under a &lt;code&gt;partial&lt;/code&gt; state&lt;/strong&gt;, counts of what loaded say they are a lower bound: RunLog's tabs and KnowledgeSources read &amp;quot;12+&amp;quot;, Inbox reads &amp;quot;Needs you · 3+&amp;quot;, ResultTable &amp;quot;at least 40 rows&amp;quot; and FailureClusters &amp;quot;at least 12 failures&amp;quot;. SpendBreakdown's total says some periods aren't known.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;NotificationCenter&lt;/code&gt;:&lt;/strong&gt; while loading or failed, the bell shows no unread count and there is no Mark all read. Under &lt;code&gt;partial&lt;/code&gt; it reads &amp;quot;2+&amp;quot;, named &amp;quot;Notifications, at least 2 unread&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;LogStream&lt;/code&gt;:&lt;/strong&gt; with &lt;code&gt;virtualize&lt;/code&gt; and &lt;code&gt;live&lt;/code&gt;, screen readers hear only lines that arrive, not lines scrolled back into view. An OSC escape sequence with no terminator no longer hides the rest of the line.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;AuditLog&lt;/code&gt;:&lt;/strong&gt; virtualised, each event tells screen readers its place in the whole list.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;TraceViewer&lt;/code&gt;:&lt;/strong&gt; a viewer first drawn while loading opens on the first failure, or the first span, once spans arrive.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DataTable&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;loading&lt;/code&gt; together with an error or empty &lt;code&gt;state&lt;/code&gt; shows only the skeleton rows, not both.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;KnowledgeSources&lt;/code&gt;:&lt;/strong&gt; Escape closes the remove confirmation and keeps the source, without also closing a Dialog or Sheet the list sits in. After Remove, focus moves to the Sources heading.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Other:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ReportReply&lt;/code&gt; (Pro):&lt;/strong&gt; until a reason is chosen, Report stays focusable and says &amp;quot;Choose what's wrong first.&amp;quot; instead of being disabled; override it under &lt;code&gt;reportReply.needsReason&lt;/code&gt;. While a report sends, Report is &lt;code&gt;aria-disabled&lt;/code&gt; and &lt;code&gt;aria-busy&lt;/code&gt; instead of &lt;code&gt;disabled&lt;/code&gt;, so focus stays in the popover, and a second press sends nothing. A failed send leaves the form open and says the report wasn't sent. Its popover has a name.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;email-layout&lt;/code&gt; (Pro):&lt;/strong&gt; &lt;code&gt;renderEmail&lt;/code&gt; no longer uses react-dom/server, so it runs in Next.js route handlers, server actions and server components, and a client page can import EmailPreview. The output is the same document as before. This lets the approve-from-anywhere block build in a new Next.js app.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;SelectionActions&lt;/code&gt; (Pro):&lt;/strong&gt; while an input or text area has focus, the toolbar doesn't appear.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Diagram&lt;/code&gt; (Pro)&lt;/strong&gt; now declares &lt;code&gt;mermaid&lt;/code&gt; as a dependency. Diagram loads it on first use, and the install used to leave it out. If you added Diagram before, run &lt;code&gt;npm install mermaid&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Install:&lt;/strong&gt; the header comments of the chat, know, highlight, mcp-input and sound libs (free) and the work, ops, team and change-hash libs (Pro) now survive &lt;code&gt;shadcn add&lt;/code&gt;, which drops anything before a file's first line of code.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks and templates (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Server errors stay on the server.&lt;/strong&gt; The browser gets a plain sentence with an eight-character reference, and the server log has the error under the same reference. A rule's refusal is still shown as written. The server foundation has &lt;code&gt;errorText()&lt;/code&gt;, &lt;code&gt;errorResponse()&lt;/code&gt; and &lt;code&gt;guardTools()&lt;/code&gt; for your own routes; wrap a Claude Agent SDK tool server as &lt;code&gt;createSdkMcpServer(guardTools({ name, tools }))&lt;/code&gt;. Server faults answer 500 (some routes used 404 or 409 for every error); a missing thread, reply, article or version answers 404, and someone who isn't an admin or owner gets 403.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AI SDK tools no longer pass a server error's words to the model.&lt;/strong&gt; A tool that throws gives the model and the browser a fixed sentence with a reference, and the detail goes to the server log; a rule's refusal is still said as written. Wrap your own tools as &lt;code&gt;streamText({ tools: guardToolSet({ … }) })&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Requests another site's page sent are refused.&lt;/strong&gt; Every route that changes something asks &lt;code&gt;crossSite(request)&lt;/code&gt; first and answers 403, which stops a page elsewhere acting as a signed-in person through their cookies. If your app is served from more than one origin, list the others in &lt;code&gt;CANDOR_TRUSTED_ORIGINS&lt;/code&gt;. It doesn't protect against cross-site scripting, callers outside a browser, or a route that changes something on GET. &lt;code&gt;demoSessionRoutes()&lt;/code&gt;'s DELETE now takes the request. &lt;code&gt;CANDOR_TRUSTED_ORIGINS&lt;/code&gt; entries are compared as origins (case, a default port, a trailing slash or a path no longer stop a match); an entry that isn't a URL is left out, and the log says so once.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Signed out gets 401, not 400.&lt;/strong&gt; Every block route checks who is signed in before it reads the request. The work, spend and runs routes of plan-build-review, cost-guard and run-console, and plan-build-review's AI SDK agent route, now answer 401 when nobody is signed in.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;audit-data-controls:&lt;/strong&gt; a prepared export downloads only for a signed-in owner (401 signed out, 403 otherwise). Exporting from the page or through the agent is owner-only too; a member sees the control locked with the reason. New exports get random ids (&lt;code&gt;EXP-&lt;/code&gt; and 24 hex digits); existing &lt;code&gt;EXP-001&lt;/code&gt; ids keep working. With Postgres, run the new migration &lt;code&gt;0001_exports_random_id.sql&lt;/code&gt;. If your own &lt;code&gt;AuditDataRepo&lt;/code&gt; assigns ids, make them unguessable (&lt;code&gt;newExportId()&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Races:&lt;/strong&gt; in plan-build-review, run-console and agent-ops-console, a write that lost a race answers 409 with a sentence saying to try again, not a 500. If you catch &lt;code&gt;Refusal&lt;/code&gt; around these stores, these conflicts now reach your handler.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Routes no longer change anything on GET.&lt;/strong&gt; Another site can make a browser send a GET with a plain link or an image, which &lt;code&gt;crossSite()&lt;/code&gt; can't stop. human-handoff: loading the inbox with &lt;code&gt;?visit=1&lt;/code&gt; only reads what changed since your last visit; the page marks it seen with POST &lt;code&gt;{ action: &amp;quot;seen&amp;quot;, at }&lt;/code&gt;, and the store has &lt;code&gt;sinceLastVisit()&lt;/code&gt; and &lt;code&gt;markSeen()&lt;/code&gt; (&lt;code&gt;visit()&lt;/code&gt; still does both). approve-from-anywhere: the run page's GET no longer resumes runs owed a decision; the page sends POST &lt;code&gt;{ action: &amp;quot;carry-on&amp;quot; }&lt;/code&gt; first, which needs someone signed in. If you call these routes yourself, send the POST. Reading an approval no longer records its expiry: an overdue approval reads as expired, and the expiry is recorded by the next decision or by the run page's carry-on POST.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Projects whose alias isn't &lt;code&gt;@&lt;/code&gt;.&lt;/strong&gt; Blocks and templates now install and build in a project whose tsconfig alias isn't &lt;code&gt;@&lt;/code&gt; (for example &lt;code&gt;~/*&lt;/code&gt;). Before, their own files kept &lt;code&gt;@/registry/…&lt;/code&gt; and &lt;code&gt;@/blocks/…&lt;/code&gt; imports there and the app didn't build. Their code now ships as components and libs, so shadcn writes the imports with your aliases, as it does for the kit; in an &lt;code&gt;@/&lt;/code&gt; project nothing changes. If you installed a block in such a project, run &lt;code&gt;npx candor-ui add &amp;lt;block&amp;gt; --overwrite&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Opening comments survive install.&lt;/strong&gt; A comment before a block file's first line of code used to be dropped by shadcn; the opening comment of &lt;code&gt;candor-server.ts&lt;/code&gt; and of five block files now sits below the first line of code and is kept. Run &lt;code&gt;npx candor-ui update&lt;/code&gt; to get them back.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Permission prompts&lt;/strong&gt; in the blocks and templates wait while your answer is sent, so Allow can't be pressed twice, and use a level-2 heading under the page's h1.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Headings&lt;/strong&gt; no longer skip a level on the approvals inbox's request page, the agent ops console's Runs page and the support copilot's Quality page.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Project workspace&lt;/strong&gt; builds in a new Next.js 16 app, where Cache Components is on by default. On a narrow screen the project panel stays closed until you open it; it used to open as a sheet over the thread when the project loaded. In that sheet the Close button no longer covers the last tab.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Server foundation:&lt;/strong&gt; &lt;code&gt;demoSessionRoutes(people, { allowed })&lt;/code&gt; lets your app decide whether the demo sign-in answers, instead of the route reading &lt;code&gt;process.env&lt;/code&gt; on each request. Left out, nothing changes.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.13.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;add --dry-run&lt;/code&gt; no longer run a shadcn preview per item&lt;/strong&gt; and read its printed output. They work out shadcn's files themselves from the registry JSON, components.json and tsconfig paths, so a large add records its lockfile at once. A block whose own files import through &lt;code&gt;@/&lt;/code&gt; is now recorded in candor-lock.json; before, it was left unrecorded. &lt;code&gt;add --path&lt;/code&gt; is recorded where the files went. Projects with &lt;code&gt;tsx: false&lt;/code&gt;, a Tailwind prefix, &lt;code&gt;cssVariables: false&lt;/code&gt;, &lt;code&gt;rtl&lt;/code&gt;, aliases through package.json imports or a workspace package, or an &lt;code&gt;asChild&lt;/code&gt; item on a Base UI style still use shadcn's preview, as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add --dry-run&lt;/code&gt;&lt;/strong&gt; lists each file the install would write (&lt;code&gt;create&lt;/code&gt;, &lt;code&gt;same&lt;/code&gt;, &lt;code&gt;differs&lt;/code&gt;, &lt;code&gt;replace&lt;/code&gt;), no longer runs shadcn, and no longer rewrites components.json for a dry run at another version. It exits 1 where the add itself would stop, and says so, and it lists the whole install. Scripts that relied on the dry run always exiting 0 should check its message.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme check&lt;/code&gt; checks token names and &lt;code&gt;data-slot&lt;/code&gt; selectors.&lt;/strong&gt; It reads the token manifest of the kit candor-lock.json records (the current one, and says so, for a release before 2.8.0). It warns, with file and line, on a &lt;code&gt;--cd-*&lt;/code&gt; name the kit doesn't read (with the nearest name it does, or the shadcn name for a colour), a value outside a token's range, an internal &lt;code&gt;--cd-*&lt;/code&gt; name a brand file shouldn't set, and a &lt;code&gt;[data-slot]&lt;/code&gt; selector no component renders. Warnings don't change the exit code. &lt;code&gt;--json&lt;/code&gt; adds &lt;code&gt;tokens&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;doctor&lt;/code&gt; and &lt;code&gt;@candor-ui/react&lt;/code&gt;.&lt;/strong&gt; With the package installed beside Pro or Premium items, or with a licence key set, &lt;code&gt;doctor&lt;/code&gt; reports a fix and exits 1, listing every import of the package by file and line with the items to add and the import each becomes. Beside free copies only, it stays a note. It notes the package's stylesheet imported beside candor.css, and both of the package's stylesheets at once.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add --dry-run --path &amp;lt;file&amp;gt;&lt;/code&gt; lists the file shadcn actually writes there.&lt;/strong&gt; shadcn installs an item's dependencies first, so a &lt;code&gt;--path&lt;/code&gt; naming a file receives a dependency's file; the CLI follows shadcn's order, so the dry run and the lockfile match what was written. To put a particular file somewhere, give &lt;code&gt;--path&lt;/code&gt; a folder.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The &lt;code&gt;lib&lt;/code&gt; alias.&lt;/strong&gt; &lt;code&gt;init&lt;/code&gt; adds a &lt;code&gt;lib&lt;/code&gt; alias to a components.json that has none, when tsconfig confirms the folder, so shadcn writes Candor's imports of lib files correctly; the README and &lt;code&gt;--help&lt;/code&gt; say so. &lt;code&gt;doctor&lt;/code&gt; names a missing one. The dry run names shadcn's &lt;code&gt;lib/utils.ts&lt;/code&gt; as shadcn's own file.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui info &amp;lt;item&amp;gt;&lt;/code&gt;&lt;/strong&gt; shows the page for the version you have, and says so when that version has no page.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui lint&lt;/code&gt;&lt;/strong&gt; counts an import of &lt;code&gt;CandorProvider&lt;/code&gt; as Candor in use.&lt;/li&gt;&lt;li&gt;An interrupted &lt;code&gt;add&lt;/code&gt; or &lt;code&gt;init&lt;/code&gt; also stops processes shadcn starts after the signal (macOS and Linux). With an unreadable candor-lock.json, &lt;code&gt;mcp&lt;/code&gt; and &lt;code&gt;init --mcp&lt;/code&gt; say why the MCP URL has no &lt;code&gt;?kit=&lt;/code&gt; version, and &lt;code&gt;doctor&lt;/code&gt; says the entries' version can't be checked. On Windows, every argument passed to shadcn is quoted where cmd.exe needs it. &lt;code&gt;theme watch&lt;/code&gt; sees a file saved while a check is running.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Give this to your agent.&lt;/strong&gt; Get started has a prompt to copy to your coding agent for adopting Candor into an app you already have. It asks about your stack and your agent's API before it writes code, installs with the CLI, leaves the licence key to you, and wraps the app in LocaleProvider, TermsProvider, EntityKindsProvider and AgentRolesProvider. It is also in llms.txt and at /adopt.md, and the docs MCP's &lt;code&gt;get_started&lt;/code&gt; returns it with &lt;code&gt;{ &amp;quot;prompt&amp;quot;: true }&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Versioned docs.&lt;/strong&gt; Every release's docs are kept as published: &lt;code&gt;/r/v/&amp;lt;version&amp;gt;/docs/&amp;lt;name&amp;gt;.md&lt;/code&gt;, plus the patterns, screens, Get started and &lt;code&gt;llms.txt&lt;/code&gt; at the same paths under &lt;code&gt;/r/v/&amp;lt;version&amp;gt;/&lt;/code&gt;. Pages go back to 1.3.0; 1.0.0 to 1.2.1 published only llms.txt. Each docs page lists the releases that have it. &lt;code&gt;/docs/versions.json&lt;/code&gt; says which releases kept what.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;version&lt;/code&gt; on the MCP's page tools.&lt;/strong&gt; &lt;code&gt;get_component_docs&lt;/code&gt;, &lt;code&gt;get_brief&lt;/code&gt;, &lt;code&gt;get_pattern&lt;/code&gt;, &lt;code&gt;get_screen&lt;/code&gt;, &lt;code&gt;get_started&lt;/code&gt;, &lt;code&gt;get_design&lt;/code&gt; and &lt;code&gt;get_review_checklist&lt;/code&gt; take &lt;code&gt;version&lt;/code&gt;, and default to the version in the server's URL (&lt;code&gt;?kit=&lt;/code&gt;, which &lt;code&gt;npx candor-ui mcp&lt;/code&gt; writes from candor-lock.json). Run &lt;code&gt;npx candor-ui mcp&lt;/code&gt; again after &lt;code&gt;update&lt;/code&gt; so the URL follows the lockfile. A release without the page answers with the current page and a note saying so.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme_check&lt;/code&gt;&lt;/strong&gt; also checks token names and &lt;code&gt;data-slot&lt;/code&gt; selectors against the kit's token manifest, as &lt;code&gt;candor-ui theme check&lt;/code&gt; does. The warnings don't fail the check. The summary has the token lines, and the JSON gains &lt;code&gt;tokens&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;suggest_components&lt;/code&gt;&lt;/strong&gt; reads &amp;quot;login page&amp;quot; as sign-in and &amp;quot;modal&amp;quot; or &amp;quot;pop-up&amp;quot; as a dialog. A word no item uses is taken as your app's own noun rather than counting against the task. &amp;quot;sign in&amp;quot; gives Sign in alone; &amp;quot;error page 404&amp;quot; gives PageState; &amp;quot;settings modal&amp;quot; starts with SettingsLayout; a credit card form no longer lists every card component.&lt;/li&gt;&lt;li&gt;The sign-in screen's brief names &lt;code&gt;SessionExpiredDialog&lt;/code&gt;. A docs page's &amp;quot;Terms used here&amp;quot; links the glossary once and doesn't list the page's own term. The docs say how to add a &lt;code&gt;&amp;quot;lib&amp;quot;&lt;/code&gt; alias to components.json.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Tokens and theming&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The token manifest.&lt;/strong&gt; Candor's tokens are published as data at &lt;code&gt;/r/tokens-manifest.json&lt;/code&gt;, and from 2.8.0 at &lt;code&gt;/r/v/&amp;lt;version&amp;gt;/tokens-manifest.json&lt;/code&gt; for each release: every token's name, layer, type, range, default per mode and density, the &lt;code&gt;data-slot&lt;/code&gt; names the components render, and the &lt;code&gt;--cd-*&lt;/code&gt; names that are internal. No licence key is needed. A release from before 2.8.0 answers 404 with a sentence saying they start at 2.8.0. Tools and agents that check a brand file can read it instead of guessing. Nothing changes in your CSS. &lt;code&gt;--cd-toast-offset&lt;/code&gt;, which Toaster reads, is in it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Theme builder:&lt;/strong&gt; below 768 px, a panel or a component's settings opens as a sheet along the bottom with the canvas visible above it, so an edit shows as you make it. Drag its grip between a low peek and about half the screen, press it to switch between the two, or use the arrow keys, Home and End. The height is kept in your browser.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Theme builder:&lt;/strong&gt; a View control beside the canvas tabs shows your theme as forced colours (Windows contrast themes) would draw it, in a dark or a light scheme. It is labelled as a simulation and lists where it differs from the real mode. With your browser already in forced colours, the canvas shows the real thing and the control says so.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Theme builder:&lt;/strong&gt; /theme-builder downloads about half the script it did (566 → 354 KB gzipped). It reads the kit's tokens from the token manifest.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Each page downloads only its own code.&lt;/strong&gt; The licence and other legal pages load about 234 KB of compressed script instead of about 1.4 MB, and no page fetches the rest of the site while you read it. /docs, /patterns and /screens load about 170 to 220 KB instead of 410 to 505 KB: they read a small list of items and tiers, and only an item's own docs page loads the full catalogue. A link's page is fetched when you point at it, focus it or touch it. A page still loading says so, and one that can't be downloaded says so and offers a reload. A page whose CSS fails to load says &amp;quot;This page didn't load&amp;quot; and offers a reload, instead of going blank.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Try each Premium template before you buy.&lt;/strong&gt; The approvals inbox, agent ops console, support copilot and project workspace run on the site with sample data at /approvals-inbox, /agent-ops-console, /support-copilot and /project-workspace, listed at /templates (in the Build menu). Each is the template's own pages and API route files running in your browser on its in-memory store, signing in and out through the template's own session route. A bar says so, and says what a real install adds: the routes on your server, your sign-in, Postgres and the agent with your model key. No agent runs, so each demo's chat is locked and says why. What you change lasts until you reload. The demos set no cookies. A link to a page inside a demo (for example /approvals-inbox/requests/CR-001) opens that page. The Pro and Premium pricing cards link to their demos (/app and /templates). The site doesn't ship the templates' database code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Checked at 400% zoom and in the accessibility tree&lt;/strong&gt;, in Chromium: /app's demo bar wraps and its Demo states menu no longer covers the composer; commands in the site's copy fields wrap; docs item names wrap; the header stops following the scroll on short screens; numbered headings, Get started's steps among them, read as &amp;quot;01: …&amp;quot;; the home page's component list is a single list for screen readers; the header's Build menu says it holds the current page (&lt;code&gt;aria-current=&amp;quot;true&amp;quot;&lt;/code&gt;). The Accessibility page says what was and wasn't tested: no real screen reader was used.&lt;/li&gt;&lt;li&gt;The home page counts the starters, and says what OrgSmith and Storywrite take from Candor: Methodic makes both, and both use Candor UI's components. Methodic's product is spelled Storywrite.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Registry&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;A missing or corrupt bundled index answers with a sentence instead of an empty 500. Reads of earlier versions' files from Vercel Blob give up after 10 seconds.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;@candor-ui/react 2.8.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The README says what the package is for:&lt;/strong&gt; the trial path, the free tier on npm. Pro and Premium install through the CLI, and Pro items can't import from the package. Moving on means copying in the components you import and removing the package; &lt;code&gt;npx candor-ui doctor&lt;/code&gt; says when a project has both.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A stylesheet without a font:&lt;/strong&gt; &lt;code&gt;@candor-ui/react/styles-no-font.css&lt;/code&gt;, the same theme and tokens as &lt;code&gt;styles.css&lt;/code&gt; without Inter, for apps that bring their own typeface. Import it instead of &lt;code&gt;styles.css&lt;/code&gt; and point &lt;code&gt;--cd-font&lt;/code&gt; (and &lt;code&gt;--cd-font-display&lt;/code&gt;) at your font. &lt;code&gt;styles.css&lt;/code&gt; still loads Inter, so nothing changes for current apps.&lt;/li&gt;&lt;li&gt;The free items' changes above (the thinking time, &lt;code&gt;PermissionPrompt&lt;/code&gt;'s &lt;code&gt;headingLevel&lt;/code&gt;, &lt;code&gt;CopyField&lt;/code&gt;, source chips, &lt;code&gt;LocaleProvider&lt;/code&gt;'s time zones, &lt;code&gt;RelativeTime&lt;/code&gt;) are in this version. The build fails if &lt;code&gt;styles.css&lt;/code&gt; lacks Inter, if a font reaches &lt;code&gt;styles-no-font.css&lt;/code&gt;, or if &lt;code&gt;package.json&lt;/code&gt;'s exports don't match the entries it builds.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For contributors&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Tests mirror the source:&lt;/strong&gt; &lt;code&gt;tests/items/&amp;lt;group&amp;gt;/&amp;lt;name&amp;gt;&lt;/code&gt; for each registry item, and &lt;code&gt;tests/blocks&lt;/code&gt;, &lt;code&gt;tests/templates&lt;/code&gt;, &lt;code&gt;tests/scripts&lt;/code&gt;, &lt;code&gt;tests/api&lt;/code&gt;, &lt;code&gt;tests/site&lt;/code&gt;, &lt;code&gt;tests/repo&lt;/code&gt; and &lt;code&gt;tests/kit&lt;/code&gt; for the rest. To find an item's tests, open the file with its name.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;npm run test:browser&lt;/code&gt;&lt;/strong&gt; measures the CSS promises in Chromium: control heights per density, motion durations per level and under reduced motion, the contrast of every pairing in light, dark and high contrast, RTL on Breadcrumb, Pagination, Switch and Sheet, and a &lt;code&gt;reflow&lt;/code&gt; group for CopyField and source chips at 320 px. It also runs the hosted demos' suite, which &lt;code&gt;npm test&lt;/code&gt; no longer does. CI runs it as its own job, and &lt;code&gt;release:check&lt;/code&gt; runs it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor.css&lt;/code&gt; is generated&lt;/strong&gt; by &lt;code&gt;npm run theme&lt;/code&gt; from &lt;code&gt;src/styles/partials/&lt;/code&gt;, its token values from &lt;code&gt;src/styles/tokens.json&lt;/code&gt;. Edit those and run &lt;code&gt;npm run theme&lt;/code&gt;, never &lt;code&gt;candor.css&lt;/code&gt;. Its header says rows step 8 px per density. CI checks that every file &lt;code&gt;npm run theme&lt;/code&gt; writes is current, &lt;code&gt;candor.css&lt;/code&gt; and the tokens manifest included; a version bump leaves the manifest stale until &lt;code&gt;npm run theme&lt;/code&gt; runs (RELEASING step 5). &lt;code&gt;npm run registry&lt;/code&gt; stops when the token manifest is for another version.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The check scripts&lt;/strong&gt; (&lt;code&gt;check:neutral&lt;/code&gt;, &lt;code&gt;check:client&lt;/code&gt;, &lt;code&gt;check:exact&lt;/code&gt;, &lt;code&gt;check:motion&lt;/code&gt;, &lt;code&gt;check:slots&lt;/code&gt;, &lt;code&gt;check:density&lt;/code&gt;, &lt;code&gt;check:layers&lt;/code&gt;) read one TypeScript parse of each source, cached in &lt;code&gt;node_modules/.cache/candor&lt;/code&gt;, instead of regular expressions. The findings on the tree are the same. They no longer count words in comments, prose or code samples as code. They now catch side-effect imports, &lt;code&gt;export * as&lt;/code&gt; and &lt;code&gt;import()&lt;/code&gt; in the layer check; &lt;code&gt;window?.&lt;/code&gt; and functions passed as props in the client check; and classes inside a template's &lt;code&gt;${…}&lt;/code&gt; and &lt;code&gt;.animate?.()&lt;/code&gt; in the motion check. check:neutral gives the line of each product word and says where it sits. &lt;code&gt;CANDOR_AST_CACHE=0&lt;/code&gt; runs without the cache.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The registry build&lt;/strong&gt; reads each item's dependencies from the parsed source, so side-effect imports, &lt;code&gt;export * as&lt;/code&gt; and &lt;code&gt;import()&lt;/code&gt; are declared, and it refuses &lt;code&gt;export … from &amp;quot;@/…&amp;quot;&lt;/code&gt;, &lt;code&gt;import(&amp;quot;@/…&amp;quot;)&lt;/code&gt; and &lt;code&gt;import x = require(&amp;quot;@/…&amp;quot;)&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;npm run docs&lt;/code&gt;&lt;/strong&gt; also writes &lt;code&gt;src/docs/item-index.json&lt;/code&gt; and &lt;code&gt;src/site/theme-builder/catalogue.json&lt;/code&gt;; commit them with &lt;code&gt;api.json&lt;/code&gt;. CI and the release check fail when either is stale. &lt;code&gt;src/site/stats.json&lt;/code&gt; gains &lt;code&gt;starters&lt;/code&gt;, and the README's starter count is checked against it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Release check and CI:&lt;/strong&gt; &lt;code&gt;npm run release:check&lt;/code&gt; fails if any file under &lt;code&gt;snapshots/&lt;/code&gt; is untracked, and checks &lt;code&gt;candor.css&lt;/code&gt; and the tokens manifest. CI's agents check also covers &lt;code&gt;snapshots/&lt;/code&gt;, and its workflow token is read-only. The overflow check measures /templates and each demo's base. &lt;code&gt;snapshot-registry.mjs --ref&lt;/code&gt; refuses a release already in the store.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The fresh-app check&lt;/strong&gt; installs and builds all 50 primitives on Base UI, not two, and builds a Premium block in a &lt;code&gt;~/*&lt;/code&gt; project and in one without &lt;code&gt;lib&lt;/code&gt;/&lt;code&gt;hooks&lt;/code&gt; aliases. The release check builds every block and template, both SDK variants, in a new &lt;code&gt;~/*&lt;/code&gt; Next.js app (&lt;code&gt;fresh-app.mjs --all-premium&lt;/code&gt;) and checks the lockfile records everything installed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;npm run registry&lt;/code&gt;&lt;/strong&gt; writes &lt;code&gt;src/docs/api.json&lt;/code&gt; before the snapshot takes its API record from it, so one run leaves &lt;code&gt;snapshots/r/&amp;lt;version&amp;gt;/api.json&lt;/code&gt; current.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Snapshots:&lt;/strong&gt; a new workflow uploads the snapshot files to Vercel Blob on every push to &lt;code&gt;main&lt;/code&gt; that changes &lt;code&gt;snapshots/&lt;/code&gt;. It needs the repository secret &lt;code&gt;BLOB_READ_WRITE_TOKEN&lt;/code&gt; and fails, saying so, without it; the upload from the release branch before merging stays. &lt;code&gt;scripts/snapshot-upload.mjs&lt;/code&gt; treats a &lt;code&gt;BLOB_READ_WRITE_TOKEN&lt;/code&gt; of &lt;code&gt;[SENSITIVE]&lt;/code&gt; as no token, says so and points at DEPLOY.md. The upload workflow gives the Blob token only to the steps that use it and runs &lt;code&gt;npm ci&lt;/code&gt; without install scripts.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Workflows&lt;/strong&gt; pin their actions to commit SHAs: CI, the snapshot upload, the shadcn canary (whose header now describes what the CLI does since 0.13) and the public repository's starters workflow, which also pins &lt;code&gt;wait-on&lt;/code&gt; to 8.0.5.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Starters:&lt;/strong&gt; &lt;code&gt;sync-starter.mjs --check&lt;/code&gt; also fails when a Candor file copied into a starter was edited by hand, and names the file.&lt;/li&gt;&lt;li&gt;The check scripts run when started through a symlinked folder.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.7.0</title>
      <link>https://candor.themethodic.com/changelog#2-7-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-7-0</guid>
      <pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The product around the agent: forms, lists and tables that carry their own states, a screen catalogue from sign-in to billing, blocks that share one server seam, a registry store built to hold many more releases, and the components an AI-first app reaches for early (a copilot panel, inline suggestions, schedules, keys and webhooks). The kit grows from 280 to 299 items: 70 free, 268 Pro. With CLI 0.12.0 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.7.0. Nothing is removed and no prop is renamed. A few behaviours do change for code you already have, and each is named, with what to do, under &amp;quot;Behaviour that changes&amp;quot; in Components and in Blocks and templates. The deprecations (the blocks' &lt;code&gt;viewerOf&lt;/code&gt;, &lt;code&gt;contextOf&lt;/code&gt; and &lt;code&gt;connect…Db&lt;/code&gt;) are under Blocks and templates.&lt;/p&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;p&gt;New items (all Pro unless marked):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Forms.&lt;/strong&gt; &lt;code&gt;field&lt;/code&gt; wraps one control with its label, hint, error and required mark; pass the form's submit count as &lt;code&gt;attempt&lt;/code&gt; and, after a failed submit, focus moves to the first field with an error. &lt;code&gt;group&lt;/code&gt; renders a fieldset for radios and checkboxes. &lt;code&gt;form-error-summary&lt;/code&gt; lists a form's problems at its top, each a link to its field. &lt;code&gt;number-input&lt;/code&gt; (step buttons that lock at the range and say why, a unit read with the field), &lt;code&gt;time-input&lt;/code&gt; (&amp;quot;HH:MM&amp;quot; with its zone), &lt;code&gt;password-input&lt;/code&gt; (Show or Hide, and a Caps Lock note) and &lt;code&gt;one-time-code&lt;/code&gt; (a row of boxes over one field, so autofill and paste work).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Filtering.&lt;/strong&gt; &lt;code&gt;date-range-picker&lt;/code&gt; offers rolling windows (each printed as its exact window) and a Custom window on two calendars, with &lt;code&gt;useDateRangeText&lt;/code&gt; to word a window in the locale. &lt;code&gt;filter-bar&lt;/code&gt; builds filters from a field, a condition and a value and hands the app &lt;code&gt;FilterRule[]&lt;/code&gt;; &lt;code&gt;useFilterChips&lt;/code&gt; gives the same chips elsewhere.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Chat and work.&lt;/strong&gt; &lt;code&gt;copilot-panel&lt;/code&gt; is an embeddable copilot for an existing product: a launcher with the app's unread count opens a panel that slides in on a wide screen and fills a narrow one, names the agent, says it is an AI system and shows guest or signed in. &lt;code&gt;inline-suggestion&lt;/code&gt; shows an agent's proposed value beside an Input, Textarea or Select, labelled AI-generated, with Accept, Edit and Reject; the field keeps its own value until the person accepts.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Agents and team.&lt;/strong&gt; &lt;code&gt;stop-all&lt;/code&gt; is a workspace-wide &amp;quot;Pause every agent&amp;quot;: it says how many runs are in flight (or that the app hasn't said), asks what happens to them with nothing chosen, and says what can and can't be undone. &lt;code&gt;step-up-dialog&lt;/code&gt; checks it is the person again before a sensitive step, by passkey, a fresh SSO sign-in or a code, each shown only when the app provides it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Admin.&lt;/strong&gt; &lt;code&gt;schedule-editor&lt;/code&gt; creates or edits a recurring job in words, with its time zone and the next five runs (worked out in the browser, and labelled so); a time the clocks skip is flagged, not moved. &lt;code&gt;api-keys&lt;/code&gt; lists keys, their scopes, last use and expiry, shows a new secret once, and says what breaks when a key is revoked. &lt;code&gt;webhooks&lt;/code&gt; lists endpoints, events and recent deliveries; a test send shows its result, adding needs an https address, and removing says what stops. &lt;code&gt;environment-connect&lt;/code&gt; connects an environment by OAuth or credentials with a connection test; &lt;code&gt;requireTest&lt;/code&gt; keeps Connect locked until a test with the current values has passed, and a saved secret is never shown back.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Billing.&lt;/strong&gt; &lt;code&gt;invoice-history&lt;/code&gt; lists invoices in their own currency with status and a download link your app serves. &lt;code&gt;billing-details&lt;/code&gt; is the form for the billing email, name, tax ID (named by the app: &amp;quot;VAT number&amp;quot;, &amp;quot;GSTIN&amp;quot;) and address; it has no card field.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Foundation.&lt;/strong&gt; &lt;code&gt;tokens&lt;/code&gt; (free) and &lt;code&gt;server&lt;/code&gt; (Premium): see Theme and foundation, and Blocks and templates.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Changes to existing items (optional props and widened types; existing code keeps working):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;A &lt;code&gt;state&lt;/code&gt; prop on eighteen lists&lt;/strong&gt; (&lt;code&gt;SessionList&lt;/code&gt;, &lt;code&gt;ApprovalQueue&lt;/code&gt;, &lt;code&gt;NotificationCenter&lt;/code&gt;, &lt;code&gt;RunLog&lt;/code&gt;, &lt;code&gt;AuditLog&lt;/code&gt;, &lt;code&gt;Inbox&lt;/code&gt;, &lt;code&gt;MembersTable&lt;/code&gt;, &lt;code&gt;KnowledgeSources&lt;/code&gt;, &lt;code&gt;ScheduleList&lt;/code&gt;, &lt;code&gt;AgentRoster&lt;/code&gt;, &lt;code&gt;ReviewQueue&lt;/code&gt;, &lt;code&gt;TraceViewer&lt;/code&gt;, &lt;code&gt;ResultTable&lt;/code&gt;, &lt;code&gt;VersionHistory&lt;/code&gt;, &lt;code&gt;EvalScorecard&lt;/code&gt;, &lt;code&gt;FailureClusters&lt;/code&gt;, &lt;code&gt;DeviceSessions&lt;/code&gt;, and &lt;code&gt;SpendBreakdown&lt;/code&gt;, which hands it to its chart), shaped like &lt;code&gt;ChartState&lt;/code&gt;. Loading draws &lt;code&gt;PageSkeleton&lt;/code&gt;, empty and error draw &lt;code&gt;PageState&lt;/code&gt; in the component's own words with the reason underneath, and partial shows the rows under its note. Counts not yet known are not shown. &lt;code&gt;ListState&lt;/code&gt; (lib/data) and &lt;code&gt;ListStateView&lt;/code&gt; (page-state) are the shared shape and renderer, and &lt;code&gt;PageStateKind&lt;/code&gt; gains &lt;code&gt;offline&lt;/code&gt;. Each list's docs example switches between its states.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;DataTable&lt;/code&gt; server mode.&lt;/strong&gt; With &lt;code&gt;onQueryChange&lt;/code&gt;, &lt;code&gt;rows&lt;/code&gt; is the page the server sent and search, sort and page changes come back as one &lt;code&gt;DataTableQuery&lt;/code&gt;; &lt;code&gt;total&lt;/code&gt; gives &amp;quot;Showing 11–20 of 248&amp;quot;, &lt;code&gt;page&lt;/code&gt; controls the page, and &lt;code&gt;state&lt;/code&gt; takes the shared list state. &lt;code&gt;virtualize&lt;/code&gt; shows thousands of in-memory rows in one scrolling body, numbered with &lt;code&gt;aria-rowcount&lt;/code&gt; and &lt;code&gt;aria-rowindex&lt;/code&gt;. Without the new props the table works as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;LogStream&lt;/code&gt; and &lt;code&gt;AuditLog&lt;/code&gt;:&lt;/strong&gt; a search field (&lt;code&gt;LogStream&lt;/code&gt;'s is on by default; &lt;code&gt;searchable&lt;/code&gt; turns it off) that never hides that lines are missing; &lt;code&gt;virtualize&lt;/code&gt;; and in &lt;code&gt;LogStream&lt;/code&gt;, ANSI colour and style codes drawn as text styles on the theme's colours. Every other escape sequence is dropped and nothing is ever HTML.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Bulk selection and export:&lt;/strong&gt; &lt;code&gt;ApprovalQueue&lt;/code&gt; and &lt;code&gt;Inbox&lt;/code&gt; take &lt;code&gt;selectable&lt;/code&gt;, &lt;code&gt;selected&lt;/code&gt;, &lt;code&gt;onSelectedChange&lt;/code&gt; and &lt;code&gt;actions&lt;/code&gt;; nothing starts selected, and approving stays one exact change at a time. &lt;code&gt;DataTable&lt;/code&gt;, &lt;code&gt;AuditLog&lt;/code&gt;, &lt;code&gt;RunLog&lt;/code&gt; and &lt;code&gt;SpendBreakdown&lt;/code&gt; take &lt;code&gt;onExport&lt;/code&gt;; the app writes the file.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;KnowledgeSources&lt;/code&gt;&lt;/strong&gt; takes &lt;code&gt;onRemove&lt;/code&gt; (asks first, names the source, says it can't be undone here) and &lt;code&gt;onCadenceChange&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;AgentRoster&lt;/code&gt;&lt;/strong&gt; takes &lt;code&gt;onToggle&lt;/code&gt; and &lt;code&gt;onCreate&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;MemoryManager&lt;/code&gt;&lt;/strong&gt; gains search, filters and &lt;code&gt;onDeleteMany&lt;/code&gt;, with a confirmation that says how many memories and who taught them. &lt;strong&gt;&lt;code&gt;ScheduleList&lt;/code&gt;&lt;/strong&gt; gains &lt;code&gt;onEdit&lt;/code&gt;, &lt;code&gt;onRunNow&lt;/code&gt; and &lt;code&gt;onDelete&lt;/code&gt; in a per-job menu; delete says what stops.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Combobox&lt;/code&gt;&lt;/strong&gt; gains &lt;code&gt;multiple&lt;/code&gt; (&lt;code&gt;values&lt;/code&gt;, &lt;code&gt;defaultValues&lt;/code&gt;, &lt;code&gt;onValuesChange&lt;/code&gt;) and takes &lt;code&gt;aria-describedby&lt;/code&gt;, &lt;code&gt;aria-invalid&lt;/code&gt; and &lt;code&gt;aria-required&lt;/code&gt;. Single mode is unchanged. In &lt;code&gt;multiple&lt;/code&gt; mode a chosen option is marked with &lt;code&gt;aria-checked&lt;/code&gt; and a &amp;quot;Selected&amp;quot; text, and &lt;code&gt;aria-selected&lt;/code&gt; follows the highlight, as in single mode; the listbox is not &lt;code&gt;aria-multiselectable&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ThreadHeader&lt;/code&gt;&lt;/strong&gt; takes &lt;code&gt;people&lt;/code&gt; beside &lt;code&gt;working&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;SelectionActions&lt;/code&gt;&lt;/strong&gt; takes &lt;code&gt;source&lt;/code&gt;, a ref to the app's own content, and &lt;code&gt;actions&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;MessageActions&lt;/code&gt;&lt;/strong&gt; (free) takes &lt;code&gt;report&lt;/code&gt;, a render function given the report's open state; a bad rating opens it, so the reason is asked once. &lt;strong&gt;&lt;code&gt;ReportReply&lt;/code&gt;&lt;/strong&gt; gains controlled &lt;code&gt;open&lt;/code&gt; and &lt;code&gt;onOpenChange&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;SignIn&lt;/code&gt;&lt;/strong&gt; gains optional &lt;code&gt;providers&lt;/code&gt; (a &amp;quot;Continue with {name}&amp;quot; button each, through &lt;code&gt;onProvider&lt;/code&gt;) and &lt;code&gt;onPasskey&lt;/code&gt;; its code field is now &lt;code&gt;OneTimeCode&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Widened types:&lt;/strong&gt; &lt;code&gt;ThreadHeader&lt;/code&gt;'s &lt;code&gt;working&lt;/code&gt; counts people; &lt;code&gt;PageStateKind&lt;/code&gt; gains &lt;code&gt;offline&lt;/code&gt;; the three money components share &lt;code&gt;formatMoney&lt;/code&gt; (lib/ops), which shows an unknown currency code as the number and the code (&amp;quot;12.5 EURO&amp;quot;) instead of throwing &lt;code&gt;RangeError&lt;/code&gt;, and no longer rounds a fraction away (4.5 JPY reads &amp;quot;¥4.5&amp;quot;).&lt;/li&gt;&lt;li&gt;&lt;code&gt;BarChart&lt;/code&gt;'s value labels get a halo in the card's colour, so a label never sits unreadable on a grid line; &lt;code&gt;Toast&lt;/code&gt;'s title and detail take &lt;code&gt;dir=&amp;quot;auto&amp;quot;&lt;/code&gt;, so an identifier in a right-to-left page isn't scrambled; &lt;code&gt;KpiRow&lt;/code&gt; lays out by its own width (a container query) instead of the window's; &lt;code&gt;NotificationCenter&lt;/code&gt;'s popover is named.&lt;/li&gt;&lt;li&gt;Selected states survive forced colours: see Theme and foundation.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Behaviour that changes (these are not additive; check them when you update):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Search is on by default&lt;/strong&gt; in &lt;code&gt;LogStream&lt;/code&gt;, &lt;code&gt;AuditLog&lt;/code&gt; and &lt;code&gt;MemoryManager&lt;/code&gt;. A page that used one of them now shows a search field. To keep the old look, pass &lt;code&gt;searchable={false}&lt;/code&gt;. &lt;code&gt;MemoryManager&lt;/code&gt; also shows scope and origin filters whenever the memories are mixed, and has no prop to turn those off.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;LogStream&lt;/code&gt; draws ANSI colour and style codes as text styles.&lt;/strong&gt; &lt;code&gt;&amp;quot;x\u001b[31mred&amp;quot;&lt;/code&gt; showed the raw characters before and now shows &amp;quot;x&amp;quot; and &amp;quot;red&amp;quot; in the theme's red. It is still text, never HTML. If your logs held literal escape sequences you wanted to see, they are no longer shown.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;formatMoney&lt;/code&gt; keeps every decimal it is given.&lt;/strong&gt; &lt;code&gt;$1.005&lt;/code&gt; no longer rounds to &lt;code&gt;$1.01&lt;/code&gt;, and &lt;code&gt;¥4.5&lt;/code&gt; shows as &lt;code&gt;¥4.5&lt;/code&gt; where it showed &lt;code&gt;¥5&lt;/code&gt;, so a zero-decimal currency (yen, won) can now show a fraction. Round the amount in your app if you want whole units. An unknown currency code shows as the number and the code (&amp;quot;12.5 EURO&amp;quot;) where it threw.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;SignIn&lt;/code&gt;'s code field is now &lt;code&gt;OneTimeCode&lt;/code&gt;&lt;/strong&gt; (six boxes), and &lt;code&gt;sign-in&lt;/code&gt; depends on &lt;code&gt;one-time-code&lt;/code&gt;. Update with &lt;code&gt;npx candor-ui update sign-in&lt;/code&gt; to get the new file and its dependency; a &lt;code&gt;SignIn&lt;/code&gt; you edited merges as usual.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PageStateKind&lt;/code&gt; gains &lt;code&gt;&amp;quot;offline&amp;quot;&lt;/code&gt;.&lt;/strong&gt; A &lt;code&gt;switch&lt;/code&gt; over it that returns for every case, or a &lt;code&gt;Record&amp;lt;PageStateKind, …&amp;gt;&lt;/code&gt;, no longer type-checks: add a case for &lt;code&gt;&amp;quot;offline&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Smaller DOM changes.&lt;/strong&gt; &lt;code&gt;ApprovalQueue&lt;/code&gt; and &lt;code&gt;Inbox&lt;/code&gt; rows gain a wrapper &lt;code&gt;div&lt;/code&gt; even without &lt;code&gt;selectable&lt;/code&gt;, so a selector such as &lt;code&gt;li &amp;gt; button&lt;/code&gt; stops matching (use &lt;code&gt;li button&lt;/code&gt;). &lt;code&gt;AgentRoster&lt;/code&gt; with no agents renders a &lt;code&gt;div&lt;/code&gt; holding the &lt;code&gt;p&lt;/code&gt;. &lt;code&gt;ScheduleList&lt;/code&gt;'s history strip has &lt;code&gt;role=&amp;quot;img&amp;quot;&lt;/code&gt;. &lt;code&gt;DataTable&lt;/code&gt;'s header wraps Export and Columns in a &lt;code&gt;div&lt;/code&gt;. &lt;code&gt;NotificationCenter&lt;/code&gt;'s popover has an &lt;code&gt;aria-label&lt;/code&gt;. The Toaster's text has &lt;code&gt;dir=&amp;quot;auto&amp;quot;&lt;/code&gt;. &lt;code&gt;KpiRow&lt;/code&gt; is wrapped in a container-query element, and its breakpoints follow its own width, not the window's.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;KpiRow&lt;/code&gt;'s columns follow its container's width.&lt;/strong&gt; A window breakpoint class you passed, such as &lt;code&gt;lg:grid-cols-3&lt;/code&gt;, no longer overrides them. Use a container variant instead, such as &lt;code&gt;@3xl:grid-cols-3&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Theme and foundation&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;tokens&lt;/code&gt;, a new free item.&lt;/strong&gt; Before, an item installed with plain shadcn (or shadcn's MCP) used classes such as &lt;code&gt;cd-press&lt;/code&gt;, &lt;code&gt;rounded-button&lt;/code&gt; and &lt;code&gt;h-(--cd-control-h-sm)&lt;/code&gt; that generated nothing, with no error, because only the four gallery themes listed &lt;code&gt;@candor/theme&lt;/code&gt;. &lt;code&gt;tokens&lt;/code&gt; is &lt;code&gt;styles/candor-tokens.css&lt;/code&gt;: Candor's &lt;code&gt;--cd-*&lt;/code&gt; variables, &lt;code&gt;@theme&lt;/code&gt; mapping, keyframes and motion utilities without its colours or dark variant, so a shadcn project keeps its own. It sets only Candor's &lt;code&gt;--cd-*&lt;/code&gt; variables and utilities, and leaves a shadcn project's own radius, colours, sidebar and type scale alone. Every code item and block now depends on it; &lt;code&gt;theme&lt;/code&gt; depends on it too and keeps its files. It is free because free items depend on it. &lt;code&gt;candor.css&lt;/code&gt; is unchanged and stays the one import a Candor project uses. What to do: on your next &lt;code&gt;add&lt;/code&gt; you get one new, unimported file; nothing you import changes.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A content-addressed snapshot store.&lt;/strong&gt; Every release used to copy every item into &lt;code&gt;snapshots/r/&amp;lt;version&amp;gt;/&lt;/code&gt; (6,299 files, 127 MB over 26 versions), all bundled into the registry function, heading for Vercel's 250 MB limit. Each distinct file is now kept once in &lt;code&gt;snapshots/blobs/&amp;lt;sha256&amp;gt;.json&lt;/code&gt; and each version has an &lt;code&gt;index.json&lt;/code&gt; mapping item name to hash, type and the tier it was sold in (29 MB in all). A released version's index can't change, so a release stays exactly as sold; the 26 existing versions were migrated and read back byte for byte. The registry function bundles only indexes and manifests; an earlier version's paid file is read from a private Vercel Blob store by hash, with the licence check unchanged and every file checked against its hash. If none can be read the route answers 503 in a sentence. URLs (&lt;code&gt;/r/v/&amp;lt;version&amp;gt;/&amp;lt;name&amp;gt;.json&lt;/code&gt;) are unchanged. Nothing to do as a consumer. The owner's steps for the Blob store and &lt;code&gt;BLOB_READ_WRITE_TOKEN&lt;/code&gt; are in &lt;code&gt;docs/DEPLOY.md&lt;/code&gt; and &lt;code&gt;docs/RELEASING.md&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;npm run check:layers&lt;/code&gt;&lt;/strong&gt; keeps &lt;code&gt;src/registry&lt;/code&gt; imports flowing down: foundation (&lt;code&gt;lib/&lt;/code&gt;, and the &lt;code&gt;locale&lt;/code&gt;, &lt;code&gt;terms&lt;/code&gt; and &lt;code&gt;locked&lt;/code&gt; providers), ui, blocks, domain. It fails on an upward import that isn't in the baseline; one is known (&lt;code&gt;locked&lt;/code&gt; imports &lt;code&gt;ui/tooltip&lt;/code&gt;). The folders themselves are renamed in 2.8.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Forced colours.&lt;/strong&gt; Windows high contrast drops backgrounds and shadows, which is how most selected states were drawn. A section at the end of &lt;code&gt;candor.css&lt;/code&gt; now marks selected rows, options, tree and command items, the chosen tab or segment, the current page and a pressed toggle or chip with an inset outline in the system's Highlight colour, using only system colour keywords. Checkboxes, radios and switches are drawn the way the system draws them.&lt;/li&gt;&lt;li&gt;A per-version API record, &lt;code&gt;snapshots/r/&amp;lt;version&amp;gt;/api.json&lt;/code&gt;, is written from 2.7.0: see the docs MCP below.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Six screens&lt;/strong&gt; join the catalogue, which now has 28: sign-in and first run, account settings, billing and usage, import data, reports and dashboards, document review.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A types section.&lt;/strong&gt; A component's page, its Markdown and so &lt;code&gt;get_component_docs&lt;/code&gt; name the shared types its props take and show them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A glossary&lt;/strong&gt; (&lt;code&gt;glossary.md&lt;/code&gt;: two-turn rule, blast radius, drift, change hash, calm level, the honesty rules), with a &amp;quot;Terms used here&amp;quot; section on the pages that use the words.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Examples&lt;/strong&gt; for &lt;code&gt;standard-cards&lt;/code&gt;, the Salesforce preset and the seven adapters.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Twenty-one patterns, eight of them new:&lt;/strong&gt; Forms and validation (a server action with zod, and the same form with react-hook-form; patterns can now carry code), Payments and invoices (card entry goes to the provider's hosted checkout, never to the app or Candor), Sign in with an identity provider, Code editor embedding, PDF rendering, Offline, Task board, and In-app help.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;item_changes(item, from, to)&lt;/code&gt;&lt;/strong&gt;, the docs MCP's thirteenth tool: props added, removed or retyped, exports and string keys, and files touched between two released versions, then the CHANGELOG entries that name the item. A version before 2.7.0 has no API record, so the start of such a range is said to be unknown and what is known from the first recorded release is labelled as part of it. &lt;code&gt;/r/v/&amp;lt;version&amp;gt;/api.json&lt;/code&gt; serves each record publicly (names, types and hashes, no source). With &lt;code&gt;?kit=&amp;lt;version&amp;gt;&lt;/code&gt; on the server's URL, &lt;code&gt;from&lt;/code&gt; defaults to your kit version.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;suggest_components&lt;/code&gt;:&lt;/strong&gt; a word for a screen's shape (dialog, page, table) counts for less than the word for its job, and a primitive that covers part of a task counts for half, so &amp;quot;approval dialog&amp;quot; finds the approval items and &lt;code&gt;permission-prompt&lt;/code&gt;; the &amp;quot;gap&amp;quot; rules fire on a form's fields, a validation error or a map of places and no longer on &amp;quot;validate the change hash&amp;quot;; it no longer says Candor has no form field item; a whitespace-only task is refused as empty and one in another script is called unreadable; &lt;code&gt;list_components&lt;/code&gt;' group counts add up to the number it says, and it says the &lt;code&gt;-claude&lt;/code&gt; versions are the difference; the Premium install label says not to ask for the key, as the Pro one does. The evaluation set grows from fourteen to twenty tasks with expected answers and runs in CI; &amp;quot;document&amp;quot; finds the artifact panel.&lt;/li&gt;&lt;li&gt;&lt;code&gt;llms.txt&lt;/code&gt;'s Setup guides line reads its tool list from the guides, and the install command and tool list come from one source across the README, &lt;code&gt;llms-install.md&lt;/code&gt; and both npm READMEs.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.12.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui theme watch [file]&lt;/code&gt;&lt;/strong&gt; runs &lt;code&gt;theme check&lt;/code&gt; now and whenever a file it reads changes (the CSS and its imports, &lt;code&gt;candor-brand.css&lt;/code&gt;, the installed theme and motion manifest, &lt;code&gt;components.json&lt;/code&gt;, &lt;code&gt;candor-lock.json&lt;/code&gt;), until Ctrl-C (exit 130). &lt;code&gt;--json&lt;/code&gt; prints one report per run. An unreadable &lt;code&gt;components.json&lt;/code&gt; (half-written, say) is reported and watching goes on.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;add --dry-run&lt;/code&gt; shows what &lt;code&gt;--replace-edits&lt;/code&gt; would change&lt;/strong&gt;: per edited file, your edits (&lt;code&gt;&amp;lt;&lt;/code&gt;), the old lines (&lt;code&gt;-&lt;/code&gt;) and the new (&lt;code&gt;+&lt;/code&gt;), and what &lt;code&gt;update&lt;/code&gt; would do instead. It writes nothing and exits 0. &lt;code&gt;add --dry-run&lt;/code&gt;, &lt;code&gt;--diff&lt;/code&gt; and &lt;code&gt;--view&lt;/code&gt; are previews: they record nothing and exit 0.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;mcp&lt;/code&gt; and &lt;code&gt;doctor&lt;/code&gt; pass your kit version.&lt;/strong&gt; With a lockfile, &lt;code&gt;candor-ui mcp &amp;lt;tool&amp;gt;&lt;/code&gt; writes the server URL with &lt;code&gt;?kit=&amp;lt;version&amp;gt;&lt;/code&gt;; running it again after the lockfile moves updates that entry only. &lt;code&gt;doctor&lt;/code&gt; says when an entry passes another version or none, and the command that fixes it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Signals.&lt;/strong&gt; The grace period now stops the whole shadcn tree, not only &lt;code&gt;npx&lt;/code&gt;: it signals the processes under npx, waits, and after 10 s kills any still running (&lt;code&gt;taskkill /T&lt;/code&gt; and &lt;code&gt;/T /F&lt;/code&gt; on Windows). Before, a shadcn that ignored the signal kept writing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;init&lt;/code&gt; with a lockfile it can't read&lt;/strong&gt; no longer stops: it says so, sets up the registry, the CSS import and the font settings, installs nothing, and exits 1 only if the theme still needs installing. The file is left as it is, and &lt;code&gt;doctor&lt;/code&gt; reports it with &lt;code&gt;git diff&lt;/code&gt; and &lt;code&gt;git checkout&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt; lists shared items and packages even with no lockfile (it reads the newest release's items and names the version); &lt;code&gt;init --latest&lt;/code&gt; installs a missing font at the recorded theme's version; &lt;code&gt;CANDOR_SHADCN=^4.24.0&lt;/code&gt; keeps its caret on Windows; the &lt;code&gt;CANDOR_SHADCN&lt;/code&gt; hint appears only when shadcn printed output the CLI couldn't read and the value can run a shadcn outside the pinned range.&lt;/li&gt;&lt;li&gt;Wording: &amp;quot;a, b (1.0.0) and c, d (2.0.0) to T&amp;quot; replaces &amp;quot;a and b (1.0.0) and c and d (2.0.0) to T&amp;quot;, and the Base UI note reads &amp;quot;Candor's button would go where your Base UI components/ui/button.tsx is&amp;quot;. The primitive and lint lists name the new items.&lt;/li&gt;&lt;li&gt;New CLI tests cover a real kill on the built CLI (SIGTERM, SIGHUP), the runner's environment, a hoisted &lt;code&gt;@candor-ui/react&lt;/code&gt;, and an explicit 401 from a versioned snapshot.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks and templates (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The &lt;code&gt;server&lt;/code&gt; foundation.&lt;/strong&gt; Every block and template used to carry its own identity stub (14 &lt;code&gt;viewerOf&lt;/code&gt; copies) and its own database pool (15 &lt;code&gt;db/connect.ts&lt;/code&gt; files), so four blocks opened four pools and replaced the stub four times. The new &lt;code&gt;server&lt;/code&gt; item (Premium, so installing it needs a Premium or Team key; &lt;code&gt;lib/candor-server.ts&lt;/code&gt;, &lt;code&gt;lib/candor-database.ts&lt;/code&gt;) is the one place: &lt;code&gt;getViewer(request)&lt;/code&gt; and &lt;code&gt;setViewerSource()&lt;/code&gt; for your auth, &lt;code&gt;signedOut()&lt;/code&gt; (a 401), &lt;code&gt;database()&lt;/code&gt; and &lt;code&gt;setDatabase()&lt;/code&gt; (one pool per server process), &lt;code&gt;Refusal&lt;/code&gt; with a status, and the agent's runtime settings (&lt;code&gt;agentModel&lt;/code&gt;, &lt;code&gt;claudeQueryOptions&lt;/code&gt;, &lt;code&gt;approvalSigning()&lt;/code&gt;). Each block keeps its own schema, store, repo and migrations.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Behaviour that changes&lt;/strong&gt; (not additive; what to do is with each): - The demo sign-in is off in production (&lt;code&gt;NODE_ENV=production&lt;/code&gt;) unless &lt;code&gt;CANDOR_DEMO_AUTH=1&lt;/code&gt; is set or the app registers its own &lt;code&gt;setViewerSource()&lt;/code&gt;. With neither, nobody is signed in and every route answers 401. Before real use, call &lt;code&gt;setViewerSource()&lt;/code&gt; with your auth; to keep the demo on a deployed preview, set &lt;code&gt;CANDOR_DEMO_AUTH=1&lt;/code&gt;. - A route now answers 401 when the demo cookie is present but empty. In 2.6 an empty cookie meant the demo person (Riley). It now signs the person out. If you relied on an empty cookie to get the demo person, set a real demo value. &lt;code&gt;Refusal&lt;/code&gt; carries a &lt;code&gt;status&lt;/code&gt;, 409 unless you give one. - A block's &lt;code&gt;db/connect.ts&lt;/code&gt; you customised keeps working only if you register your driver with &lt;code&gt;setDatabase()&lt;/code&gt;. The shim calls the foundation's pool otherwise, so an edit that opened its own pool is not used until you do.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Deprecated, removed in 3.0:&lt;/strong&gt; &lt;code&gt;contextOf(request)&lt;/code&gt; in &lt;code&gt;audit-data-controls/store.ts&lt;/code&gt; and &lt;code&gt;approvals-inbox/store.ts&lt;/code&gt; stays synchronous and returns &lt;code&gt;Ctx&lt;/code&gt; as in 2.6, reading the demo cookie only. Routes use the new async &lt;code&gt;signedInContext(request)&lt;/code&gt;, which asks &lt;code&gt;getViewer()&lt;/code&gt; and returns &lt;code&gt;Ctx | null&lt;/code&gt; (null when nobody is signed in); move your calls to it, await it and check for null. Also &lt;code&gt;viewerOf(request)&lt;/code&gt; in each block's &lt;code&gt;store.ts&lt;/code&gt; and &lt;code&gt;connect…Db(url)&lt;/code&gt; in &lt;code&gt;db/connect.ts&lt;/code&gt;. They are back as thin shims so a block you edited still compiles and &lt;code&gt;update&lt;/code&gt; doesn't delete them. &lt;code&gt;viewerOf&lt;/code&gt; answers as in 2.6 and reads the demo cookie only, not &lt;code&gt;setViewerSource()&lt;/code&gt;'s source; &lt;code&gt;connect…Db&lt;/code&gt; returns the shared pool for &lt;code&gt;DATABASE_URL&lt;/code&gt; and a pool of its own for any other URL. What to do: if you replaced &lt;code&gt;viewerOf&lt;/code&gt; with your auth, call &lt;code&gt;setViewerSource()&lt;/code&gt; in &lt;code&gt;candor-server.ts&lt;/code&gt; instead and move your calls to &lt;code&gt;getViewer&lt;/code&gt;; if you edited &lt;code&gt;db/connect.ts&lt;/code&gt;, keep your edit or move to &lt;code&gt;database()&lt;/code&gt;. &lt;code&gt;update&lt;/code&gt; merges both.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The templates sign in&lt;/strong&gt; through a documented seam: each has a sign-in page (the kit's &lt;code&gt;SignIn&lt;/code&gt; through the foundation's &lt;code&gt;DemoSignIn&lt;/code&gt;) and a demo session route. The demo says it sends no email and which code to type. A 401 from any route goes to the sign-in page, and Sign out ends the session. To use your own auth, delete the session route and the sign-in page and call &lt;code&gt;setViewerSource()&lt;/code&gt;; nothing else changes. The approvals inbox's words are a strings table (&lt;code&gt;approvalsInboxStrings&lt;/code&gt;, overridable under &lt;code&gt;approvalsInbox&lt;/code&gt; in &lt;code&gt;LocaleProvider&lt;/code&gt;), and the shells show a skeleton, not a &amp;quot;Loading…&amp;quot; person, until the server says who is signed in.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PermissionPrompt&lt;/code&gt; in the chat views.&lt;/strong&gt; The 14 chat views (10 blocks, 3 templates and the Next.js starter) use &lt;code&gt;PermissionPrompt&lt;/code&gt; in place of a hand-rolled &amp;quot;Waiting for your go-ahead&amp;quot; banner; &lt;code&gt;eval-dashboard&lt;/code&gt; uses &lt;code&gt;Select&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;meta.framework&lt;/code&gt;.&lt;/strong&gt; Each block records &lt;code&gt;&amp;quot;framework&amp;quot;: &amp;quot;next-app&amp;quot;&lt;/code&gt; (the App Router) and the build refuses a block without one; it is carried into every block and template item's &lt;code&gt;meta.framework&lt;/code&gt;. Nothing reads it yet: the CLI does not yet warn before installing into another framework.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Candor and a free kit&lt;/strong&gt; (&lt;code&gt;/compare&lt;/code&gt;): what AI Elements, assistant-ui and CopilotKit say they ship, read from their own pages on 9 November 2026, each with the address it was read at; it names no winner. Linked from the hero and footer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;What you can check&lt;/strong&gt;, on the home page: npm weekly downloads read when the site is built (with the day, and left out if npm gave none), the public repository and the release cadence. No customer counts, quotes or logos. Three Honest vs. typical toggles sit under &amp;quot;More than a chat box&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A Build menu&lt;/strong&gt; in the header holds Examples, Patterns, Screens, Guides and the Theme builder.&lt;/li&gt;&lt;li&gt;A docs Preview shows a skeleton and a status while its example loads; &lt;code&gt;/app&lt;/code&gt; has a skip link and its Demo states button sits in a landmark; the Methodic line leads with what Methodic ships on Candor; the accessibility page and the upgrade FAQ read their numbers from &lt;code&gt;stats.json&lt;/code&gt; and the prices.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The overflow check&lt;/strong&gt; sees clipped content, measures the 14 key pages at 320, 360 and 768 px and with the header menu open (444 loads), can fail (&lt;code&gt;--self-test&lt;/code&gt;), and runs at a pinned Playwright. Its first run found &lt;code&gt;/docs&lt;/code&gt; 18 px too wide at 320 px; fixed.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The theme builder (free tool)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;From my brand&lt;/strong&gt; is first in Start and previewed live: the canvas shows the mapped colours until you Apply, and each colour's role is a choice (Primary, Accent, Greys, Page, Ink, each status or Not used), with &amp;quot;You get&amp;quot; beside it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Primary&lt;/strong&gt; sets the theme's primary whichever theme the page shows; a dark-only primary is behind &amp;quot;Override the primary in Dark only&amp;quot;. &lt;strong&gt;Derive from this primary&lt;/strong&gt; brings hand-set colours around the primary back into line, as one undoable step. Hex, &lt;code&gt;rgb()&lt;/code&gt; and &lt;code&gt;hsl()&lt;/code&gt; colours in a hand-edited file are read and converted to &lt;code&gt;oklch()&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A line you add by hand survives the next download:&lt;/strong&gt; a declaration the builder can't set is kept as written and written again under &amp;quot;Kept as written&amp;quot;, listed in Download with Remove.&lt;/li&gt;&lt;li&gt;The load report separates &amp;quot;You changed&amp;quot; from &amp;quot;Follows from it&amp;quot;. The library lists the open theme first, each with its primary. Check says when Running and Failed are hard to tell apart (OKLab distance below 0.12). The Download summary says Motion and Type in words. Your agent's name and place noun reach Approvals, Dashboards and the Brand sample.&lt;/li&gt;&lt;li&gt;Undo and redo history now survives a reload whatever order the values were set in, and Undo takes down the note that spoke for the step. Chosen options and swatches show in forced colours. Stat cards fit their column on Dashboards, one press in the Toast preview shows one toast, and a tall toast stack no longer clips. A full axe pass runs at 1440 and 390.&lt;/li&gt;&lt;li&gt;Fixed after review: moving Primary to another colour in the brand mapping swaps the two roles instead of dropping a colour; a hand-edited file's primary derives its dark and high-contrast colours, where Candor's blue stayed around it; a hex shown as typed is the hex you gave, not the rounded colour's; after Apply, focus moves to &amp;quot;Change the mapping&amp;quot;, not the page body; and the brand sample names the colours set in Components that the theme's roles don't drive.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Build and checks&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The release check runs &lt;code&gt;check:layers&lt;/code&gt;, &lt;code&gt;doc-facts --check&lt;/code&gt; and the overflow script's &lt;code&gt;--self-test&lt;/code&gt;; from the dated CHANGELOG section it also runs &lt;code&gt;sync-starter --check&lt;/code&gt; (the starters must not be behind the source). It checks the snapshot store and &lt;code&gt;candor-tokens.css&lt;/code&gt; with &lt;code&gt;git status&lt;/code&gt;, so new files count, and ignores Finder's untracked &amp;quot; 2&amp;quot; copies.&lt;/li&gt;&lt;li&gt;&lt;code&gt;sync-starter&lt;/code&gt; writes &lt;code&gt;.candor-sync.json&lt;/code&gt; (kept out of the public starters); &lt;code&gt;public-repo&lt;/code&gt;, &lt;code&gt;sync-starter&lt;/code&gt; and &lt;code&gt;skills-publish&lt;/code&gt; skip Finder duplicates; a file &lt;code&gt;sync-starter&lt;/code&gt; adds reaches the public starter before it is committed; &lt;code&gt;public-release&lt;/code&gt; stops before a second commit. The public README says what is true, and the issue chooser's paid-item link is an https page. A public workflow builds the three starters and runs axe on the Vite starter.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The Blob upload now runs before the release commit&lt;/strong&gt; (&lt;code&gt;scripts/snapshot-upload.mjs&lt;/code&gt;, safe from &lt;code&gt;release/2.7&lt;/code&gt; because blobs are content-addressed and never overwritten), so a paid file of an older version is in the store when 2.7.0 deploys. Before, it ran after the merge and those versions answered 503 until it finished.&lt;/li&gt;&lt;li&gt;Stats count the new tests (4,091); &lt;code&gt;RELEASING.md&lt;/code&gt; no longer creates a GitHub release from the private repository.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.6.2</title>
      <link>https://candor.themethodic.com/changelog#2-6-2</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-6-2</guid>
      <pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Fixes from six cold reviews of the kit, the site and the public repository (&lt;code&gt;internal/review-2026-11/&lt;/code&gt;): the docs an agent reads carry every prop and type, &lt;code&gt;suggest_components&lt;/code&gt; says when Candor has nothing, the site's numbers add up and its pages fit a phone, and the CLI survives a shadcn release. No item is added and no item's API changes in a way that breaks code: unions widen, optional props and one deprecated alias are added. With CLI 0.11.2 and &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.6.2.&lt;/p&gt;&lt;h3&gt;Components (fixes reach every tier)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Plan ids, model vendors, channel kinds, notice kinds and inbox kinds take values Candor doesn't know (&lt;code&gt;(string &amp;amp; {})&lt;/code&gt; beside the known ones), with a plain label and icon for the unknown value, as &lt;code&gt;AuditLog&lt;/code&gt; already did. Before, a plan called &amp;quot;starter&amp;quot; or a model from Mistral failed the type check.&lt;/li&gt;&lt;li&gt;Right to left: &lt;code&gt;ProvenanceTrace&lt;/code&gt; draws its connectors across the gutter in RTL; &lt;code&gt;Sheet&lt;/code&gt; and &lt;code&gt;Drawer&lt;/code&gt; take &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; sides (&lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; still work) and &lt;code&gt;AppLayout&lt;/code&gt; uses them; &lt;code&gt;TraceViewer&lt;/code&gt; places its bars with &lt;code&gt;inset-inline-start&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ImportReview&lt;/code&gt; shows every issue in a group on request instead of eight and &amp;quot;and N more&amp;quot;; &lt;code&gt;ReviewQueue&lt;/code&gt; says when it has nothing to review instead of rendering nothing, and summarises its progress past fifty items; &lt;code&gt;CheckpointList&lt;/code&gt;, &lt;code&gt;MembersTable&lt;/code&gt;, &lt;code&gt;ScheduleList&lt;/code&gt;, &lt;code&gt;AgentRoster&lt;/code&gt; and &lt;code&gt;VersionHistory&lt;/code&gt; say when they are empty.&lt;/li&gt;&lt;li&gt;&lt;code&gt;PlanPicker&lt;/code&gt;, &lt;code&gt;SubscriptionStatus&lt;/code&gt; and &lt;code&gt;DowngradeImpact&lt;/code&gt; format money through &lt;code&gt;useFormat&lt;/code&gt; in a &lt;code&gt;currency&lt;/code&gt; prop (default USD) instead of a hard-coded dollar sign.&lt;/li&gt;&lt;li&gt;&lt;code&gt;card-registry&lt;/code&gt; exports &lt;code&gt;RegistryCard&lt;/code&gt;; &lt;code&gt;Card&lt;/code&gt; stays as a deprecated alias until 3.0, so it no longer collides with &lt;code&gt;ui/card&lt;/code&gt;'s &lt;code&gt;Card&lt;/code&gt; in an app that imports both.&lt;/li&gt;&lt;li&gt;&lt;code&gt;RunNode&lt;/code&gt; gains &lt;code&gt;lastHeardAt&lt;/code&gt; and &lt;code&gt;hostOffline&lt;/code&gt;, so &lt;code&gt;RunTree&lt;/code&gt; shows a subagent that has gone quiet or lost its host, the way &lt;code&gt;TaskTray&lt;/code&gt; and &lt;code&gt;AgentActivity&lt;/code&gt; do.&lt;/li&gt;&lt;li&gt;&lt;code&gt;withRender&lt;/code&gt; (&lt;code&gt;lib/render-prop&lt;/code&gt;, free) keeps an element's own children when none are passed, and refuses Base UI's function form of &lt;code&gt;render&lt;/code&gt; with a message instead of crashing.&lt;/li&gt;&lt;li&gt;&lt;code&gt;DataImport&lt;/code&gt; and &lt;code&gt;SourceIngest&lt;/code&gt; take an &lt;code&gt;error&lt;/code&gt; for a rejected file; &lt;code&gt;DataImport&lt;/code&gt; can give a loaded file back.&lt;/li&gt;&lt;li&gt;&lt;code&gt;TestResults&lt;/code&gt; filters to failed tests and re-runs one (&lt;code&gt;onRerun&lt;/code&gt;); &lt;code&gt;SteerComposer&lt;/code&gt; attaches files.&lt;/li&gt;&lt;li&gt;&lt;code&gt;BarChart&lt;/code&gt; and &lt;code&gt;LineChart&lt;/code&gt;'s focusable value rects carry a role, so axe passes on a page that shows them.&lt;/li&gt;&lt;li&gt;&lt;code&gt;MembersTable&lt;/code&gt; and &lt;code&gt;Stepper&lt;/code&gt; no longer widen a narrow page.&lt;/li&gt;&lt;li&gt;An agent's &lt;code&gt;Message&lt;/code&gt; is labelled &amp;quot;Name (Role)&amp;quot;, so a screen reader hears &amp;quot;agent&amp;quot; once; &lt;code&gt;AppLayout&lt;/code&gt; draws its top row as the app's banner landmark when there is anything in it.&lt;/li&gt;&lt;li&gt;Twelve item descriptions say what the item does instead of carrying an internal code name (&amp;quot;Candor's ReviewCanvas&amp;quot;) or restating the name (&amp;quot;A run that stopped.&amp;quot;).&lt;/li&gt;&lt;li&gt;Three defaults changed, each for a fix above; an app that relies on the old one should check: &lt;code&gt;Message&lt;/code&gt;'s default &lt;code&gt;agentLabel&lt;/code&gt; string is now &amp;quot;Name (Role)&amp;quot;; the billing items' &lt;code&gt;price&lt;/code&gt; strings no longer carry a currency symbol, because the formatter adds it, so an override that includes one should drop it; &lt;code&gt;AppLayout&lt;/code&gt; draws its top row as a &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, so an app that put its own banner outside &lt;code&gt;AppLayout&lt;/code&gt; should move it into &lt;code&gt;top&lt;/code&gt; or it has two.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and the docs MCP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Exported types and function signatures are shown whole; before, 85 types were cut off partway through.&lt;/li&gt;&lt;li&gt;Button, Badge, Toggle, ToggleGroup and Surface pages list their &lt;code&gt;variant&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;tone&lt;/code&gt; and other variant props with values and defaults; exported constants such as &lt;code&gt;standardCards&lt;/code&gt; and the preset kinds have their types, so those pages are no longer empty. Component pages show the Motion section the &lt;code&gt;.md&lt;/code&gt; pages already had.&lt;/li&gt;&lt;li&gt;Blocks and templates no longer list &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; as components or repeat their exports; &lt;code&gt;llms.txt&lt;/code&gt;, &lt;code&gt;llms-full.txt&lt;/code&gt;, the skill's &lt;code&gt;components.md&lt;/code&gt; and the MCP list each one once with its &lt;code&gt;-claude&lt;/code&gt; version beside it. &lt;code&gt;llms-full.txt&lt;/code&gt; lists the functions, values and types of the adapters and shared helpers. &lt;code&gt;scale&lt;/code&gt; is listed under shared helpers.&lt;/li&gt;&lt;li&gt;Each setup guide has a Markdown version at &lt;code&gt;/guides.md&lt;/code&gt; and &lt;code&gt;/guides/&amp;lt;tool&amp;gt;.md&lt;/code&gt;, linked from the page.&lt;/li&gt;&lt;li&gt;&lt;code&gt;suggest_components&lt;/code&gt; lists only items that fit the task; when nothing fits it says &amp;quot;Candor has no item for this&amp;quot; and names the nearest pattern or says the job is left to the app. It takes an optional &lt;code&gt;sdk&lt;/code&gt; (&lt;code&gt;ai-sdk&lt;/code&gt;, &lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;ag-ui&lt;/code&gt;) and suggests only that SDK's adapter and block versions; without it, no adapter, and it says which to add. Install commands are split by tier. Coding agents should pass &lt;code&gt;sdk&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;candor-ui&lt;/code&gt; skill names all twelve MCP tools and says to call &lt;code&gt;list_screens&lt;/code&gt; first for a new screen.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.11.2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;candor-ui&lt;/code&gt; runs a pinned shadcn (&lt;code&gt;shadcn@~4.23.0&lt;/code&gt;) instead of &lt;code&gt;shadcn@latest&lt;/code&gt;, because &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; read what shadcn prints. &lt;code&gt;CANDOR_SHADCN&lt;/code&gt; runs another version, range or tag. A weekly CI job runs the fresh-app check against &lt;code&gt;shadcn@latest&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;init&lt;/code&gt; installs the theme and Inter the way &lt;code&gt;add&lt;/code&gt; installs an item: at the version &lt;code&gt;candor-lock.json&lt;/code&gt; records, and recorded in it; &lt;code&gt;init --latest&lt;/code&gt; takes the newest release. When the lockfile records the theme, &lt;code&gt;init --overwrite&lt;/code&gt; stops and points to &lt;code&gt;npx candor-ui update theme&lt;/code&gt;. Before, it installed the newest theme and left the lockfile naming the old one.&lt;/li&gt;&lt;li&gt;On SIGINT, SIGTERM or SIGHUP during &lt;code&gt;add&lt;/code&gt;, the CLI passes the signal to shadcn and waits for it to exit before putting &lt;code&gt;components.json&lt;/code&gt; back, then exits 128 plus the signal's number. Before, a signal to the CLI alone left shadcn running.&lt;/li&gt;&lt;li&gt;When a release's snapshot can't be read, &lt;code&gt;add&lt;/code&gt; says the registry couldn't be reached and names the URL; the &amp;quot;an item added after x.y.z isn't in it&amp;quot; hint appears only on a 404.&lt;/li&gt;&lt;li&gt;With items at several versions, the stop-and-ask reads &amp;quot;move button (2.5.1) and motion, render-prop, status and locale (2.6.0) to 2.4.0&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt; prints a line per item, shared item and npm package before shadcn runs and a line per item as it records them; no spinners when the output isn't a terminal. The time an install takes is unchanged: it is shadcn's per-item runs, which a later CLI replaces.&lt;/li&gt;&lt;li&gt;&lt;code&gt;doctor&lt;/code&gt; notes when &lt;code&gt;@candor-ui/react&lt;/code&gt; is installed beside copied items (the package's providers don't reach the copies). On a Base UI project, &lt;code&gt;doctor&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; say that Candor's primitives are Radix and name the project's own files they would go over; &lt;code&gt;add&lt;/code&gt; says so before shadcn runs.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Every &lt;code&gt;/screens&lt;/code&gt; page, &lt;code&gt;/docs/members-table&lt;/code&gt; and &lt;code&gt;/docs/stepper&lt;/code&gt; fit a 390 px phone; a check in CI and the release check loads every sitemap page at 390 px and fails on sideways scrolling.&lt;/li&gt;&lt;li&gt;The home page and the pricing cards count by kind, from &lt;code&gt;stats.json&lt;/code&gt;: agent components and hooks, restyled primitives, blocks and templates, themes; the cards add up to the headline. The theme builder's component index says what its count leaves out.&lt;/li&gt;&lt;li&gt;A &amp;quot;Skip to content&amp;quot; link on every page; props tables and code blocks that scroll are focusable and named.&lt;/li&gt;&lt;li&gt;&amp;quot;Most popular&amp;quot; is gone from the Pro card; the hero run is labelled an example. Each pricing card states its support terms as the licence has them; Support and Contact are in the footer; the 60-day continuity promise is under the cards; the FAQ says how to upgrade a tier (for the price difference, by email; the key moves; no downgrades), and the licence's section 4 says the same.&lt;/li&gt;&lt;li&gt;One install story everywhere: the &lt;code&gt;candor-ui&lt;/code&gt; CLI, which wraps shadcn, with shadcn alone as the fallback.&lt;/li&gt;&lt;li&gt;The docs are ordered the way an app is built (Chat first, templates last), Pro and Premium are marked in the sidebar, the tier filter has three states, and a group card opens its group.&lt;/li&gt;&lt;li&gt;Get started from nothing: a step 0 that creates the app, a short first page without the Thread demo's controls, and the no-key Vite starter (&amp;quot;Try it in a minute, no key&amp;quot;), also in &lt;code&gt;llms.txt&lt;/code&gt;. The guides say the &lt;code&gt;components.json&lt;/code&gt; block is what &lt;code&gt;init&lt;/code&gt; writes.&lt;/li&gt;&lt;li&gt;&lt;code&gt;/app&lt;/code&gt; is pre-rendered with its own title and description, its way back goes to &lt;code&gt;/examples&lt;/code&gt;, and its notice and top bar sit in landmarks; &lt;code&gt;/gallery&lt;/code&gt; redirects to &lt;code&gt;/examples&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;On a phone the docs and examples keep their filter, and the docs their tier filter, above the component select.&lt;/li&gt;&lt;li&gt;Short inline code stays on one line and code has no ligatures; the roadmap's &amp;quot;In progress&amp;quot; shows the last release and the one being prepared; the changelog marks releases that changed no package and explains same-day dates; the home preview says how to see a locked control's reason on a phone; &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; no longer starts dark, the head script or the system setting picks the theme.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The theme builder (free tool)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The result line says &amp;quot;checks&amp;quot; and the Download panel has no stray count line; &amp;quot;Ship&amp;quot; is Download, with a download icon; fixes show the hex beside each OKLCH value.&lt;/li&gt;&lt;li&gt;axe passes: chart rects have a role, the title and toolbar sit in a landmark, the canvas has an &lt;code&gt;h2&lt;/code&gt;; preset buttons carry the preset's name; the panel-width separator reads in pixels; copies say &amp;quot;Copied the …&amp;quot;.&lt;/li&gt;&lt;li&gt;Toasts no longer cover the canvas; the leave prompt no longer fires on a plain reload; an unreadable paste changes nothing and says so; Hide and Show are at the top of the rail; no text is cut short in the settings select or the theme's name at 390 px.&lt;/li&gt;&lt;li&gt;The Button Locked figure shows every variant locked; the default motion level is Off, Subtle or Expressive, or &amp;quot;following Candor's&amp;quot;, not a fourth level; Check names the solid focus ring apart from the ring at 80%.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The public repository (MethodicDev/candor)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Each release gets a tag and a GitHub Release with its changelog section (and the releases 1.9.0 to 2.6.1 are filled in). &lt;code&gt;SECURITY.md&lt;/code&gt;, &lt;code&gt;SUPPORT.md&lt;/code&gt;, &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, issue forms and a pull request template.&lt;/li&gt;&lt;li&gt;The README opens with a permission prompt from the Vite starter, badges, &amp;quot;Try it in a minute, no key&amp;quot; first, how the repository works, the paid tiers with prices, refund window and key commands, &amp;quot;Why Candor&amp;quot; and &amp;quot;Tools&amp;quot;, and &amp;quot;What's here&amp;quot; grouped by area with a link per item. It says that &lt;code&gt;@candor-ui/react&lt;/code&gt; changes only when a free item does. The About text leads with the difference; two more topics.&lt;/li&gt;&lt;li&gt;The starters record the kit version they were generated from; the Vite starter builds without the chunk warning.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Build and checks&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Every build and check script lists directories through &lt;code&gt;scripts/fs-walk.mjs&lt;/code&gt;, which skips the &amp;quot;name 2.ext&amp;quot; copies Finder and iCloud leave behind; &lt;code&gt;tsconfig&lt;/code&gt; and Vitest exclude them.&lt;/li&gt;&lt;li&gt;The registry build stamps every item's tier (&lt;code&gt;meta.tier&lt;/code&gt;) and refuses a free item that depends on a paid one; the licence check and the README check read the stamp.&lt;/li&gt;&lt;li&gt;&lt;code&gt;npm run registry&lt;/code&gt; builds the motion manifest itself; CI's stats check keeps the committed test count (&lt;code&gt;stats.mjs --keep-tests&lt;/code&gt;), and the release check counts.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.6.1</title>
      <link>https://candor.themethodic.com/changelog#2-6-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-6-1</guid>
      <pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;CLI 0.11.1, for Storywrite's ask 36: &lt;code&gt;candor-ui add&lt;/code&gt; installs at the version your lockfile records, so adding one item no longer moves the items it shares with the rest of your project to a newer release; &lt;code&gt;--latest&lt;/code&gt; and &lt;code&gt;--version&lt;/code&gt; opt in, and &lt;code&gt;add&lt;/code&gt; names anything it would move and asks first. No change to the kit or &lt;code&gt;@candor-ui/react&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;CLI 0.11.1&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;candor-ui add&lt;/code&gt; installs at the version &lt;code&gt;candor-lock.json&lt;/code&gt; records (the theme's, else the newest installed item's), and so do the shared items the item uses (&lt;code&gt;locale&lt;/code&gt;, &lt;code&gt;render-prop&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;motion&lt;/code&gt;): for the shadcn run it points the &lt;code&gt;@candor&lt;/code&gt; registry entry at that release's snapshot (&lt;code&gt;/r/v/&amp;lt;version&amp;gt;/&lt;/code&gt;) and puts &lt;code&gt;components.json&lt;/code&gt; back after, on failure and on interrupt too. Before, &lt;code&gt;add&lt;/code&gt; always installed the newest release and rewrote shared items to it (Storywrite's ask 36).&lt;/li&gt;&lt;li&gt;New &lt;code&gt;add --latest&lt;/code&gt; (the newest release) and &lt;code&gt;add --version &amp;lt;x.y.z&amp;gt;&lt;/code&gt; (that release; a version &lt;code&gt;/r/versions.json&lt;/code&gt; doesn't list is refused, with the list). A project with no lockfile installs the newest release, as before, and the last line says so.&lt;/li&gt;&lt;li&gt;Before shadcn runs, &lt;code&gt;add&lt;/code&gt; names the installed items it would move to another version, and the edits it would overwrite, and stops unless &lt;code&gt;--yes&lt;/code&gt; is given (&amp;quot;This would move locale, render-prop and status from 2.1.0 to 2.6.1… &lt;code&gt;npx candor-ui update&lt;/code&gt; is the way to move them on purpose. Nothing was installed.&amp;quot;). With &lt;code&gt;--yes&lt;/code&gt; the same line is a notice. The last line says what was installed and at which version.&lt;/li&gt;&lt;li&gt;Unchanged, on purpose: &lt;code&gt;init&lt;/code&gt; still installs &lt;code&gt;theme&lt;/code&gt; and the font from the newest release.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.6.0</title>
      <link>https://candor.themethodic.com/changelog#2-6-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-6-0</guid>
      <pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Density that reaches controls: heights, paddings and row heights follow &lt;code&gt;data-density&lt;/code&gt;, so the theme builder's Density control changes what it says. The builder keeps a library of themes in the browser and its undo history across a reload, and an override never erases a nested surface. The docs MCP gains &lt;code&gt;theme_check&lt;/code&gt;, the same checks as the CLI, for a coding agent verifying its own edits. With CLI 0.11.0 (the checker shared with the MCP); &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.6.0 carries the free changes.&lt;/p&gt;&lt;h3&gt;The theme builder (free tool)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Several themes in this browser:&lt;/strong&gt; the list beside the theme's name has New theme (Candor's defaults, nothing chosen), Rename, Duplicate, Delete (asks first; can't be undone) and one-press switching. Download, Copy and Share take the open theme. A share link opened beside kept work opens as a new theme instead of replacing yours. The privacy page names every key the builder uses.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Undo and redo survive a reload&lt;/strong&gt;, with their step names: the last fifty steps each way, kept for the tab.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A component's ground no longer hides the surfaces inside it:&lt;/strong&gt; the override writes only the component's own ground; the card, bubble, well and popover inside keep their colour, or step from the ground just far enough to stay distinct and readable where their own colour would vanish. Check lists each surface inside a ground against it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Density says what it sets since 2.6:&lt;/strong&gt; field heights (32, 36 or 40 px), table heading rows (32, 40 or 48 px) with 4, 8 or 12 px above and below the text of the rows under them, and padding, as well as text and widths; exports carry the control and row tokens. A component's own density is written under &lt;code&gt;:root:not([data-density])&lt;/code&gt;, so the person's &lt;code&gt;data-density&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; still wins over it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Loading a hand-edited file:&lt;/strong&gt; an edited primary is the theme's primary, the same as typing it, so its hover, focus ring, accent grounds and the dark and high-contrast primaries follow it; a role the file set itself is kept and the load report names it; the report lists only the values you edited and says once which values follow from them; something the builder can't read changes nothing and says so. Button's block also names a Button inside &lt;code&gt;Locked&lt;/code&gt; (&lt;code&gt;[data-slot=&amp;quot;locked&amp;quot;] &amp;gt; button[data-slot=&amp;quot;tooltip-trigger&amp;quot;][data-variant]&lt;/code&gt;), and the brief says so.&lt;/li&gt;&lt;li&gt;A reload never asks &amp;quot;Leave site?&amp;quot;: the browser asks only if a change couldn't be kept in this browser; leaving by a site link still asks while the theme hasn't been downloaded, copied or shared. After &amp;quot;Apply this fix&amp;quot; focus moves to the next fix; each panel opens at its top; &amp;quot;Theme canvas&amp;quot; keeps the open panel.&lt;/li&gt;&lt;li&gt;The Chat view's Thread shows the plain thread; the docs page keeps its &amp;quot;600 messages&amp;quot; demo toggle.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Density (free theme; reaches every tier)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;data-density=&amp;quot;compact&amp;quot; | &amp;quot;spacious&amp;quot;&lt;/code&gt; now changes the height, padding and gaps of controls, menu items and table rows, not only text sizes and widths. One height ladder: &lt;code&gt;--cd-control-h-2xs&lt;/code&gt; (24 px) to &lt;code&gt;--cd-control-h-lg&lt;/code&gt; (40 px), with &lt;code&gt;--cd-control-px-*&lt;/code&gt;, &lt;code&gt;--cd-control-py&lt;/code&gt;, &lt;code&gt;--cd-control-gap&lt;/code&gt;, &lt;code&gt;--cd-area-min-h&lt;/code&gt;, &lt;code&gt;--cd-item-*&lt;/code&gt;, &lt;code&gt;--cd-row-*&lt;/code&gt; and &lt;code&gt;--cd-cell-px&lt;/code&gt;, each with compact and spacious values; compact never goes under 24 px, so no target shrinks past WCAG's minimum. Utilities (&lt;code&gt;h-control-sm&lt;/code&gt;, &lt;code&gt;px-control&lt;/code&gt;, &lt;code&gt;h-row&lt;/code&gt;, …) are registered; the components use the &lt;code&gt;h-(--cd-control-h-sm)&lt;/code&gt; form so a consumer's &lt;code&gt;h-10&lt;/code&gt; still wins through &lt;code&gt;cn()&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Ninety-six components read the tokens, Button, Input, Textarea, Select, Combobox and DatePicker triggers, Toggle, Tabs, Pagination, the four menus, Command, the table primitive, DataTable, SessionList, Inbox, ApprovalQueue and the Composer's buttons among them. At the default density nothing changes (checked class by class against 2.5.1). The Console gallery theme now compacts controls as well as text.&lt;/li&gt;&lt;li&gt;Every density token read carries its default as a fallback (&lt;code&gt;h-(--cd-control-h-sm,2rem)&lt;/code&gt;), so an app that updates a component without updating its &lt;code&gt;theme&lt;/code&gt; item still draws the default sizes.&lt;/li&gt;&lt;li&gt;&lt;code&gt;npm run check:density&lt;/code&gt; fails on a fixed control height or padding class in the registry, or on a token read without its fallback, with a short allowlist of honest fixed sizes (chart frames, drawings, skeletons); it runs in &lt;code&gt;release:check&lt;/code&gt; and CI.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The docs MCP and CLI 0.11.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;theme_check&lt;/code&gt;&lt;/strong&gt; in the docs MCP server (read-only, keyless, fetches nothing): send the contents of &lt;code&gt;candor-brand.css&lt;/code&gt; (up to 256 KB) and it returns the contrast of every pairing in light, dark and high contrast and every &lt;code&gt;--cd-motion-*&lt;/code&gt; and &lt;code&gt;--cd-sound-*&lt;/code&gt; value against the current kit's manifest, as a short summary in the CLI's words and as JSON; sound files are reported as not measured because it can't see your &lt;code&gt;public/&lt;/code&gt;. A file made for an older kit is checked against the current names, with a note. &lt;code&gt;llms.txt&lt;/code&gt;, Get started and the skill say when to call it: after editing the brand file.&lt;/li&gt;&lt;li&gt;&lt;code&gt;candor-ui theme check&lt;/code&gt; and the MCP's &lt;code&gt;theme_check&lt;/code&gt; run the same code (&lt;code&gt;packages/cli/src/check/&lt;/code&gt;); the CLI's output and exit codes are unchanged. Hostile input stays cheap: no suggestion for names over 64 characters or past 200 unknown names, nesting capped at 32 levels with a plain error, findings listed 200 per kind with exact counts.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.5.1</title>
      <link>https://candor.themethodic.com/changelog#2-5-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-5-1</guid>
      <pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Fixes from the cold review of the live site: the privacy page says what the theme builder keeps in the browser, the builder is linked from the header, Get started, the brand FAQ and the agent docs, the stale version copy is gone, a code block on the motion page renders, and a dozen small things in the builder and the site. Nothing under &lt;code&gt;src/registry&lt;/code&gt; changed, so &lt;code&gt;@candor-ui/react&lt;/code&gt; stays at 2.5.0 and the CLI at 0.10.0.&lt;/p&gt;&lt;h3&gt;Site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The privacy page says what the theme builder keeps in your browser (the theme and panel width in local storage, the open panel and pasted brand colours in session storage; nothing is sent anywhere; how to clear them) and that light or dark is shared with themethodic.com through a cookie on &lt;code&gt;.themethodic.com&lt;/code&gt;; the GDPR and DPA pages no longer say &amp;quot;no cookies&amp;quot;.&lt;/li&gt;&lt;li&gt;The site's copy reads the kit's version: the home pill (&amp;quot;New in 2.5&amp;quot;), the Accessibility page and the Roadmap no longer name old releases, and a test fails on any copy older than the kit's minor.&lt;/li&gt;&lt;li&gt;The theme builder is in the header, in Get started as &amp;quot;Make it yours&amp;quot; (the &lt;code&gt;@import&lt;/code&gt; lines and &lt;code&gt;theme check&lt;/code&gt;), in the brand FAQ, and in &lt;code&gt;llms.txt&lt;/code&gt;, the design reference and the theme docs, so a coding agent can find it. &lt;code&gt;/themes&lt;/code&gt; points at the builder's checks and &lt;code&gt;npx candor-ui theme check&lt;/code&gt;, not a script customers don't have.&lt;/li&gt;&lt;li&gt;Visitors who have chosen no theme get the one their system uses (before, dark); the home announcement pill wraps on a phone.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docs pages keep fenced code in descriptions, so the code sample on &lt;code&gt;/docs/motion&lt;/code&gt; renders as a code block, and a function's description is no longer repeated under Functions.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Theme builder&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Brand field shows a primary set by hand (and says so, with Remove); the right-to-left and other-theme previews are as wide as Default; the agent name you type reaches every example screen; leaving asks only when there is work not yet downloaded, copied or shared; canvas notes go after six seconds and wait while the pointer is on them; segmented controls no longer run their words together; Sound's fields are named with their event; the page opens with skip links to the toolbar and the canvas; the agent brief says &amp;quot;the CSS file named in components.json&amp;quot;.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.5.0</title>
      <link>https://candor.themethodic.com/changelog#2-5-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-5-0</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The theme builder, rebuilt a second time around what people come to do: Start, Colour, Type, Shape, Motion and Sound on a labelled rail, a Components workspace that shows one component with its states and settings side by side, every change visible where it is made, work kept in the browser, one theme switch for the whole page, and a token file beside the CSS. Candor's pages and the builder wear the Methodic site's header. &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.5.0 is 2.4.0's code with the new motion sentences in its doc comments.&lt;/p&gt;&lt;h3&gt;The theme builder (free tool)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Rebuilt around the site header&lt;/strong&gt;, whose theme control now themes the whole page, light, dark or high contrast, chrome included. A labelled rail: Start, Colour, Type, Shape, Motion, Sound; then Components, one at a time; then Check and Ship. Panels push the canvas and can be resized; below 768 px the rail is a bottom bar and panels open as sheets. Undo and Redo name their step.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Start&lt;/strong&gt; offers each preset with four shapes (Candor, Soft, Crisp, Square), &amp;quot;From my brand&amp;quot; (paste hex codes; the primary can be locked so fixes adjust foregrounds and rings instead), Random that says what it chose, and Open a file. The Style panel and its duplicate controls are gone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Colour&lt;/strong&gt; edits whichever theme the page shows, with that theme's values in the fields; fixes that keep your primary come first. &lt;strong&gt;Type&lt;/strong&gt; keeps Inter in the list, takes a custom font by name or address and says when it isn't installed here. &lt;strong&gt;Shape&lt;/strong&gt; is radius and density together. &lt;strong&gt;Motion&lt;/strong&gt; names each family in plain words first; &amp;quot;Preview as&amp;quot; lives there and is never exported. &lt;strong&gt;Sound&lt;/strong&gt; plays the starter set; the local-file picker is gone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Components&lt;/strong&gt; is a workspace: an index in a curated order (by how often a component is met and how much it shows a theme) with search and filters; one component at a time with its states side by side (loading, error, locked, right to left and the other theme where it has them) and a labelled Replay for each moment; its settings by plain name with swatches. A change you make is applied to the component in front of you at once, as well as to the exported file, so a radius, colour or motion edit is visible within a frame.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The canvas&lt;/strong&gt; opens on a brand sample (buttons, a link, a focus ring, every status, a chart, a selected row, an input with an error, a locked control) before Chat, Approvals, Run, Dashboards, Patterns and Screens, where templates and full-stack blocks appear as compositions of their own parts. Cards keep name, gear and reset only.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Check&lt;/strong&gt; groups failures by fix. &lt;strong&gt;Ship&lt;/strong&gt; shows what changed in every section as a diff with counts, downloads the CSS and a design-token file (&lt;code&gt;candor-theme.json&lt;/code&gt;, DTCG: every role per theme with its checks, component overrides, motion and sound), and copies the brief for a coding agent, the DESIGN.md addendum, a PR summary (what changed since the loaded file, checks before and after) and your product's words as a provider config. A brand-intent field travels into all of them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Your work is kept&lt;/strong&gt; in this browser and in the page's address; a link pasted into an open tab is applied, a bad link says so, and leaving before a download asks first. Opening a hand-edited file keeps your edits and lists what differed from the builder's own line; a file without that line is mapped into the panels.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The brand path holds up:&lt;/strong&gt; the hex you type is kept exactly, in the CSS comment and in the token file, and an edited hex loads back; a bright primary keeps its hue in dark and says when no dark value can pass; Random names a kept colour that blocks it and offers to replace it; a Google Fonts address loads (one that arrives in a link or a file loads only after a press); Density and Heading weight say what they reach. Density does not change control heights, which the kit's density tokens don't cover yet.&lt;/li&gt;&lt;li&gt;Every bug the cold review of the first build found has a test and is closed; the re-review of this build is &lt;code&gt;internal/design/theme-builder-v2/REVIEW-UX-2.5.md&lt;/code&gt;, with its seven named fixes made.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The site header is the Methodic family header on every page (the &lt;code&gt;/app&lt;/code&gt; demo keeps its own shell): the tile and name with the page's section beside them, a sliding pill under the current page, a single theme button that still offers system, light, dark and high contrast, the call to action, and a full-width menu below 1024 px. Light and dark are shared with themethodic.com through its cookie, and the page's theme is set before first paint. The footer's family links include Candor UI.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Every motion moment now has its own sentence, in plain words, saying when it plays and what it never does; they show in each component's Motion section, in the MCP and in the theme builder, and a test keeps it so. An item's description is never one of its &lt;code&gt;@motion&lt;/code&gt; tags.&lt;/li&gt;&lt;li&gt;A worktree's dev server serves fonts through its linked &lt;code&gt;node_modules&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.4.0</title>
      <link>https://candor.themethodic.com/changelog#2-4-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-4-0</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The motion layer put to work: the catalogue's behaviours on the components where decisions land, queues move, values change and checks return; sound as a closed set of five events with a CC0 starter set; the motion manifest the docs, the MCP and the CLI read; &lt;code&gt;data-slot&lt;/code&gt; on every component root so a brand file can reach each one; &lt;code&gt;candor-ui theme check&lt;/code&gt; for motion and sound and &lt;code&gt;theme apply&lt;/code&gt;; and the 2.3 review's leftovers. With CLI 0.10.0; &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.4.0 carries the free changes. The theme builder that edits all of this per component is being reworked and follows in 2.5.&lt;/p&gt;&lt;h3&gt;Motion follows the outcome, on more components&lt;/h3&gt;&lt;p&gt;Every moment below plays only for a change seen on screen, never on first draw, and is set per family or per moment from a brand file (&lt;code&gt;--cd-motion-&amp;lt;item&amp;gt;-&amp;lt;moment&amp;gt;-*&lt;/code&gt;). Each is tagged in the component and listed in the manifest.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Free&lt;/strong&gt; - &lt;code&gt;ContextMeter&lt;/code&gt;'s percentage crossfades when the count changes; the upload bar's and setup ring's fills are documented as the fill moments they were. - &lt;code&gt;Locked&lt;/code&gt;'s shake ends with its animation instead of a fixed timer. &lt;code&gt;Alert&lt;/code&gt; counts &amp;quot;first draw&amp;quot; from the page's load, so the first alert an app shows can rise in. &lt;code&gt;Composer&lt;/code&gt; chips are flex children of the chip row again; &lt;code&gt;EntityChip&lt;/code&gt; and &lt;code&gt;AttachmentChip&lt;/code&gt; gain &lt;code&gt;style&lt;/code&gt;. - &lt;code&gt;useLeaving&lt;/code&gt;'s fallback is 600 ms; &lt;code&gt;useMotionMode(ref)&lt;/code&gt; is new in &lt;code&gt;lib/motion.ts&lt;/code&gt;; families with one drawing are marked fixed in the design reference; &lt;code&gt;check:motion&lt;/code&gt; requires literal defaults.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Pro&lt;/strong&gt; - &lt;strong&gt;A decision lands:&lt;/strong&gt; &lt;code&gt;ApprovalRequest&lt;/code&gt; and &lt;code&gt;EntityDisambiguation&lt;/code&gt; open the outcome line and draw its tick or cross only after the service confirms; &lt;code&gt;Plan&lt;/code&gt; opens its heading line when the plan leaves &amp;quot;proposed&amp;quot;. Nothing moves on the click, and a prompt that mounts already decided is still. - &lt;strong&gt;Rows arrive and leave:&lt;/strong&gt; &lt;code&gt;ApprovalQueue&lt;/code&gt;, &lt;code&gt;Inbox&lt;/code&gt;, &lt;code&gt;NotificationCenter&lt;/code&gt;, &lt;code&gt;TaskTray&lt;/code&gt;, &lt;code&gt;SessionList&lt;/code&gt; and &lt;code&gt;RunLog&lt;/code&gt; rows rise in when added after first draw (never on a tab, filter, pin or scroll); &lt;code&gt;ApprovalQueue&lt;/code&gt; and &lt;code&gt;Inbox&lt;/code&gt; rows collapse out only once the data removes them, so a failed decision never shows as gone. - &lt;strong&gt;Toasts&lt;/strong&gt; leave on dismiss or expiry and the rest slide to fill the gap (skipped under calm and none); error toasts still never leave on their own. - &lt;strong&gt;The undo window&lt;/strong&gt; gains a bar that drains from the server's deadline, read from the clock each frame, so a slept tab jumps; it never pauses on hover and steps in tenths under calm. - &lt;strong&gt;Values in place:&lt;/strong&gt; &lt;code&gt;StatCard&lt;/code&gt;, &lt;code&gt;UsageMeters&lt;/code&gt;, &lt;code&gt;RunReceipt&lt;/code&gt; and &lt;code&gt;Badge&lt;/code&gt; crossfade a figure that changes and pop a count that rises; nothing counts through numbers that were never measured. - &lt;strong&gt;Validation:&lt;/strong&gt; &lt;code&gt;Input&lt;/code&gt; and &lt;code&gt;Textarea&lt;/code&gt; gain &lt;code&gt;attend&lt;/code&gt;: one attention ring on the invalid field after a failed submit, never a shake, and never on first draw. &lt;code&gt;AccountCreate&lt;/code&gt; and &lt;code&gt;SignIn&lt;/code&gt; focus and ring the field the error concerns once the service has answered, and fade their messages in; &lt;code&gt;InviteMembers&lt;/code&gt; fades in its &amp;quot;won't be sent&amp;quot; note. - &lt;code&gt;TypeToConfirm&lt;/code&gt; pops each time the text comes to match exactly and shakes (expressive only) when it stops matching. &lt;code&gt;EnvironmentBand&lt;/code&gt; rings once, in the environment's colour, when the environment in scope changes. - &lt;strong&gt;Measured fills:&lt;/strong&gt; &lt;code&gt;BulletBar&lt;/code&gt; and &lt;code&gt;UsageMeters&lt;/code&gt; move between measured values; &lt;code&gt;DataImport&lt;/code&gt; gains &lt;code&gt;progress&lt;/code&gt; (0–1, a bar only while reading). - &lt;strong&gt;Checks draw as they return:&lt;/strong&gt; &lt;code&gt;ShipReview&lt;/code&gt;, &lt;code&gt;TestResults&lt;/code&gt; and &lt;code&gt;RestoreResult&lt;/code&gt; draw each check's mark when its result arrives; &lt;code&gt;RestoreResult&lt;/code&gt; gains &lt;code&gt;fresh&lt;/code&gt;. &lt;code&gt;SteerComposer&lt;/code&gt; draws the read tick on &lt;code&gt;picked-up&lt;/code&gt;, never on send. - &lt;code&gt;Drawer&lt;/code&gt;'s &lt;code&gt;data-side&lt;/code&gt; is now &lt;code&gt;data-edge&lt;/code&gt; (no alias: the old name meant a popover's side to the overlay family); an app that styled the old attribute changes its selector. &lt;code&gt;ToggleGroup&lt;/code&gt;'s first choice lands in place; &lt;code&gt;Stepper&lt;/code&gt;'s tick uses the done moment's tokens; &lt;code&gt;Combobox&lt;/code&gt; and &lt;code&gt;Carousel&lt;/code&gt; use the layer's hooks.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Sound&lt;/h3&gt;&lt;p&gt;A closed set of five events, &lt;code&gt;needs-you&lt;/code&gt;, &lt;code&gt;finished&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt;, &lt;code&gt;reply&lt;/code&gt; and &lt;code&gt;silent&lt;/code&gt;, off until the person turns them on, always beside a visible cue, raised from data and never from a mount, one sound per burst and the same event at most once in 3 s. The brand names the files: &lt;code&gt;--cd-sound-&amp;lt;event&amp;gt;: &amp;quot;/sounds/needs-you.mp3&amp;quot;&lt;/code&gt;, &lt;code&gt;--cd-sound-volume&lt;/code&gt; and &lt;code&gt;--cd-sound-&amp;lt;event&amp;gt;-volume&lt;/code&gt; (0–1), &lt;code&gt;--cd-sound-&amp;lt;event&amp;gt;-ogg&lt;/code&gt; as an alternative. Nothing is fetched until a sound plays, and Candor's CSS sets no defaults.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Free:&lt;/strong&gt; &lt;code&gt;sound&lt;/code&gt; (&lt;code&gt;lib/sound.ts&lt;/code&gt;): the event names and token reading; it plays nothing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Pro:&lt;/strong&gt; &lt;code&gt;useAttention&lt;/code&gt; plays the brand's sound for each signal (&lt;code&gt;sound.src&lt;/code&gt; is now optional; &lt;code&gt;sound.when&lt;/code&gt; &amp;quot;away&amp;quot; | &amp;quot;always&amp;quot;, &amp;quot;always&amp;quot; when left out; &lt;code&gt;sound.events&lt;/code&gt;; per-signal &lt;code&gt;sound&lt;/code&gt;; kinds map &lt;code&gt;approval&lt;/code&gt;→&lt;code&gt;needs-you&lt;/code&gt;, &lt;code&gt;finished&lt;/code&gt;→&lt;code&gt;finished&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt;→&lt;code&gt;failed&lt;/code&gt;); coalescing now also applies to an explicit &lt;code&gt;src&lt;/code&gt;. New &lt;code&gt;useArrivals(ids, onNew)&lt;/code&gt;, which calls back only for ids not present at its first render. New &lt;code&gt;sound-setting&lt;/code&gt;: Off / When I'm away / Always, the events as checkboxes with their cue in words, a Play button each; Off is the default and the kit stores nothing. New &lt;code&gt;sounds&lt;/code&gt;: five short CC0 sounds from Kenney (0.18–0.57 s, under 5 KB each); the registry carries text, so it installs &lt;code&gt;scripts/candor-sounds.mjs&lt;/code&gt; and &lt;code&gt;public/sounds/LICENCE.txt&lt;/code&gt;, and &lt;code&gt;node scripts/candor-sounds.mjs&lt;/code&gt; writes the five MP3s to &lt;code&gt;public/sounds/&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The motion manifest and &lt;code&gt;data-slot&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;src/docs/motion.json&lt;/code&gt;, written by &lt;code&gt;npm run docs&lt;/code&gt;: every family's settings and, per item, its moments with family, defaults, utilities and the sentence from its &lt;code&gt;@motion&lt;/code&gt; tag. Each item's docs page (and so the MCP) has a Motion section listing its moments and the token to set them with. Served at &lt;code&gt;/r/motion-manifest.json&lt;/code&gt; and &lt;code&gt;/r/v/&amp;lt;version&amp;gt;/motion-manifest.json&lt;/code&gt;, no key needed.&lt;/li&gt;&lt;li&gt;Every component's root carries &lt;code&gt;data-slot=&amp;quot;&amp;lt;item&amp;gt;&amp;quot;&lt;/code&gt; (&lt;code&gt;npm run check:slots&lt;/code&gt; keeps it so), so a brand file's &lt;code&gt;[data-slot=&amp;quot;&amp;lt;item&amp;gt;&amp;quot;]&lt;/code&gt; block reaches each one. Radix-style parts keep their own slots.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and rules&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The design reference, the accessibility statement and the agent-UI skill describe the sound events, the manifest and &lt;code&gt;candor-ui theme check&lt;/code&gt;; the design reference marks one-drawing families fixed. &lt;code&gt;internal/PLAN-3.0.md&lt;/code&gt; gains the native &lt;code&gt;AttentionKind&lt;/code&gt; mapping, the &lt;code&gt;when: &amp;quot;away&amp;quot;&lt;/code&gt; default and the drawer rename.&lt;/li&gt;&lt;li&gt;&lt;code&gt;tw-animate-css&lt;/code&gt; is no longer a dependency of the theme item, the site or &lt;code&gt;@candor-ui/react&lt;/code&gt;; apps that installed it keep it. The fresh-app check also builds a Base UI (&lt;code&gt;base-nova&lt;/code&gt;) project with &lt;code&gt;switch&lt;/code&gt; and &lt;code&gt;checkbox&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.10.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;theme check&lt;/code&gt; reads motion and sound against the motion manifest of the kit you have installed (a &lt;code&gt;motion.json&lt;/code&gt; beside &lt;code&gt;candor.css&lt;/code&gt;, else the registry's copy for the version in &lt;code&gt;candor-lock.json&lt;/code&gt;, else the latest with a note; if none can be had it says the motion checks didn't run): unknown names with &amp;quot;did you mean&amp;quot; or &amp;quot;known from &amp;lt;version&amp;gt;&amp;quot;, levels outside 0–2, durations outside the family's range, speed outside 0.5–1.5, a spring where nothing can overshoot, attention past 5 s or 3 rings a second, a clock level below 1, raw animations on a Candor slot, sound paths that don't resolve, sounds over 1.5 s or 100 KB or in the wrong format, and a &lt;code&gt;@candor-theme&lt;/code&gt; newer than 2. A sound length it can't read is &amp;quot;not measured&amp;quot;, never a pass. &lt;code&gt;--json&lt;/code&gt; adds &lt;code&gt;motionAndSound&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;New &lt;code&gt;theme apply &amp;lt;file | url&amp;gt;&lt;/code&gt;: checks the file in memory, writes &lt;code&gt;candor-brand.css&lt;/code&gt; next to &lt;code&gt;candor.css&lt;/code&gt; (asks before replacing one; &lt;code&gt;--overwrite&lt;/code&gt;), adds the import after &lt;code&gt;candor.css&lt;/code&gt;'s, lists the sound files the theme names as present or missing (it never downloads them), and says what changed in words. A builder share link is refused with a pointer to the builder's Download.&lt;/li&gt;&lt;li&gt;The CLI has its own vitest config, so &lt;code&gt;cd packages/cli &amp;amp;&amp;amp; npx vitest run&lt;/code&gt; passes.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.3.0</title>
      <link>https://candor.themethodic.com/changelog#2-3-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-3-0</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The ground for per-component theming: a motion token layer with fourteen families and their variants, every hard-coded duration in the kit moved onto it, a defined calm level under reduced motion, and the twenty-two primitives the kit was missing, in Candor's theme and with their honest moments. With CLI 0.9.1; &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.3.0 carries the free changes. The theme builder that edits all of this per component follows in 2.4.&lt;/p&gt;&lt;h3&gt;Motion is a theme layer (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Fourteen families&lt;/strong&gt;, one per kind of change: &lt;code&gt;reveal&lt;/code&gt;, &lt;code&gt;arrive&lt;/code&gt;, &lt;code&gt;pop&lt;/code&gt;, &lt;code&gt;mark&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, &lt;code&gt;move&lt;/code&gt;, &lt;code&gt;overlay&lt;/code&gt;, &lt;code&gt;press&lt;/code&gt;, &lt;code&gt;tint&lt;/code&gt;, &lt;code&gt;refuse&lt;/code&gt;, &lt;code&gt;attention&lt;/code&gt;, &lt;code&gt;live&lt;/code&gt; and &lt;code&gt;clock&lt;/code&gt;. Each has a level (0 off, 1 subtle, 2 expressive), a duration, an easing, an amplitude where it has one, and a closed set of variants (&lt;code&gt;mark: draw | pop | drop&lt;/code&gt;, &lt;code&gt;overlay: scale | slide | fade&lt;/code&gt;, &lt;code&gt;arrive: rise | fade | pop&lt;/code&gt;, and so on; the full table is in the design reference). A brand file sets them for a family everywhere (&lt;code&gt;--cd-motion-&amp;lt;family&amp;gt;-*&lt;/code&gt;) or for one moment of one component (&lt;code&gt;--cd-motion-&amp;lt;item&amp;gt;-&amp;lt;moment&amp;gt;-*&lt;/code&gt;); &lt;code&gt;--cd-motion-speed&lt;/code&gt; (0.5–1.5) scales every duration but the clock's and the attention ring's (which stays under five seconds). A brand changes how a change looks, never when it plays: triggers stay in the components.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New free item &lt;code&gt;motion&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;lib/motion.ts&lt;/code&gt;): the family table, &lt;code&gt;motion(item, moment, family)&lt;/code&gt; to build a moment's chain, and the hooks &lt;code&gt;useSettled&lt;/code&gt;, &lt;code&gt;useArrived&lt;/code&gt;, &lt;code&gt;useLeaving&lt;/code&gt; and &lt;code&gt;useMotionAllowed&lt;/code&gt;. The copies of these hooks in StatusDot, StepList and Composer are gone.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Every component is on it.&lt;/strong&gt; Every moment in the kit is a chain on a family; no hard-coded duration or &lt;code&gt;tw-animate&lt;/code&gt; class is left in the registry, blocks or templates, and &lt;code&gt;npm run check:motion&lt;/code&gt; keeps it that way. Update &lt;code&gt;theme&lt;/code&gt; together with your components, because they use its new &lt;code&gt;cd-*&lt;/code&gt; utilities. 2.2's &lt;code&gt;animate-*&lt;/code&gt; utilities and a brand's &lt;code&gt;--cd-pop-from&lt;/code&gt; or &lt;code&gt;--cd-motion-shake&lt;/code&gt; still work. Small visible differences at &lt;code&gt;subtle&lt;/code&gt;: four chevrons turn in 200 ms (were 150), StepList's mark background in 150 ms (was 200), overlays use Candor's standard easing, and the sheet fades while it slides.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Reduced motion is the calm level&lt;/strong&gt;, not &amp;quot;everything to 0.001 ms&amp;quot;: only opacity and colour change over time, 150 ms at most, nothing loops; &lt;code&gt;live&lt;/code&gt; goes still beside its word, &lt;code&gt;attention&lt;/code&gt; is one ring that fades, &lt;code&gt;clock&lt;/code&gt; steps, &lt;code&gt;reveal&lt;/code&gt; snaps to its measured size. &lt;code&gt;data-motion=&amp;quot;calm&amp;quot;&lt;/code&gt; offers the same as a choice in the app; &lt;code&gt;none&lt;/code&gt; stays the hard off and outranks everything, and &lt;code&gt;subtle&lt;/code&gt; and &lt;code&gt;expressive&lt;/code&gt; are unchanged. Your app's own transitions keep their duration under reduced motion (2.2 cut every one to 0.001 ms) and only the properties they may change are limited.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Fixes in spirit.&lt;/strong&gt; StatusDot has two new optional props, &lt;code&gt;lastHeardAt&lt;/code&gt; and &lt;code&gt;staleAfter&lt;/code&gt;: a running dot pulses only while the run has been heard from within &lt;code&gt;staleAfter&lt;/code&gt;, and is still, with its word, otherwise. PermissionPrompt's waiting pulse is 4.8 s (was 7.2 s). Messages, reasoning entries, StepList steps and StepWalker's stage no longer animate on first draw, and StepList's stagger is gone; Thread marks newly arrived messages with &lt;code&gt;data-arrived&lt;/code&gt;. HoldToConfirm (Pro) steps in tenths under reduced motion.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Primitives&lt;/h3&gt;&lt;p&gt;The Radix-based ones take Radix's &lt;code&gt;asChild&lt;/code&gt; and Base UI's &lt;code&gt;render&lt;/code&gt;; all respect &lt;code&gt;data-motion&lt;/code&gt;, put their words through &lt;code&gt;LocaleProvider&lt;/code&gt;, and lock rather than disable. Nothing is pre-selected.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Free:&lt;/strong&gt; &lt;code&gt;checkbox&lt;/code&gt; (the tick draws only after the person changes it), &lt;code&gt;switch&lt;/code&gt;, &lt;code&gt;slider&lt;/code&gt; (position follows the pointer with no easing; &lt;code&gt;locked&lt;/code&gt; keeps it focusable and says why, and &lt;code&gt;thumbLabels&lt;/code&gt; names the thumbs), &lt;code&gt;progress&lt;/code&gt; (moves only between the values it is given; with no value it is indeterminate rather than a guessed fraction), &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;alert&lt;/code&gt; (&lt;code&gt;destructive&lt;/code&gt; is &lt;code&gt;role=&amp;quot;alert&amp;quot;&lt;/code&gt;, the rest &lt;code&gt;role=&amp;quot;status&amp;quot;&lt;/code&gt;) and &lt;code&gt;accordion&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Pro:&lt;/strong&gt; &lt;code&gt;toggle&lt;/code&gt; and &lt;code&gt;toggle-group&lt;/code&gt; (the highlight slides to the chosen item), &lt;code&gt;alert-dialog&lt;/code&gt; (focus starts on Cancel; the &lt;code&gt;irreversible&lt;/code&gt; prop prints what can't be undone and ties it to the action), &lt;code&gt;drawer&lt;/code&gt; (follows the pointer one to one when dragged, no &lt;code&gt;vaul&lt;/code&gt;; &lt;code&gt;onDismissAttempt&lt;/code&gt; runs before Escape, an outside click or a drag closes it and can keep it open), &lt;code&gt;menubar&lt;/code&gt;, &lt;code&gt;context-menu&lt;/code&gt; and &lt;code&gt;navigation-menu&lt;/code&gt; (submenus open from their trigger; items take &lt;code&gt;locked&lt;/code&gt; with the reason beside them), &lt;code&gt;breadcrumb&lt;/code&gt;, &lt;code&gt;pagination&lt;/code&gt; (&lt;code&gt;PaginationRange&lt;/code&gt; says nothing about a total it wasn't given; &lt;code&gt;pageWindow&lt;/code&gt; picks the page numbers to draw), &lt;code&gt;table&lt;/code&gt; (the plain table beside &lt;code&gt;data-table&lt;/code&gt;; its scrolling box is a tab stop), &lt;code&gt;stepper&lt;/code&gt; (a step is done only when your app says so; the tick and rail animate when that happens on screen), &lt;code&gt;calendar&lt;/code&gt; and &lt;code&gt;date-picker&lt;/code&gt; (months, weekdays and digits from the locale, via &lt;code&gt;Intl&lt;/code&gt;, no &lt;code&gt;react-day-picker&lt;/code&gt;; unavailable days say why; presets print their exact date), &lt;code&gt;combobox&lt;/code&gt; (never invents an option; server search shows &amp;quot;Searching…&amp;quot;, results fade in only after the first draw) and &lt;code&gt;carousel&lt;/code&gt; (scroll-snap, &amp;quot;3 of 8&amp;quot;, no auto-advance unless you set &lt;code&gt;interval&lt;/code&gt;, and it pauses on hover, focus, reduced motion and &lt;code&gt;data-motion=&amp;quot;none&amp;quot;&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;No new npm dependencies.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs and rules&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The accessibility statement, the Principles page's ninth rule, the design reference and the agent-UI skill describe the fourteen families, their variants, who decides (the OS, then the app, then the brand) and the calm level. The release runbook lists &lt;code&gt;check:motion&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;internal/PLAN-3.0.md&lt;/code&gt; opens the ledger of agreed breaking changes for a future 3.0, each with its migration.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.9.1&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;audit&lt;/code&gt; reads the page as someone who asked for reduced motion: &lt;code&gt;infinite-animation&lt;/code&gt; names what still loops, and the new &lt;code&gt;calm-motion&lt;/code&gt; names transform, translate, scale, rotate and height animations and transitions that still run.&lt;/li&gt;&lt;li&gt;&lt;code&gt;lint&lt;/code&gt; warns (&lt;code&gt;motion-hardcoded&lt;/code&gt;) about raw durations, &lt;code&gt;tw-animate&lt;/code&gt; classes and &lt;code&gt;transition-all&lt;/code&gt; in files that use Candor components, and points at the motion families.&lt;/li&gt;&lt;li&gt;&lt;code&gt;doctor&lt;/code&gt;'s clash check knows the new primitives.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.2.0</title>
      <link>https://candor.themethodic.com/changelog#2-2-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-2-0</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Theming from the terminal and a gallery of vetted themes, an audit command, the 2.0 and 2.1 review leftovers, a changelog feed and the policy pages, and the reach pieces: skills publishing and open-in-sandbox buttons. With CLI 0.9.0; &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.2.0 carries the free changes.&lt;/p&gt;&lt;h3&gt;Theming&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Theme gallery&lt;/strong&gt; at &lt;code&gt;/themes&lt;/code&gt; (free): four vetted looks beside the default, Slate (cool neutrals, blue accent), Paper (warm off-whites, ink text, terracotta accent), Console (dark-first, dense, green status accent) and Signal (a higher-saturation accent), each defined as colour data in &lt;code&gt;scripts/theme.mjs&lt;/code&gt;, checked for every pairing in light, dark and high contrast like the default (CI fails if one fails), and shipped as the registry items &lt;code&gt;theme-slate&lt;/code&gt;, &lt;code&gt;theme-paper&lt;/code&gt;, &lt;code&gt;theme-console&lt;/code&gt;, &lt;code&gt;theme-signal&lt;/code&gt;: an override file imported after &lt;code&gt;candor.css&lt;/code&gt;. The page previews the same components in each, with the measured totals, the install command and a download; the site's &amp;quot;132 checks&amp;quot; number still counts the default theme, the gallery's own checks are shown on its page.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CLI 0.9.0, &lt;code&gt;candor-ui theme check [file]&lt;/code&gt;&lt;/strong&gt;: reads your overrides on top of Candor's theme, resolves the colour roles per theme the way &lt;code&gt;candor.css&lt;/code&gt; does, and reports every pairing's measured contrast and pass/fail with totals (exit 1 on a failure; &lt;code&gt;--json&lt;/code&gt;); it changes nothing. &lt;strong&gt;&lt;code&gt;candor-ui theme from &amp;lt;source&amp;gt;&lt;/code&gt;&lt;/strong&gt; turns existing brand tokens (a shadcn &lt;code&gt;globals.css&lt;/code&gt;, a Tailwind config, or a Figma variables export) into a &lt;code&gt;candor-brand.css&lt;/code&gt; override file, runs the check, and prints failures with the nearest passing lightness as a suggestion, never applied; writes only with &lt;code&gt;--out&lt;/code&gt;. The contrast module is a copy of &lt;code&gt;src/lib/contrast.ts&lt;/code&gt;, with a test that fails if the two drift.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Checking an app&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;CLI 0.9.0, &lt;code&gt;candor-ui audit [path|url]&lt;/code&gt;&lt;/strong&gt;: with a path, runs &lt;code&gt;lint&lt;/code&gt;; with a URL, if Playwright and axe-core resolve from the project, loads the page, runs axe, and checks the honesty rules visible in the DOM (disabled controls without a reason, pre-checked decisions, animations that loop, model-looking external links in messages). Writes &lt;code&gt;AUDIT.md&lt;/code&gt; grouped by principle; exit 1 on an error-level finding; &lt;code&gt;--json&lt;/code&gt;. Without Playwright or axe it says &amp;quot;page not audited: install …&amp;quot;, still lints the project, and exits 2, so a CI step doesn't pass on an unaudited page.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui list --installed&lt;/code&gt;&lt;/strong&gt; says &amp;quot;kit x.y.z available; this item unchanged since a.b.c&amp;quot; when the item itself did not change, instead of &amp;quot;x available&amp;quot;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;/changelog.xml&lt;/code&gt;&lt;/strong&gt;: a feed with one entry per released version, linked from the changelog page and its &lt;code&gt;&amp;lt;link rel=&amp;quot;alternate&amp;quot;&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;/dpa&lt;/code&gt;, &lt;code&gt;/gdpr&lt;/code&gt;, &lt;code&gt;/licence-key&lt;/code&gt;&lt;/strong&gt;: a data-processing statement and GDPR notes true to how Candor works (the registry sees a key and an IP for rate limiting and stores nothing; Polar processes purchases), and a page for buyers about the licence key: where it is, how to set it, what each tier covers, how a refund affects it, how a team shares it. A &amp;quot;Legal&amp;quot; group in the footer.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&amp;quot;Open in StackBlitz&amp;quot;&lt;/strong&gt; on free items' docs pages opens the public starter in StackBlitz (it does not yet pre-add the item; the install command is beside it).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Example screenshots&lt;/strong&gt;: &lt;code&gt;scripts/screenshots.mjs&lt;/code&gt; renders the templates and gallery pages in light, dark and high contrast at desktop and phone widths with Playwright, and &lt;code&gt;/examples&lt;/code&gt; shows them with alt text. Not run in CI.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Skills publishing&lt;/strong&gt;: &lt;code&gt;scripts/skills-publish.mjs&lt;/code&gt; validates both skills' frontmatter for the skills.sh registry and prints the publish commands; &lt;code&gt;docs/RELEASING.md&lt;/code&gt; step 8 names it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Review leftovers from 2.0 and 2.1&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;compare-slider&lt;/strong&gt;: the clipped side is inert, so keyboard focus can't reach controls that aren't visible.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;details-list&lt;/strong&gt;: folded rows stay in the DOM, hidden, so find-in-page reaches them; the doc comment says a group the person must read before confirming stays open.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;session-list&lt;/strong&gt;: the unread dot's name is visually hidden text, not an &lt;code&gt;aria-label&lt;/code&gt; on a span.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Honest vs. typical&lt;/strong&gt;: the estimate example's Start runs a scripted run to a measured result.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Theme builder&lt;/strong&gt;: &lt;code&gt;apply&lt;/code&gt; uses a functional update; the 2× cap on accent strength is shown beside the control.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Roadmap&lt;/strong&gt;: the shipped items leave &amp;quot;In progress&amp;quot;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Assessed, not built&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Managed Agents adapter&lt;/strong&gt;: still beta with no stable event shapes as of 2026-11-08 (&lt;code&gt;internal/MANAGED-AGENTS-2026-11.md&lt;/code&gt; has the evidence); the adapter waits for stable shapes.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.1.0</title>
      <link>https://candor.themethodic.com/changelog#2-1-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-1-0</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Storywrite's agreement card and two SessionList fixes. With CLI 0.8.1; &lt;code&gt;@candor-ui/react&lt;/code&gt; 2.1.0 carries the free change (RelativeTime). Nothing you installed needs changing.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;details-list&lt;/strong&gt; (new, Pro; Storywrite ask 35): &lt;code&gt;DetailsList&lt;/code&gt;, titled groups of label-and-value rows for a card where a person reads and confirms how something will be built and checked: install commands, checks with time limits, services with image, port and health, risky paths. Each group is a real description list (&lt;code&gt;dl&lt;/code&gt;, &lt;code&gt;dt&lt;/code&gt;, &lt;code&gt;dd&lt;/code&gt;) under a heading button with &lt;code&gt;aria-expanded&lt;/code&gt;, folds away, and can show a &lt;code&gt;summary&lt;/code&gt; while folded (&amp;quot;3 checks, 2 with time limits&amp;quot;); &lt;code&gt;collapsible&lt;/code&gt; and &lt;code&gt;defaultOpen&lt;/code&gt; say which. A &lt;code&gt;command&lt;/code&gt; value is monospace, wraps, and has a copy control that says &amp;quot;Copied&amp;quot; only after the clipboard took it; &lt;code&gt;code&lt;/code&gt; is the same without the control; a &lt;code&gt;link&lt;/code&gt; is followed only inside the app; an unknown value shows as &amp;quot;Not known&amp;quot;. &lt;code&gt;AttributesRail&lt;/code&gt; stays the flat sibling. Install with &lt;code&gt;npx candor-ui add details-list&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;session-list&lt;/strong&gt; (Pro; Storywrite ask 33): a row's time faded out on hover even when the row had no &lt;code&gt;onRename&lt;/code&gt;, &lt;code&gt;onPin&lt;/code&gt; or &lt;code&gt;onDelete&lt;/code&gt;, leaving a blank where nothing replaced it. It now gives way only when there is a menu button to take its place.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;session-list, relative-time&lt;/strong&gt; (SessionList is Pro, RelativeTime is free; Storywrite ask 34): a row's link was named &amp;quot;Thread title 2 days&amp;quot;, the bare time without its direction. &lt;code&gt;RelativeTime&lt;/code&gt; with &lt;code&gt;bare&lt;/code&gt; still draws &amp;quot;2 days&amp;quot; and now also names the whole phrase, &amp;quot;2 days ago&amp;quot;, to a screen reader, in the locale; so the row's link reads &amp;quot;Thread title 2 days ago&amp;quot;, and every other bare time benefits. The spoken phrase is visually hidden text inside the &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt;, so a bare time's &lt;code&gt;textContent&lt;/code&gt; now holds it as well as the short form (&amp;quot;2 days2 days ago&amp;quot;); a test that reads &lt;code&gt;textContent&lt;/code&gt; should match on the short form or query the element it means. Update with &lt;code&gt;npx candor-ui update session-list relative-time&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CLI 0.8.1&lt;/strong&gt;: &lt;code&gt;candor-ui lint&lt;/code&gt; knows &lt;code&gt;DetailsList&lt;/code&gt; as a Candor component, so a file that uses only it counts as using Candor.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 2.0.0</title>
      <link>https://candor.themethodic.com/changelog#2-0-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#2-0-0</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The platform release: a theme builder that checks contrast as you brand it, a catalogue of agent screens with variations, more starters, an interactive Honest vs. typical gallery, a roadmap, and &lt;code&gt;candor-ui list&lt;/code&gt; and &lt;code&gt;search&lt;/code&gt;. With CLI 0.8.0. It is a major version because of the platform step, not because anything broke: the theme builder, the screen catalogue, the starters and CLI browsing make Candor a platform rather than a kit. No installed code changes meaning, and nothing you installed needs changing. &lt;code&gt;@candor-ui/react&lt;/code&gt; moves to 2.0.0 with the kit.&lt;/p&gt;&lt;h3&gt;For people choosing and branding Candor&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Theme builder&lt;/strong&gt; at &lt;code&gt;/theme-builder&lt;/code&gt; (free): brand Candor with your primary and accent colours, greys, font, radius and density, see real components in light, dark and high contrast, and read the full contrast report: the same 44 pairings per theme that &lt;code&gt;npm run theme&lt;/code&gt; checks, now in &lt;code&gt;src/lib/contrast.ts&lt;/code&gt; and shared by the script and the site. Nothing is fixed for you silently; failing pairings are named with a passing lightness you can apply. Download &lt;code&gt;candor-brand.css&lt;/code&gt; (overrides after the &lt;code&gt;candor.css&lt;/code&gt; import, with the result in its header) or copy a &lt;code&gt;DESIGN.md&lt;/code&gt; addendum. Everything stays in the browser.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Screen catalogue&lt;/strong&gt; at &lt;code&gt;/screens&lt;/code&gt; (docs): 22 screens an agent product needs, 63 layouts with wireframes, each with when to pick it, the items it uses with their tiers, the honesty rules that matter most there, an install command and a brief a coding agent can take. Also as Markdown at &lt;code&gt;/screens/&amp;lt;slug&amp;gt;.md&lt;/code&gt;, in &lt;code&gt;llms.txt&lt;/code&gt;, and in the docs MCP as &lt;code&gt;get_screen&lt;/code&gt; and &lt;code&gt;list_screens&lt;/code&gt;; &lt;code&gt;suggest_components&lt;/code&gt; names matching screens.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Honest vs. typical&lt;/strong&gt; is a gallery: each moment has a Typical / Honest switch that swaps a live example in place, with the rule it illustrates linked; five more moments (an estimate shown as measured, a disabled control versus a locked one, markdown with a model-written link, a pre-selected Approve, &amp;quot;Deleted&amp;quot; without what stays).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Roadmap&lt;/strong&gt; at &lt;code&gt;/roadmap&lt;/code&gt;: in progress, next and later, with no dates; the changelog stays the record.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Starters&lt;/strong&gt;: &lt;code&gt;starters/vite-ag-ui&lt;/code&gt; (Vite + React 19 + the AG-UI adapter, with a scripted in-browser run when no agent URL is set) and &lt;code&gt;starters/tanstack-start-claude&lt;/code&gt; (TanStack Start + the Claude Agent SDK adapter, the same to-do agent as the Next starter). &lt;code&gt;scripts/sync-starter.mjs&lt;/code&gt; refreshes all three; the public repo publishes them as &lt;code&gt;starter-vite-ag-ui/&lt;/code&gt; and &lt;code&gt;starter-tanstack-start-claude/&lt;/code&gt; beside &lt;code&gt;starter/&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.8.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui list [--tier] [--group] [--installed] [--json]&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;search &amp;lt;words…&amp;gt;&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;info &amp;lt;item&amp;gt;&lt;/code&gt;&lt;/strong&gt; read the site's docs index, so a person or an agent can find an item from the terminal; &lt;code&gt;--installed&lt;/code&gt; marks what &lt;code&gt;candor-lock.json&lt;/code&gt; has and whether a newer version exists; an unknown name suggests the item that exports it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Free items&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;font-source-sans&lt;/strong&gt;, &lt;strong&gt;font-ibm-plex&lt;/strong&gt; (new): Source Sans 3 and IBM Plex Sans, self-hosted (OFL), beside Inter; import next to &lt;code&gt;candor.css&lt;/code&gt; like &lt;code&gt;font-inter&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;theme&lt;/strong&gt;: a &lt;code&gt;spacious&lt;/code&gt; density preset, &lt;code&gt;data-density=&amp;quot;spacious&amp;quot;&lt;/code&gt;, the other way from &lt;code&gt;compact&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Pro items&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;compare-slider&lt;/strong&gt; (new): &lt;code&gt;CompareSlider&lt;/code&gt;, two versions under one draggable divider, both labelled so neither reads as the better one; a real slider (arrow keys 1%, Shift 10%, Home/End); a &lt;code&gt;caption&lt;/code&gt; says what is compared and where it came from.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;run-scrubber&lt;/strong&gt; (new): &lt;code&gt;RunScrubber&lt;/code&gt;, a timeline for replaying a run at its real timestamps: ticks where the events were, a thumb the person drags or steps with the keyboard, the current event beside it, &lt;code&gt;onChange(index)&lt;/code&gt; for the app's own trace or log, and play at the measured intervals (speed labelled), stopping at the end; two events at one timestamp say so.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;hubspot-kinds&lt;/strong&gt;, &lt;strong&gt;github-kinds&lt;/strong&gt;, &lt;strong&gt;jira-kinds&lt;/strong&gt;, &lt;strong&gt;linear-kinds&lt;/strong&gt; (new presets): each product's main objects as entity kinds with icons and nouns, named as the product names them, and a &lt;code&gt;TermsProvider&lt;/code&gt; preset where its words differ; like &lt;code&gt;salesforce-kinds&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Repo&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;docs/RELEASING.md&lt;/code&gt; publishes the MCP registry entry (&lt;code&gt;com.themethodic/candor&lt;/code&gt;) with each version.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.9.1</title>
      <link>https://candor.themethodic.com/changelog#1-9-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-9-1</guid>
      <pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Fixes from the 1.9.0 review that could wait a week: motion edge cases, UndoWindow at expiry, useAttention while focused, and a motion scenario on the Honest vs. typical page. With CLI 0.7.1; &lt;code&gt;@candor-ui/react&lt;/code&gt; 1.9.1 carries the free changes.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;composer&lt;/strong&gt;: a chip removed and added back within the ghost's 400 ms no longer shows a ghost beside the real chip.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;permission-prompt&lt;/strong&gt;: a press inside another prompt no longer nudges this one; only a press on inert space outside every prompt does. An outside press still never counts as deny.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;use-attention&lt;/strong&gt;: stays quiet (no title badge, no notification) while the window is focused and visible, and counts by kind: the hook returns &lt;code&gt;AttentionWithCounts&lt;/code&gt;, &lt;code&gt;Attention&lt;/code&gt; plus &lt;code&gt;counts&lt;/code&gt; (the number waiting per &lt;code&gt;kind&lt;/code&gt;); the &lt;code&gt;Attention&lt;/code&gt; type itself is unchanged, so code that builds one by hand still compiles.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;undo-window&lt;/strong&gt;: when the window closes while a failure message is showing, it says &amp;quot;Can't be undone now.&amp;quot; and fires &lt;code&gt;onClose&lt;/code&gt;; the server and the client render the same first frame; after a failed undo with time left, Undo stays for a retry.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;step-list, tool-call, undo-window&lt;/strong&gt;: under reduced motion or &lt;code&gt;data-motion=&amp;quot;none&amp;quot;&lt;/code&gt; no animation delay remains (the cross's second stroke drew after 120 ms).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;thread&lt;/strong&gt;: &amp;quot;Jump to latest&amp;quot; pulses for any new message, however the messages are nested, once per arrival.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Site&lt;/strong&gt;: Honest vs. typical gains a fifth moment, &amp;quot;A tick before the clipboard answered&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CLI 0.7.1&lt;/strong&gt;: &lt;code&gt;lint&lt;/code&gt;'s &lt;code&gt;estimate-as-measured&lt;/code&gt; also reaches props ending in Ms, Seconds, Minutes, Duration, Cost, Tokens or Count (your own wrappers' props, since no Candor component has most of them), keys inside an object literal such as &lt;code&gt;call={{ durationMs: … }}&lt;/code&gt;, and template literals that multiply by a rate (&lt;code&gt;${tokens * 0.002}&lt;/code&gt;). Exact unit changes and counts (&lt;code&gt;* 1000&lt;/code&gt;, &lt;code&gt;* 0.001&lt;/code&gt;, &lt;code&gt;pages * perPage&lt;/code&gt;) are not flagged, and &lt;code&gt;settledCount&lt;/code&gt; and &lt;code&gt;retryCount&lt;/code&gt; are checked. Candor's own source still has no finding.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.9.0</title>
      <link>https://candor.themethodic.com/changelog#1-9-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-9-0</guid>
      <pubDate>Sat, 07 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Reach and rigour: setup for every coding tool, a design system and fundamentals agents read, a lint for the honesty rules, honest motion, and components for the moments after an agent acts. With CLI 0.7.0; &lt;code&gt;@candor-ui/react&lt;/code&gt; 1.9.0 carries the free changes.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;A ninth principle: motion follows the outcome.&lt;/strong&gt; Motion reports a change that happened and never predicts or decorates one. A success mark is drawn after the result settles, a rail fills only to the step that finished, and a state that was already final when the page drew does not animate. The Principles page has it.&lt;/p&gt;&lt;h3&gt;For coding agents and their tools&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Setup guides&lt;/strong&gt; at &lt;code&gt;/guides&lt;/code&gt;, one per tool: Claude Code, Cursor, Codex, VS Code with Copilot, Windsurf, Zed, Cline, OpenCode, JetBrains, v0, Lovable and Replit. Each gives the registry, the docs MCP server in that tool's own config (verified against the tool's documentation), the skill or the brief, and an example prompt. Linked from Get started, the footer and &lt;code&gt;llms.txt&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Plugins.&lt;/strong&gt; Claude Code: &lt;code&gt;claude plugin marketplace add MethodicDev/candor&lt;/code&gt;, then &lt;code&gt;claude plugin install candor-ui@candor&lt;/code&gt; installs the skill and the docs MCP server together (&lt;code&gt;.claude-plugin/&lt;/code&gt;). Cursor, Codex and VS Code / Copilot packages under &lt;code&gt;plugins/&lt;/code&gt;, with &lt;code&gt;.cursor-plugin/marketplace.json&lt;/code&gt; and &lt;code&gt;.github/plugin/marketplace.json&lt;/code&gt; (&lt;code&gt;copilot plugin install candor-ui@candor&lt;/code&gt;). &lt;code&gt;.mcp/server.json&lt;/code&gt; describes the docs MCP server for the MCP registry (&lt;code&gt;com.themethodic/candor&lt;/code&gt;, remote, no auth). Every description says the server is docs-only and keyless. &lt;code&gt;llms-install.md&lt;/code&gt; tells an agent how to set all of it up by itself. The public repo carries them.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A second skill, &lt;code&gt;skills/candor-agent-ui&lt;/code&gt;&lt;/strong&gt; (MIT, &lt;code&gt;npx skills add MethodicDev/candor&lt;/code&gt;): design fundamentals for screens where an AI agent acts, in any framework and design system: the nine honesty rules with examples, approval ergonomics, the status vocabulary and the states of a tool call, folding turns, progress and finishing while away, blast radius and undo, AI disclosure, accessibility, and a &lt;strong&gt;review checklist&lt;/strong&gt; to run after each screen.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A design system agents read&lt;/strong&gt;: &lt;code&gt;skills/candor-ui/references/design.md&lt;/code&gt; and &lt;code&gt;/design.md&lt;/code&gt;, generated from the shipped CSS by &lt;code&gt;scripts/build-design.mjs&lt;/code&gt; (every colour role and what it's for, the type scale, radius, shadows, motion, density, themes, how to re-token for a brand, and a do/don't per honesty rule); checked fresh in CI. The &lt;code&gt;candor-ui&lt;/code&gt; skill gains an &amp;quot;After each screen&amp;quot; section pointing at the checklist and design.md.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Docs MCP&lt;/strong&gt;: new tools &lt;code&gt;get_design&lt;/code&gt;, &lt;code&gt;get_review_checklist&lt;/code&gt; and &lt;code&gt;get_brief&lt;/code&gt; (an item's brief, the same text the docs page's &amp;quot;Copy for a coding agent&amp;quot; copies).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI 0.7.0&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui mcp &amp;lt;tool&amp;gt;&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;init --mcp &amp;lt;tool&amp;gt;&lt;/code&gt;&lt;/strong&gt; add the docs MCP server (&lt;code&gt;https://candor.themethodic.com/mcp&lt;/code&gt;, read-only, no key) as a server named &lt;code&gt;candor&lt;/code&gt; to a tool's project-level config: Claude Code (&lt;code&gt;.mcp.json&lt;/code&gt;), Cursor (&lt;code&gt;.cursor/mcp.json&lt;/code&gt;), Codex (&lt;code&gt;.codex/config.toml&lt;/code&gt;), VS Code (&lt;code&gt;.vscode/mcp.json&lt;/code&gt;) and OpenCode (&lt;code&gt;opencode.json&lt;/code&gt;). Existing servers, comments and formatting are kept, running it twice changes nothing, and &lt;code&gt;doctor&lt;/code&gt; says which tools have it. Zed, Windsurf and Cline have no documented project-level file, so the command names them and points at their settings.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui lint [paths…]&lt;/code&gt;&lt;/strong&gt; checks an app's &lt;code&gt;.tsx/.ts/.jsx/.js&lt;/code&gt; files against the honesty rules: &lt;code&gt;model-html&lt;/code&gt; (error: HTML rendered from a string in a file that shows a chat), &lt;code&gt;disabled-without-reason&lt;/code&gt;, &lt;code&gt;preselected-decision&lt;/code&gt; and &lt;code&gt;estimate-as-measured&lt;/code&gt; (warnings). Prints &lt;code&gt;path:line:col  rule  message&lt;/code&gt;, exits 1 on an error; &lt;code&gt;--strict&lt;/code&gt; fails on warnings, &lt;code&gt;--json&lt;/code&gt; for machines. Each rule is documented in the CLI README with the principle it serves. Candor's own source (the registry, blocks, templates, starter, site and docs examples) passes with one warning.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Free items&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;theme&lt;/strong&gt;: &lt;code&gt;data-motion=&amp;quot;none&amp;quot; | &amp;quot;subtle&amp;quot; | &amp;quot;expressive&amp;quot;&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or any container, like &lt;code&gt;data-theme&lt;/code&gt;. Subtle is the default and today's behaviour; none turns every animation and transition off, with or without the OS setting; expressive scales pops and lets a pressed locked control shake. Duration tokens &lt;code&gt;--cd-dur-quick&lt;/code&gt;, &lt;code&gt;--cd-dur-base&lt;/code&gt;, &lt;code&gt;--cd-dur-slow&lt;/code&gt; (use as &lt;code&gt;duration-(--cd-dur-base)&lt;/code&gt;), and keyframes &lt;code&gt;collapse-down&lt;/code&gt;, &lt;code&gt;collapse-up&lt;/code&gt;, &lt;code&gt;pop-in&lt;/code&gt;, &lt;code&gt;pop-out&lt;/code&gt;, &lt;code&gt;tick-draw&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;shake&lt;/code&gt;, &lt;code&gt;attention&lt;/code&gt;. The reduced-motion rule stays last and wins. No new props anywhere in this list.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;collapsible&lt;/strong&gt;: content opens and closes to its measured height; &lt;code&gt;ToolCall&lt;/code&gt;, &lt;code&gt;Reasoning&lt;/code&gt;, &lt;code&gt;FoldedTurns&lt;/code&gt; and a card's summary inherit it. Nothing moves on content that mounts open.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;tool-call, step-list, status-dot&lt;/strong&gt;: a mark whose status reaches done or failed while on screen draws its tick or cross; one that mounts finished is drawn still. &lt;code&gt;StepList&lt;/code&gt;'s rail fills under a finished step, never ahead of it. &lt;code&gt;StatusDot&lt;/code&gt; pops into its final colour (too small for a drawn mark).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;message-actions, copy-field&lt;/strong&gt;: the copy icon stays until the clipboard write settles, then the tick (copied) or cross (failed) appears; &lt;code&gt;data-copy&lt;/code&gt; carries the state.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;context-meter&lt;/strong&gt;: the ring sweeps to a new measured count and changes colour at the 80% line; neither the first render nor server markup sweeps from zero.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;composer&lt;/strong&gt;: mention and attachment chips added after the first draw pop in; a removed chip pops out as an inert ghost, hidden outright under &lt;code&gt;data-motion=&amp;quot;none&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;locked&lt;/strong&gt;: pressing a locked control keeps its reason open and emphasises a printed one; the shake exists only under &lt;code&gt;data-motion=&amp;quot;expressive&amp;quot;&lt;/code&gt;. Activation stays blocked.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;permission-prompt&lt;/strong&gt;: pulses three times when a decision arrives, then stays still (and not at all while &lt;code&gt;busy&lt;/code&gt;). A press on inert space outside it, the gesture that would dismiss a dialog, nudges it instead; nothing but Allow or Deny is ever a decision, as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;thread&lt;/strong&gt;: &amp;quot;Jump to latest&amp;quot; pulses once each time a message arrives while the reader is scrolled up, then stays still; the jump scrolls instantly under reduced motion or &lt;code&gt;data-motion=&amp;quot;none&amp;quot;&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Pro items&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;hold-to-confirm&lt;/strong&gt; (new): &lt;code&gt;HoldToConfirm&lt;/code&gt;, a button held, by pointer or with Space or Enter, for &lt;code&gt;holdMs&lt;/code&gt; (1200 unless the app says otherwise) before &lt;code&gt;onConfirm&lt;/code&gt; fires. The bar fills from the clock; letting go early cancels and says so. The required &lt;code&gt;reason&lt;/code&gt; (what it does, whether it can be undone) is read with the button; &lt;code&gt;locked&lt;/code&gt; says why. Nothing pre-armed, no one-key path, never auto-focused.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;undo-window&lt;/strong&gt; (new): &lt;code&gt;UndoWindow&lt;/code&gt;, an action just taken with Undo for exactly the window the server granted (&lt;code&gt;until&lt;/code&gt; or &lt;code&gt;seconds&lt;/code&gt;; no default, so without either the app's &lt;code&gt;cannotUndo&lt;/code&gt; text shows and there is no Undo). Time left is read from the clock, so a slept tab catches up. Pending until &lt;code&gt;onUndo&lt;/code&gt; settles, then &amp;quot;Undone.&amp;quot; or &amp;quot;Couldn't undo: &amp;lt;the rejection's reason&amp;gt;&amp;quot;; when the window closes, &amp;quot;Can't be undone now.&amp;quot; with what happened kept.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;use-attention&lt;/strong&gt; (new): &lt;code&gt;useAttention&lt;/code&gt;, a count and a &amp;quot;(n) &amp;quot; title badge for what waits on a person or finished while they were away, cleared on focus, on the tab becoming visible, or by &lt;code&gt;clear()&lt;/code&gt;. System notifications only with &lt;code&gt;notify&lt;/code&gt; on and permission already granted (the hook never asks; &lt;code&gt;requestPermission()&lt;/code&gt; is for the app's own button); sound only with a &lt;code&gt;src&lt;/code&gt; the app passed and &lt;code&gt;enabled: true&lt;/code&gt;. SSR-safe.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site and repo&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Home page: a &amp;quot;Built with Candor&amp;quot; strip naming OrgSmith and StoryWright as Methodic's products on Candor, and Methodic as a Salesforce consulting and AppExchange partner.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SECURITY.md&lt;/code&gt;: how to report a vulnerability privately, what's in scope, and how fixes reach installed components (&lt;code&gt;npx candor-ui update&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;The README quotes the measured counts; CI fails if the README or the Polar copy disagrees with &lt;code&gt;src/site/stats.json&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;docs/RELEASING.md&lt;/code&gt; is the release runbook, &lt;code&gt;CLAUDE.md&lt;/code&gt; the repo's standing instructions, and &lt;code&gt;npm run release:check&lt;/code&gt; runs CI's checks locally with a preflight on the version, the CHANGELOG and the package versions.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.8.1</title>
      <link>https://candor.themethodic.com/changelog#1-8-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-8-1</guid>
      <pubDate>Fri, 06 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Three accessibility and theming fixes a customer found in 1.8. No new props.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;CommandPalette&lt;/code&gt;: the search box also carries &lt;code&gt;aria-label&lt;/code&gt; (the &lt;code&gt;search&lt;/code&gt; string). In 1.8 it was named only by cmdk's label, hidden with &lt;code&gt;display: none&lt;/code&gt;; Chromium follows that through &lt;code&gt;aria-labelledby&lt;/code&gt;, but not every accessibility tree does, and there the box had no name.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SessionList&lt;/code&gt;: each group (&amp;quot;Today&amp;quot;, or your own &amp;quot;Needs you&amp;quot;, &amp;quot;Projects&amp;quot;) is a group named by its heading, so a screen reader can move between groups and says which one a row is in. This holds with &lt;code&gt;virtualize&lt;/code&gt; too, where a group's heading can be outside the rendered rows. The visible heading is hidden from screen readers so it isn't read twice.&lt;/li&gt;&lt;li&gt;&lt;code&gt;AppLayout&lt;/code&gt;: the panel's sheet is 448px wide (&lt;code&gt;max-w-md&lt;/code&gt;), as it was meant to be. The sheet primitive's own &lt;code&gt;sm:max-w-sm&lt;/code&gt; (384px) had won at every width the panel is a sheet.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.8.0</title>
      <link>https://candor.themethodic.com/changelog#1-8-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-8-0</guid>
      <pubDate>Fri, 06 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Links where things navigate, a palette and composer that say only what's true, agents that ask mid-call and connect to new servers, and plans that say when a run left them. New optional props and CLI 0.6.0; no breaking changes.&lt;/p&gt;&lt;h3&gt;Shell and composer: a customer's asks&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;SessionList&lt;/code&gt;: a session with &lt;code&gt;href&lt;/code&gt; (new on &lt;code&gt;Session&lt;/code&gt;) is a real link, so it opens in a new tab, its address can be copied, and the open one is the current page to a screen reader. A plain click still goes through &lt;code&gt;onOpen&lt;/code&gt; for your router; other clicks are the browser's. Without &lt;code&gt;href&lt;/code&gt;, rows are buttons as before.&lt;/li&gt;&lt;li&gt;&lt;code&gt;AppLayout&lt;/code&gt;: &lt;code&gt;navOpen&lt;/code&gt; and &lt;code&gt;onNavOpenChange&lt;/code&gt; control the sidebar sheet, so the app can close it when the person navigates. &lt;code&gt;navButton={false}&lt;/code&gt; drops the built-in menu button for an app with its own top bar. The frame carries &lt;code&gt;data-nav&lt;/code&gt; (&amp;quot;rail&amp;quot; or &amp;quot;sheet&amp;quot;) and &lt;code&gt;group/app-layout&lt;/code&gt;, so your own button can show only while the sidebar is a sheet (&lt;code&gt;group-data-[nav=rail]/app-layout:hidden&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;code&gt;CommandPalette&lt;/code&gt; is named once: the dialog by its title, the search box &amp;quot;Search&amp;quot; and the list &amp;quot;Results&amp;quot; (new strings &lt;code&gt;search&lt;/code&gt; and &lt;code&gt;results&lt;/code&gt;). Before, a screen reader heard the title three times before the first item, and the list's name was cmdk's English &amp;quot;Suggestions&amp;quot; whatever the locale.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Composer&lt;/code&gt;'s keyboard hints name only what's on: &amp;quot;@ mention&amp;quot; only with &lt;code&gt;mentions&lt;/code&gt;, &amp;quot;/ command&amp;quot; (new string &lt;code&gt;hintCommand&lt;/code&gt;) only with &lt;code&gt;commands&lt;/code&gt;. &lt;code&gt;hints={false}&lt;/code&gt; hides them.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Plan drift and autonomy (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Plan&lt;/code&gt;: &lt;strong&gt;drift&lt;/strong&gt;. A step can say how the run left the approved plan, with &lt;code&gt;drift&lt;/code&gt; on &lt;code&gt;PlanStep&lt;/code&gt; (&lt;code&gt;{ kind: &amp;quot;added&amp;quot; | &amp;quot;skipped&amp;quot; | &amp;quot;changed&amp;quot;, note?, from? }&lt;/code&gt;), from your app's own records. Candor never works drift out by itself. - Each drifted step says so in words: &amp;quot;Added during the run, not in the approved plan&amp;quot;, &amp;quot;Skipped by the run, though it was approved&amp;quot; or &amp;quot;Changed from the approved plan&amp;quot;. A changed step can say what was approved (&amp;quot;Approved as: Backfill from billing country&amp;quot;), and any step can say why (&lt;code&gt;note&lt;/code&gt;). - A line above the steps counts them: &amp;quot;The run left the approved plan: 1 step added and 1 step skipped&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Plan&lt;/code&gt;: &lt;strong&gt;autonomy on accept&lt;/strong&gt;. With &lt;code&gt;autonomy&lt;/code&gt; (a list of &lt;code&gt;PlanAutonomyOption&lt;/code&gt;), accepting says what it allows. The person picks one before Accept is available; none is picked for them. &lt;code&gt;onAccept&lt;/code&gt; gets the choice as its second argument. - Two options have built-in words: &lt;code&gt;&amp;quot;askBeforeEdits&amp;quot;&lt;/code&gt; (&amp;quot;Ask before each edit&amp;quot;) and &lt;code&gt;&amp;quot;runWithoutAsking&amp;quot;&lt;/code&gt; (&amp;quot;Run without asking&amp;quot;). Your own take &lt;code&gt;label&lt;/code&gt; and &lt;code&gt;detail&lt;/code&gt;; &lt;code&gt;locked&lt;/code&gt; says why one can't be picked.&lt;/li&gt;&lt;li&gt;The new words are in &lt;code&gt;planStrings&lt;/code&gt;, so LocaleProvider can override them.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;New optional props and fields only: a plan without &lt;code&gt;drift&lt;/code&gt; or &lt;code&gt;autonomy&lt;/code&gt; looks and accepts exactly as before. &lt;code&gt;onAccept&lt;/code&gt; still gets the skipped steps first.&lt;/p&gt;&lt;h3&gt;MCP servers that ask, and connecting one&lt;/h3&gt;&lt;p&gt;MCP's 2026-07-28 revision stopped servers pushing questions at the client: a call that needs more comes back &amp;quot;input required&amp;quot;, and the client asks the person and retries the call with the answers. Candor shows those questions with the components that already ask people things, and gives the person a straight account of a server before connecting it.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;mcp-input&lt;/code&gt;&lt;/strong&gt; (free lib): an MCP &lt;code&gt;input_required&lt;/code&gt; result as Candor data, and the person's answers back as the retry. - &lt;code&gt;mcpInputView(result, { server })&lt;/code&gt; turns each of the server's &lt;code&gt;inputRequests&lt;/code&gt; into an item, in the server's order. A form (&lt;code&gt;elicitation/create&lt;/code&gt;) becomes questions in &lt;code&gt;ClarifyingQuestions&lt;/code&gt;' shape: an enum (with or without titles, single or multiple) a choice, a boolean Yes or No, text and numbers a line. A field's title becomes the tag when it also has a description. A form with no fields, a plain &amp;quot;go ahead?&amp;quot;, becomes a two-answer &lt;code&gt;Decision&lt;/code&gt; for &lt;code&gt;ApprovalDecision&lt;/code&gt;. - A link the server wants opened (URL mode: a sign-in, a payment) is a &lt;code&gt;Decision&lt;/code&gt; too, with the page's host and its full address as facts, and a warning for an encoded (&lt;code&gt;xn--&lt;/code&gt;) name or a page not on https. Nothing opens until the person accepts; an address that isn't http or https isn't offered at all. - The server's default is marked as its suggestion and never chosen for the person; a text field shows it as a hint and stays empty. A choice the server doesn't require offers &amp;quot;Leave unanswered&amp;quot; rather than assuming one. - What it can't show stays on screen as &amp;quot;not supported&amp;quot;, with the method and why: a model prompt (sampling), a request for folders (roots), a form with a field it can't draw, or a kind newer than this file. Nothing is dropped. Answer those yourself and pass them as &lt;code&gt;own&lt;/code&gt;. - &lt;code&gt;mcpInputResponses(view, replies)&lt;/code&gt; checks the answers against each form's schema first (required fields, choices, whole numbers, minimum and maximum, length, email, URL and date formats, how many to pick) and returns the problems in words, or the &lt;code&gt;inputResponses&lt;/code&gt; to send. Declined and dismissed requests are sent as such, and what wasn't sent is listed in &lt;code&gt;notSent&lt;/code&gt;. - &lt;code&gt;mcpRetryParams(original, view, inputResponses)&lt;/code&gt; is the original call's params with the answers and the server's &lt;code&gt;requestState&lt;/code&gt; exactly as it came, and without an earlier round's state when this round has none. - The view keeps your app's name for the server (&lt;code&gt;server&lt;/code&gt;) apart from the name the server gives itself (&lt;code&gt;serverClaims&lt;/code&gt;), so the person sees who is asking as your app knows it. - Free items can't depend on paid ones, so the question and decision shapes are defined in the file; they fit &lt;code&gt;ClarifyingQuestion&lt;/code&gt; and &lt;code&gt;Decision&lt;/code&gt; as they are. The words are in &lt;code&gt;mcpInputWords&lt;/code&gt;; pass your own.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;McpConnect&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;mcp-connect&lt;/code&gt;, Pro): the card for connecting a new MCP server. - Where data goes first: the server's host, then its full address (or the command a local server runs with), and who runs it as your app knows it. Left out, it says the owner isn't known. - What it says it can do: each tool by name, with its title and description. A tool with no description says &amp;quot;Not described by the server&amp;quot;. The server's own hints (&amp;quot;Says it only reads&amp;quot;, &amp;quot;Says it can change or delete&amp;quot;) are labelled as its claims, which nothing has checked. Past &lt;code&gt;toolLimit&lt;/code&gt; (6), the rest fold behind &amp;quot;Show all&amp;quot;. - What it asks for: each permission with a box nobody has ticked. One the server doesn't explain says &amp;quot;Not described by the server&amp;quot;, never hidden. A permission it needs to connect is marked, and Connect stays locked, saying why, until it's ticked. &lt;code&gt;onConnect&lt;/code&gt; gets only the ids the person ticked. - A list the server hasn't given is said to be unknown (&amp;quot;The server hasn't listed what it can do&amp;quot;), not shown as empty; an empty one says there's nothing. - How to disconnect later, always. An optional acknowledgement the person ticks themselves, &lt;code&gt;busy&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt;. - Connect and Cancel are the same size and style, so neither is the easy way out. - Its words are under &lt;code&gt;mcpConnect&lt;/code&gt; in &lt;code&gt;LocaleProvider&lt;/code&gt;'s &lt;code&gt;strings&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;New items only: nothing existing changes.&lt;/p&gt;&lt;h3&gt;Usage that isn't metered yet (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;UsageMeters&lt;/code&gt;: &lt;code&gt;pending&lt;/code&gt; is work already done that the provider hasn't metered yet. It's drawn after what's used as a striped part of the bar and said in words (&amp;quot;about $1.10 not yet metered&amp;quot;), and read with the meter's value. &lt;code&gt;mayExceedBy&lt;/code&gt; says how far a run may still go past the limit (&amp;quot;May go over the limit by up to $2.&amp;quot;), from your own figure: a provider that checks the limit between steps, a run already under way. Both have &lt;code&gt;…Text&lt;/code&gt; versions for server-formatted money. The meter never works either out.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;React 19.3 and the React Compiler&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;SidePanel&lt;/code&gt;: &lt;code&gt;keepTabs&lt;/code&gt; keeps tabs that aren't showing mounted, so switching back finds each as it was (its scroll, a half-filled form). On React 19.2 and later it uses React's &lt;code&gt;&amp;lt;Activity&amp;gt;&lt;/code&gt;, so a hidden tab's effects pause until it's shown again; on 19.0 and 19.1 hidden tabs simply stay mounted. Without it, only the showing tab is rendered, as before.&lt;/li&gt;&lt;li&gt;CI now runs the React Compiler (1.0) over every component, block and template (&lt;code&gt;npm run check:compiler&lt;/code&gt;), and fails if it has to skip one for a reason that isn't on a short, explained list (syntax the compiler can't lower yet, and demo code that writes a cookie in a click handler). Turn the compiler on in your app and Candor's components are optimised with it.&lt;/li&gt;&lt;li&gt;Candor still supports every React 19 release. Fragment Refs (19.3) would have meant dropping 19.0 to 19.2, so the &lt;code&gt;Thread&lt;/code&gt;'s focus handling stays as it is.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Claude Agent SDK adapter (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;When the SDK summarises earlier messages to make room (&lt;code&gt;compact_boundary&lt;/code&gt;), the thread now says so, as a system line between replies: &amp;quot;Earlier messages were summarised to make room. The agent works from that summary now; the messages above are unchanged.&amp;quot; Before, a long session lost its history from the agent's view without a word.&lt;/li&gt;&lt;li&gt;A cleared conversation (&lt;code&gt;conversation_reset&lt;/code&gt;, from &lt;code&gt;/clear&lt;/code&gt; and similar) gets a line too: the agent doesn't see the messages above.&lt;/li&gt;&lt;li&gt;&lt;code&gt;eventText&lt;/code&gt; gives these lines your own words, for other languages.&lt;/li&gt;&lt;li&gt;&lt;code&gt;recalled&lt;/code&gt; on the adapter's state lists the memories the SDK recalled for each reply, by message id, with whose memory each is (personal, team or organization), ready for a &lt;code&gt;MemoryUsed&lt;/code&gt; line in that message's &lt;code&gt;footer&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI (candor-ui 0.6.0) and finding components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;update &amp;lt;item&amp;gt; --moved a=b&lt;/code&gt; records the move even when the item is already at the target version; before, it said &amp;quot;already at&amp;quot; and wrote nothing, so the lockfile couldn't learn about a file moved between releases. A &lt;code&gt;--moved&lt;/code&gt; naming a file no item here installed is refused, with the paths the lockfile does know.&lt;/li&gt;&lt;li&gt;&lt;code&gt;add&lt;/code&gt; with a component's name (&lt;code&gt;npx candor-ui add ApprovalDecision&lt;/code&gt;) says which item it lives in (&lt;code&gt;approval-request&lt;/code&gt;) and installs nothing, instead of failing on a name no item has.&lt;/li&gt;&lt;li&gt;&lt;code&gt;llms.txt&lt;/code&gt; and the docs MCP's &lt;code&gt;list_components&lt;/code&gt; and &lt;code&gt;search_docs&lt;/code&gt; name an item's other components: &lt;code&gt;approval-request&lt;/code&gt; exports &lt;code&gt;ApprovalRequest&lt;/code&gt; and &lt;code&gt;ApprovalDecision&lt;/code&gt;. &lt;code&gt;get_component_docs&lt;/code&gt; already found an item by any of its components.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Site&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Honest vs. typical&lt;/strong&gt; (&lt;code&gt;/honest-vs-typical&lt;/code&gt;): four moments side by side, a plain rendering of what an agent UI typically shows beside the Candor component with the same data: an approval for a change that moved since it was asked for, a run that went quiet, a restore that missed a shell change, and a cost the SDK didn't report. Each links to the components' docs and the principle it keeps. No products are named.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.7.0</title>
      <link>https://candor.themethodic.com/changelog#1-7-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-7-0</guid>
      <pubDate>Fri, 06 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Agents that work while nobody watches, approvals that can be edited and answered from anywhere, memory that says what it used, and the next round of a customer's asks for the thread, messages and composer. New items, optional props and CLI 0.5.0; no breaking changes. One behaviour to know: &lt;code&gt;candor-ui add --overwrite&lt;/code&gt; now stops before replacing an item you've changed.&lt;/p&gt;&lt;h3&gt;Background work hub (Pro)&lt;/h3&gt;&lt;p&gt;Runs that go on without the person watching, shown honestly: a run is never called running when nothing has been heard from it.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;RunHeartbeat&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;run-heartbeat&lt;/code&gt;, Pro): a run's state that never claims it's alive on no evidence. - With &lt;code&gt;lastHeardAt&lt;/code&gt;, a running run heard from recently says &amp;quot;Running · heard 1 minute ago&amp;quot;. Silent for longer than &lt;code&gt;staleAfter&lt;/code&gt; (two minutes unless set), it says &amp;quot;No update since 10:42&amp;quot; instead, and that it may have stopped. A queued or waiting run is quiet by design, so it doesn't go stale. - &lt;code&gt;hostOffline&lt;/code&gt; (&lt;code&gt;{ host?, since? }&lt;/code&gt;) says the machine or worker can't be reached (&amp;quot;Runner 3 offline since 10:40&amp;quot;), with the last update. It comes ahead of everything but a finished run. - A run that needs the person (status &lt;code&gt;&amp;quot;waiting&amp;quot;&lt;/code&gt;, or &lt;code&gt;needs&lt;/code&gt;) says what for, with a Respond your app handles (&lt;code&gt;onRespond&lt;/code&gt;). An offline run that needs the person still says what for. - Before the page has a clock (server rendering), it gives the last update's time and claims nothing. - Without &lt;code&gt;lastHeardAt&lt;/code&gt;, the app isn't tracking freshness, and the status is shown as given, as before. - &lt;code&gt;compact&lt;/code&gt; is one line, for lists. &lt;code&gt;useLivenessWords()&lt;/code&gt; gives the same words for your own lists.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;SteerComposer&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;steer-composer&lt;/code&gt;, Pro): send a message into a run while it works. - Each message says where it is: sending, sent but not picked up yet (&amp;quot;Build agent hasn't picked it up yet&amp;quot;), picked up (and when), or not delivered, with the reason and a Retry. A message isn't shown as read until your service says so. - &lt;code&gt;onWithdraw&lt;/code&gt; takes back a message the agent hasn't read yet; one it has read can't be withdrawn. - The note above the box says when the agent reads messages (&lt;code&gt;pickupNote&lt;/code&gt;, &amp;quot;between steps&amp;quot; by default), or that the run is quiet, its host is offline, or it's waiting on the person: a message doesn't answer what it asked. - A finished run takes no messages and says so. Enter sends; Shift+Enter breaks a line.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;lastHeardAt&lt;/code&gt; and &lt;code&gt;hostOffline&lt;/code&gt;&lt;/strong&gt; on &lt;code&gt;BackgroundTask&lt;/code&gt;, &lt;code&gt;AgentActivityEntry&lt;/code&gt; and &lt;code&gt;Session&lt;/code&gt;, with a &lt;code&gt;staleAfter&lt;/code&gt; prop on &lt;code&gt;TaskTray&lt;/code&gt;, &lt;code&gt;AgentActivity&lt;/code&gt; and &lt;code&gt;SessionList&lt;/code&gt;. A silent or offline run stops showing as running in each: - &lt;code&gt;TaskTray&lt;/code&gt; counts it as &amp;quot;not heard from&amp;quot; instead of running (&amp;quot;1 running · 2 not heard from&amp;quot;), and its row says &amp;quot;No update since 10:42&amp;quot; or that its host is offline. - &lt;code&gt;AgentActivity&lt;/code&gt; shows the same line instead of the agent's status. - &lt;code&gt;SessionList&lt;/code&gt; shows it instead of the status with &lt;code&gt;showStatus&lt;/code&gt;; without it, the dot stops pulsing and its label says why.&lt;/li&gt;&lt;li&gt;&lt;code&gt;status&lt;/code&gt; (free) gains &lt;code&gt;runLiveness(run, now, staleAfter)&lt;/code&gt;, the &lt;code&gt;RunLiveness&lt;/code&gt; and &lt;code&gt;HostOffline&lt;/code&gt; types, and &lt;code&gt;STALE_AFTER&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The &amp;quot;Unknown stays unknown&amp;quot; principle now names &lt;code&gt;run-heartbeat&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;New optional props, fields and functions only: existing code renders and runs as before. Data without &lt;code&gt;lastHeardAt&lt;/code&gt; or &lt;code&gt;hostOffline&lt;/code&gt; looks exactly as it did.&lt;/p&gt;&lt;h3&gt;Approvals (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ApprovalRequest&lt;/code&gt;: &lt;strong&gt;edit before approving&lt;/strong&gt;. With &lt;code&gt;onApproveEdited&lt;/code&gt; and the request's new &lt;code&gt;input&lt;/code&gt; (the change as it will run, as the agent proposed it), the person deciding can edit it as JSON first. They see exactly what they changed against the proposal, the same view &lt;code&gt;PermissionPrompt&lt;/code&gt; shows for an edited tool call, and the edited change's own hash once it's worked out. &amp;quot;Approve as edited&amp;quot; calls &lt;code&gt;onApproveEdited(hash, input)&lt;/code&gt; with that hash; an edit that changes nothing approves through &lt;code&gt;onApprove&lt;/code&gt; as before. Nothing is pre-selected, and an edit to a change in production or one that can't be undone needs one more tick (&amp;quot;I've checked my edit&amp;quot;) before it can be approved. The compact density never edits: it opens the full request, as before. &lt;code&gt;hashOf&lt;/code&gt; works the hash out (by default &lt;code&gt;changeHash&lt;/code&gt;: the sha256 of the input's canonical JSON); pass your server's own, and have the server recompute it from the input it receives. Once decided, &lt;code&gt;decision.editedFrom&lt;/code&gt; (the proposed change's hash) shows &amp;quot;Edited before it ran&amp;quot;, the words the tool call uses. With the Claude Agent SDK, the edited input is the answer's &lt;code&gt;updatedInput&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;changeHash&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;change-hash&lt;/code&gt;): the sha256 of a change in the same canonical form (keys sorted at every depth) in the browser and on the server, so an approval made against a hash can be checked where the change runs.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New types:&lt;/strong&gt; &lt;code&gt;ApprovalRequest.input&lt;/code&gt; and &lt;code&gt;decision.editedFrom&lt;/code&gt; (both optional).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Approve from anywhere&lt;/strong&gt; (new, &lt;code&gt;approve-from-anywhere&lt;/code&gt; and &lt;code&gt;approve-from-anywhere-claude&lt;/code&gt;): an agent that changes feature-flag rollouts, whose one write pauses the run until someone else decides, however long that takes. - The approver gets an email (&lt;code&gt;EmailLayout&lt;/code&gt;) with the approval's id and the change's hash, and no link: they open the approval page themselves and type the id. The email says to check the hash on the page matches. - The approval page is made for a phone: the compact &lt;code&gt;ApprovalRequest&lt;/code&gt;, which opens the full request to decide a production change or to edit the percentage first (edit before approving, above). The server works out the edited change's hash again and refuses the approval if it isn't the one the approver was shown, and only the percentage can be edited. Only the people it was sent to (&lt;code&gt;people&lt;/code&gt;, through &lt;code&gt;mayDecide&lt;/code&gt;) can decide it, never the person whose run asked. - The decision is data, so the run resumes whether or not the process that paused it is still there. On the Vercel AI SDK the run is its saved messages, resumed from them as soon as someone decides. On the Claude Agent SDK the waiting process polls the block's &lt;code&gt;ApprovalStore&lt;/code&gt;; if it went away (a restart or a deploy), its heartbeat stops, and the decision is applied and the agent carried on from its session (the SDK's &lt;code&gt;resume&lt;/code&gt;). Browsers re-attach to a Claude run from its stored events (&lt;code&gt;ClaudeRunStore&lt;/code&gt;, &lt;code&gt;attachClaudeAgentRun&lt;/code&gt;). Resuming is claimed with a conditional write, so one process does it. The approver's answer comes back as soon as the decision is recorded; the run carries on after, so a long or second approval never holds their request open. - The change applies once, exactly as approved, only if the flag hasn't moved since it was asked for. A request nobody decides expires after a day and the run is told. The person who asked can't approve their own run's write, including by answering the adapter's approval directly. - Data is kept in memory, or in Postgres in the &lt;code&gt;anywhere_&lt;/code&gt; tables; only Postgres survives a restart. Emails go to an outbox table for your mailer.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Memory (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;MemoryUsed&lt;/code&gt;&lt;/strong&gt; (new, &lt;code&gt;memory-used&lt;/code&gt;): the line under a reply that says what it remembered, &amp;quot;Used 2 memories&amp;quot;, which opens them, each with who taught it and when. &lt;code&gt;onOpen&lt;/code&gt; makes each one a button (to open it in &lt;code&gt;MemoryManager&lt;/code&gt;, say) and &lt;code&gt;onManage&lt;/code&gt; adds &amp;quot;Manage memory&amp;quot;. &lt;code&gt;fromHistory&lt;/code&gt; says the reply also drew on past chats, which can't be listed, in words rather than as an empty or made-up list (&amp;quot;Used past chats&amp;quot; when that's all it used). &lt;code&gt;forgotten&lt;/code&gt; counts memories it used that have since been forgotten, without words it no longer has. With no memory used it renders nothing. Put it in &lt;code&gt;Message&lt;/code&gt;'s new &lt;code&gt;footer&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;MemoryMode&lt;/code&gt;&lt;/strong&gt; (new, &lt;code&gt;memory-mode&lt;/code&gt;): memory on, paused or off, with what each does to the memories already kept. Paused always says they're kept and come back. What off does is the app's to say (&lt;code&gt;whenOff&lt;/code&gt;, required): &amp;quot;kept&amp;quot;, or &amp;quot;deleted&amp;quot;, which asks first, says how many go (&lt;code&gt;count&lt;/code&gt;) and offers &amp;quot;Pause instead&amp;quot;. The mode shown is the one the app reported; &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;locked&lt;/code&gt; work as in &lt;code&gt;PermissionMode&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;MemoryManager&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;history&lt;/code&gt; (with &lt;code&gt;chats&lt;/code&gt; when known) says agents also learn from past chats, which can't be shown or forgotten one by one here, and an empty list then reads &amp;quot;No saved memories.&amp;quot; instead of &amp;quot;Nothing remembered yet.&amp;quot; &lt;code&gt;mode&lt;/code&gt; says above the list when memory is paused (kept, not used) or off.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/strong&gt; (free): &lt;code&gt;footer&lt;/code&gt;, a node shown under an agent reply after who checked it and above the actions row, for lines like &lt;code&gt;MemoryUsed&lt;/code&gt;. &lt;code&gt;MessageFooter&lt;/code&gt; takes it too. Without it, nothing changes.&lt;/li&gt;&lt;li&gt;&lt;code&gt;know&lt;/code&gt;: the &lt;code&gt;MemoryModeValue&lt;/code&gt; type (&amp;quot;on&amp;quot;, &amp;quot;paused&amp;quot;, &amp;quot;off&amp;quot;).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;New strings: &lt;code&gt;memoryUsed&lt;/code&gt; and &lt;code&gt;memoryMode&lt;/code&gt; tables; &lt;code&gt;memoryManager&lt;/code&gt; gains &lt;code&gt;emptyWithHistory&lt;/code&gt;, &lt;code&gt;history&lt;/code&gt;, &lt;code&gt;historyCount&lt;/code&gt;, &lt;code&gt;paused&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Thread, messages and composer (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Thread&lt;/code&gt;: &lt;code&gt;anchor&lt;/code&gt; opens it at an element in it (a chapter divider, the card that needs the reader) instead of the bottom, and waits for the reader instead of following; &lt;code&gt;scrollerRef&lt;/code&gt; hands over the scrolling element; &lt;code&gt;onDrop&lt;/code&gt; takes files dropped on the thread; &lt;code&gt;fade={false}&lt;/code&gt; turns off the soft fade at the bottom.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;MessageHeader&lt;/code&gt;: &lt;code&gt;density=&amp;quot;compact&amp;quot;&lt;/code&gt; draws a 12px name in a 24px row.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Message&lt;/code&gt; and &lt;code&gt;MessageContent&lt;/code&gt;: &lt;code&gt;bareCode&lt;/code&gt; shows code and other payload blocks without their frame.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ThreadEvent&lt;/code&gt;: &lt;code&gt;align=&amp;quot;start&amp;quot;&lt;/code&gt;, a left-aligned line (right-aligned in RTL) with the time at its end; pair it with 1.6's &lt;code&gt;timeFormat=&amp;quot;time&amp;quot;&lt;/code&gt; for a clock time.&lt;/li&gt;&lt;li&gt;&lt;code&gt;FoldedTurns&lt;/code&gt;: &lt;code&gt;header&lt;/code&gt; replaces the dashed line with your own (a card with a title, how it ended, its cost), with Show and Hide after it.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Composer&lt;/code&gt;: - A held state, &lt;code&gt;{ kind: &amp;quot;held&amp;quot;, reason }&lt;/code&gt;: typing stays open, sending waits, and the box says why (&amp;quot;Your partner is still thinking&amp;quot;). &lt;code&gt;locked&lt;/code&gt; still disables the box. - &lt;code&gt;textareaRef&lt;/code&gt; to focus the box from outside. - &lt;code&gt;sendShape=&amp;quot;round&amp;quot;&lt;/code&gt; for a round send button.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI (candor-ui 0.5.0)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;add --overwrite&lt;/code&gt; stops before shadcn replaces an installed item you've changed: it names the files, installs nothing, and says to bring them up to date with &lt;code&gt;update&lt;/code&gt; (which merges) first. &lt;code&gt;--replace-edits&lt;/code&gt; replaces them anyway; it isn't passed to shadcn.&lt;/li&gt;&lt;li&gt;When shadcn writes nothing (it stops if a file it would update has your changes, and still exits 0), &lt;code&gt;add&lt;/code&gt; says so, names that file, records nothing for those items and exits 1. Before, it said the items were &amp;quot;already installed&amp;quot;.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.6.0</title>
      <link>https://candor.themethodic.com/changelog#1-6-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-6-0</guid>
      <pubDate>Fri, 06 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;From a team building on Candor: what got in their way, fixed. Strict TypeScript, moved files, money your server formats, absolute times, and the accessibility statement. New optional props, one new free item and CLI 0.4.0; no breaking changes. One thing to do if you use Inter: see &amp;quot;Inter is its own item&amp;quot;.&lt;/p&gt;&lt;h3&gt;Strict TypeScript&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The kit, blocks and templates compile with &lt;code&gt;exactOptionalPropertyTypes&lt;/code&gt; on. Every optional property is written &lt;code&gt;?: T | undefined&lt;/code&gt;, so passing a value that may be undefined to an optional prop works under both settings, and lock-reason maps (&lt;code&gt;ToolSetting.locked&lt;/code&gt;, &lt;code&gt;RestoreDialog&lt;/code&gt;, &lt;code&gt;ReviewLadder&lt;/code&gt;, &lt;code&gt;NotificationPreferences&lt;/code&gt;) accept undefined. CI checks it (&lt;code&gt;npm run check:exact&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;It also compiles with &lt;code&gt;noImplicitOverride&lt;/code&gt;: the error boundaries in &lt;code&gt;card-registry&lt;/code&gt; and &lt;code&gt;a2ui-surface&lt;/code&gt; mark &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;render&lt;/code&gt; as &lt;code&gt;override&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Messages and times&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Message&lt;/code&gt;, &lt;code&gt;MessageHeader&lt;/code&gt;, &lt;code&gt;MessageFooter&lt;/code&gt; and &lt;code&gt;ThreadEvent&lt;/code&gt; take &lt;code&gt;timeFormat&lt;/code&gt;: &lt;code&gt;&amp;quot;relative&amp;quot;&lt;/code&gt; (the default), or an absolute &lt;code&gt;&amp;quot;time&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;date&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;datetime&amp;quot;&lt;/code&gt; in the locale, for every time the message shows.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Message&lt;/code&gt; takes &lt;code&gt;meta&lt;/code&gt;: &lt;code&gt;false&lt;/code&gt; hides the &amp;quot;You · time&amp;quot; line under a person's message, a node replaces it.&lt;/li&gt;&lt;li&gt;&lt;code&gt;message-content&lt;/code&gt; installs &lt;code&gt;safe-markdown&lt;/code&gt;, and the docs name &lt;code&gt;plainBlocks&lt;/code&gt; and &lt;code&gt;markdownBlocks&lt;/code&gt; as the way to build a message's blocks. Import them from &lt;code&gt;safe-markdown&lt;/code&gt;: they run on the server too.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Money as your server wrote it&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;When your server decides what's exact and what's &amp;quot;about&amp;quot;, give it the text and Candor shows it as written, never rounding or summing: &lt;code&gt;UsageMeters&lt;/code&gt; (&lt;code&gt;usedText&lt;/code&gt;, &lt;code&gt;limitText&lt;/code&gt;, &lt;code&gt;estimateText&lt;/code&gt;, read to screen readers through &lt;code&gt;aria-valuetext&lt;/code&gt;), &lt;code&gt;RunReceipt&lt;/code&gt; (&lt;code&gt;totalText&lt;/code&gt;, and a model's &lt;code&gt;costText&lt;/code&gt;), &lt;code&gt;RunEstimate&lt;/code&gt; (&lt;code&gt;costText&lt;/code&gt;), &lt;code&gt;SpendBreakdown&lt;/code&gt; (&lt;code&gt;totalText&lt;/code&gt;) and &lt;code&gt;StatCard&lt;/code&gt; (&lt;code&gt;valueText&lt;/code&gt;). The numbers still place bars and markers.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Toasts&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Toaster&lt;/code&gt; takes &lt;code&gt;offset&lt;/code&gt; (or the &lt;code&gt;--cd-toast-offset&lt;/code&gt; token) to keep clear of something fixed at the bottom, such as a chat composer.&lt;/li&gt;&lt;li&gt;When the focused control is under the stack anyway, the stack moves to the top (WCAG 2.4.11). Your own &lt;code&gt;className=&amp;quot;bottom-…&amp;quot;&lt;/code&gt; on &lt;code&gt;Toaster&lt;/code&gt; still wins over the default position.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Inter is its own item&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The theme no longer imports Inter. It's the new free item &lt;code&gt;font-inter&lt;/code&gt; (&lt;code&gt;styles/candor-font-inter.css&lt;/code&gt;, OFL-1.1), so a project can keep its own font and its own font licences. Without it, &lt;code&gt;--cd-font&lt;/code&gt; falls back to the system's sans-serif.&lt;/li&gt;&lt;li&gt;&lt;code&gt;candor-ui init&lt;/code&gt; adds and imports it unless you pass &lt;code&gt;--no-font&lt;/code&gt;. &lt;strong&gt;If you update the theme and want Inter,&lt;/strong&gt; run &lt;code&gt;npx candor-ui init&lt;/code&gt; again (it adds the font and changes nothing else), or &lt;code&gt;npx candor-ui add font-inter&lt;/code&gt; and import &lt;code&gt;styles/candor-font-inter.css&lt;/code&gt; after &lt;code&gt;candor.css&lt;/code&gt;. &lt;code&gt;update&lt;/code&gt; says so when it takes Inter away, and &lt;code&gt;doctor&lt;/code&gt; notes when text uses the system font.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI (candor-ui 0.4.0)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; follows a file you moved: it finds it when it's still exactly as installed, or you say where with &lt;code&gt;--moved &amp;lt;installed path&amp;gt;=&amp;lt;where it is now&amp;gt;&lt;/code&gt;, and &lt;code&gt;candor-lock.json&lt;/code&gt; remembers the move. A move must stay inside the project and keep the file's name, so a typo can't merge Candor's file into another one.&lt;/li&gt;&lt;li&gt;An item with a file &lt;code&gt;update&lt;/code&gt; can't find is now left alone: nothing of it is written, it stays at its old version, and &lt;code&gt;update&lt;/code&gt; exits 1. Before, it moved on without that file.&lt;/li&gt;&lt;li&gt;&lt;code&gt;verify&lt;/code&gt;, for CI: checks &lt;code&gt;candor-lock.json&lt;/code&gt; against the registry's versioned snapshots and the files on disk, without running shadcn. Files you changed are listed, not failed.&lt;/li&gt;&lt;li&gt;Installing several items at once no longer leaves some unrecorded: small differences shadcn makes in a batch (a &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt; line, trailing spaces) count as the same install.&lt;/li&gt;&lt;li&gt;&lt;code&gt;init --no-font&lt;/code&gt;, and &lt;code&gt;doctor&lt;/code&gt; flags a monorepo's shared package that still points at the old GitHub registry.&lt;/li&gt;&lt;li&gt;The Get started guide now covers the lockfile, merges, &lt;code&gt;--dry-run&lt;/code&gt;, &lt;code&gt;--from&lt;/code&gt;, &lt;code&gt;--moved&lt;/code&gt; and &lt;code&gt;verify&lt;/code&gt;; &lt;code&gt;/docs/cli&lt;/code&gt; and &lt;code&gt;/docs/updating&lt;/code&gt; lead there.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Accessibility (WCAG 2.2 AA)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;A public accessibility statement at [/accessibility](https://candor.themethodic.com/accessibility): WCAG 2.2 AA as the target, what's checked on every release, and the known gaps (no screen-reader pass by people yet).&lt;/li&gt;&lt;li&gt;Focus rings that carry focus on their own go from 40-50% to 80% opacity, meeting 3:1 on every surface in every theme; &lt;code&gt;npm run theme&lt;/code&gt; now measures the ring as drawn, blended at 80%.&lt;/li&gt;&lt;li&gt;The chosen segment in segmented controls has a 1px edge as well as its fill.&lt;/li&gt;&lt;li&gt;RoleMatrix, DataRetention, ComparisonView, RunLog, MetadataDiff's file body, DataImport's preview, RestoreDialog's checks, TestResults' stack traces and Diagram can be scrolled from the keyboard. &lt;strong&gt;They're new tab stops:&lt;/strong&gt; a test that counts Tab presses through these components needs one more for each.&lt;/li&gt;&lt;li&gt;&lt;code&gt;AppSidebar&lt;/code&gt; takes &lt;code&gt;help&lt;/code&gt;, which puts Help in the same place on every page (3.2.6).&lt;/li&gt;&lt;li&gt;A test fails on any new button or link smaller than 24px without a hit area (2.5.8).&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.5.1</title>
      <link>https://candor.themethodic.com/changelog#1-5-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-5-1</guid>
      <pubDate>Fri, 06 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Two fixes, both found by a team building on Candor.&lt;/p&gt;&lt;h3&gt;Toast&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;A fifth toast no longer pushes out an error. The oldest toast that isn't an error goes first, the newest always shows, and errors stay until someone dismisses them, as the docs always said. Before, the toaster kept the newest four whatever their tone, so four notices after a failure hid it. Errors can now stack past four, so the stack scrolls once it reaches the top of the screen, keeping the newest in view. &lt;code&gt;capToasts&lt;/code&gt; is exported for tests.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI (candor-ui 0.3.1)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;init&lt;/code&gt; and &lt;code&gt;key&lt;/code&gt; (including &lt;code&gt;key --remove&lt;/code&gt;) move &lt;code&gt;@candor&lt;/code&gt; off the pre-launch raw GitHub address (&lt;code&gt;raw.githubusercontent.com/…/public/r/&lt;/code&gt;) to the public registry, and say so. Before, they kept it, so a project set up before launch stayed frozen at that commit and needed a GitHub token. &lt;code&gt;--registry-url&lt;/code&gt; still sets any address you choose.&lt;/li&gt;&lt;li&gt;On the old address, &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; stop and say to run &lt;code&gt;init&lt;/code&gt;, rather than sending your licence key to GitHub. &lt;code&gt;doctor&lt;/code&gt; flags it (in a monorepo's shared package too) instead of saying &amp;quot;All good&amp;quot;, and skips checking the key.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.5.0</title>
      <link>https://candor.themethodic.com/changelog#1-5-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-5-0</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;Approvals that last, AI that says it's AI. Seven new items (two free), durable approvals and the full Claude Agent SDK permission model in the adapters, and the CLI in monorepos. New optional props and functions only: existing code renders and runs as before. Two type changes widen what's accepted (&lt;code&gt;AuditAction&lt;/code&gt;, &lt;code&gt;ClaudeApproval&lt;/code&gt;); see below.&lt;/p&gt;&lt;h3&gt;Durable approvals and runs (free adapters)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Claude Agent SDK, server half&lt;/strong&gt; (&lt;code&gt;claude-agent-server&lt;/code&gt;): - Permission requests wait in an &lt;code&gt;ApprovalStore&lt;/code&gt; instead of only in process memory. &lt;code&gt;memoryApprovalStore()&lt;/code&gt; is the default; pass your own (a table, a queue) as &lt;code&gt;approvals&lt;/code&gt;, so any instance can take the answer. &lt;code&gt;waitByPolling&lt;/code&gt; helps a store that can't push. Answering and closing each happen once, whichever comes first, so a late answer to a run that already ended is refused, not lost. - &lt;code&gt;claudeCanUseTool({ approvals, emit, owner })&lt;/code&gt; is the same canUseTool outside &lt;code&gt;streamClaudeAgent&lt;/code&gt;, for an agent run by your own worker or workflow engine. Answer it from your own route, such as a workflow signal. - &lt;code&gt;answerClaudeApproval(store, id, answer, { owner })&lt;/code&gt; records the full answer: allowed, denied, allowed with an edited input, answers to the agent's questions, and the &amp;quot;always allow&amp;quot; rules the person picked. It checks the answer fits the request (an edited input must be an object; only offered rules can be kept). The 1.4 &lt;code&gt;answerClaudeAgentApproval&lt;/code&gt; still works, synchronously, on the default store. - A &lt;code&gt;ClaudeRunStore&lt;/code&gt; (&lt;code&gt;memoryRunStore()&lt;/code&gt;) keeps a run's events. With &lt;code&gt;detach&lt;/code&gt;, a run carries on when the browser goes away, and &lt;code&gt;attachClaudeAgentRun&lt;/code&gt; streams it again from any point, then live. &lt;code&gt;stopClaudeAgentRun&lt;/code&gt; stops it. Responses carry the run's id in &lt;code&gt;x-candor-run-id&lt;/code&gt;. &lt;code&gt;onEvent&lt;/code&gt; hands you every event to keep for replay, and &lt;code&gt;prompt&lt;/code&gt; records what the person sent as the run's first event. A run store creates a run only on &lt;code&gt;start&lt;/code&gt;, and &lt;code&gt;memoryRunStore&lt;/code&gt; forgets only finished runs (oldest first, past &lt;code&gt;maxRuns&lt;/code&gt;), so a live run keeps its owner. It keeps up to &lt;code&gt;maxEvents&lt;/code&gt; (5,000) per run, after which partial-text events are dropped. - &lt;code&gt;approvalTimeoutMs&lt;/code&gt; closes a request nobody answered as expired: the tool is denied, never allowed. Set one with &lt;code&gt;detach&lt;/code&gt;, or a run can wait for ever. - &lt;code&gt;editable(tool, input)&lt;/code&gt; says which tools' input a person may edit (every tool by default). An edit to any other tool is refused by the server, whatever the browser sends, and the request tells the browser (&lt;code&gt;editable: false&lt;/code&gt;). - The input a person edited is recorded: &lt;code&gt;candor_approval_closed&lt;/code&gt; carries it, and the tool card and any replay show what ran, marked &amp;quot;Edited before it ran&amp;quot;, with the agent's proposal beside it. - A stop and an answer at the same moment: the request closes as stopped, and the answer is refused, so the record never says &amp;quot;approved&amp;quot; for a tool that didn't run. - &lt;code&gt;setClaudeAgentPermissionMode(runId, mode, owner, { allowed })&lt;/code&gt; changes a running agent's mode (the SDK's &lt;code&gt;setPermissionMode&lt;/code&gt;, streaming input only) and tells the browser. The route enforces policy: modes outside &lt;code&gt;allowed&lt;/code&gt;, or the run's &lt;code&gt;modes&lt;/code&gt;, are refused, so a mode &lt;code&gt;PermissionMode&lt;/code&gt; shows as locked can't be set by posting to the route directly. - The agent still runs in the process that started it: a store makes the answer and the record durable, not the run.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Claude Agent SDK, browser half&lt;/strong&gt; (&lt;code&gt;use-claude-agent&lt;/code&gt;): &lt;code&gt;initialEvents&lt;/code&gt; replays a stored conversation; &lt;code&gt;attachUrl&lt;/code&gt; and &lt;code&gt;runId&lt;/code&gt; re-attach to a run after a reload (&lt;code&gt;attach()&lt;/code&gt; does it on demand); &lt;code&gt;onRespond&lt;/code&gt; answers through your own route instead of &lt;code&gt;approveApi&lt;/code&gt;, which is now optional; &lt;code&gt;stopApi&lt;/code&gt; stops a detached run; &lt;code&gt;modeApi&lt;/code&gt;, &lt;code&gt;permissionMode&lt;/code&gt; and &lt;code&gt;setPermissionMode&lt;/code&gt;. &lt;code&gt;respond&lt;/code&gt; takes a fourth argument with &lt;code&gt;updatedInput&lt;/code&gt;, &lt;code&gt;answers&lt;/code&gt; and &lt;code&gt;alwaysAllow&lt;/code&gt;. Requests now send a &lt;code&gt;promptId&lt;/code&gt; too: pass it to the server's &lt;code&gt;prompt&lt;/code&gt;, and re-attaching with &lt;code&gt;initialEvents&lt;/code&gt; replaces the run's events instead of adding them again.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Vercel AI SDK 7&lt;/strong&gt; (&lt;code&gt;ai-sdk&lt;/code&gt;, &lt;code&gt;use-candor-chat&lt;/code&gt;): runs on &lt;code&gt;WorkflowAgent&lt;/code&gt; stream the same UI messages, so they work as they are. A tool waiting for approval stays waiting for as long as the workflow does, and an approval made automatically is marked on the tool call. Re-attaching after a reload is the AI SDK's own &lt;code&gt;WorkflowChatTransport&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The Claude Agent SDK's permission model (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;AskUserQuestion&lt;/code&gt; becomes questions: &lt;code&gt;ClaudeApproval.questions&lt;/code&gt;, shaped for &lt;code&gt;ClarifyingQuestions&lt;/code&gt; (&lt;code&gt;claudeQuestions&lt;/code&gt;). Answers go back as the SDK expects, keyed by the question's text, several choices joined with &amp;quot;, &amp;quot;, the person's own words used as typed.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ClaudeApproval&lt;/code&gt; also carries &lt;code&gt;suggestions&lt;/code&gt; (the SDK's &amp;quot;always allow&amp;quot; rules, offered and never kept unless the person picks one), &lt;code&gt;noAlwaysAllow&lt;/code&gt;, &lt;code&gt;mode&lt;/code&gt;, &lt;code&gt;displayName&lt;/code&gt;, &lt;code&gt;agentId&lt;/code&gt; and &lt;code&gt;mcpServer&lt;/code&gt;. &lt;code&gt;claudeSuggestions&lt;/code&gt; turns the rules into plain parts to show. &lt;code&gt;claudePermissionResult(request, answer)&lt;/code&gt; turns an answer into the SDK's &lt;code&gt;PermissionResult&lt;/code&gt;, wherever the answer lands.&lt;/li&gt;&lt;li&gt;&lt;code&gt;fromClaudeAgentEvents&lt;/code&gt; reports &lt;code&gt;permissionMode&lt;/code&gt; from the SDK's &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; messages and the new &lt;code&gt;candor_mode&lt;/code&gt; event.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;PermissionPrompt&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;permission-prompt&lt;/code&gt;, free): a tool call waiting on the person. It says why it reached them and the run's permission mode, lets them edit the input as JSON and shows exactly what they changed before &amp;quot;Allow as edited&amp;quot;, offers &amp;quot;don't ask again&amp;quot; rules as boxes nobody has ticked, and opens on Deny when the request asks. Nothing carries over from one request to the next. A rule that switches to &amp;quot;Allow everything&amp;quot; or &amp;quot;Automatic&amp;quot; says what that hands away. When the agent asks questions, it shows them as a short form with nothing chosen. The Claude gallery demo uses it.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ToolCall&lt;/code&gt; takes &lt;code&gt;approval: { by: &amp;quot;person&amp;quot; | &amp;quot;automatic&amp;quot;, note }&lt;/code&gt; and marks a call &amp;quot;Approved automatically&amp;quot;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;AI disclosure&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;AiDisclosure&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;ai-disclosure&lt;/code&gt;, free): tells people they're interacting with an AI system, as a first line in the thread or a compact &amp;quot;AI&amp;quot; badge for a header, with the app's own explanation. The agent is named only by the app. It helps with EU AI Act Article 50(1); it makes no legal claim, and whether it's enough is the deployer's call. Free by the owner's decision, as part of &amp;quot;a good agent chat&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;AiContentLabel&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;ai-content-label&lt;/code&gt;, Pro): &amp;quot;AI-generated&amp;quot;, &amp;quot;AI-modified&amp;quot;, &amp;quot;No AI used&amp;quot; or &amp;quot;AI involvement not recorded&amp;quot;, after the two categories in the EU's voluntary Code of Practice on marking and labelling AI-generated content (final, 10 June 2026): fully AI-generated and partially AI-modified. The level comes from the app's records, never a guess, and the mark is Candor's own. The label goes with the content: &lt;code&gt;provenanceText&lt;/code&gt;, &lt;code&gt;withProvenance&lt;/code&gt; for copied text, &lt;code&gt;provenanceMetadata&lt;/code&gt; (&lt;code&gt;ai:involvement&lt;/code&gt;, &lt;code&gt;ai:by&lt;/code&gt;, &lt;code&gt;ai:at&lt;/code&gt;) for downloads and sidecar files, and &lt;code&gt;useCopyWithProvenance&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;A docs page, &amp;quot;Telling people they're talking to an AI&amp;quot;, says what the components do and what stays the deployer's.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Checkpoints and an honest restore (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;CheckpointList&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;checkpoint-list&lt;/code&gt;): restore points per turn, what each holds (files, conversation or both, with counts when known), who made it, and where the work is now. A checkpoint that can't be restored stays listed with its Restore locked and the reason.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;RestoreDialog&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;restore-dialog&lt;/code&gt;): restore code, conversation or both, with nothing chosen for the person. It says what a restore doesn't undo: shell commands run since (listed when the app knows them, or &amp;quot;not recorded&amp;quot;), changes made outside the agent, and effects such as sent messages and deployments. After a restore, &lt;code&gt;RestoreResult&lt;/code&gt; shows what the app checked, item by item: &amp;quot;Restored&amp;quot; only when every check matched, a mismatch flagged with what differs, and &amp;quot;not checked&amp;quot; said as such. Restoring both needs a check of each: one that covers only the files is &amp;quot;Partly checked&amp;quot;, naming the conversation (&lt;code&gt;RestoreCheck.area&lt;/code&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Approvals (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ApprovalRequest&lt;/code&gt;: - &lt;code&gt;target&lt;/code&gt; and &lt;code&gt;values&lt;/code&gt;: a change to one thing shows each value before and after (&lt;code&gt;from: null&lt;/code&gt; reads &amp;quot;Not set&amp;quot;; a &lt;code&gt;from&lt;/code&gt; left out reads &amp;quot;Not recorded&amp;quot;). - &lt;code&gt;restrictedTo: { who, reason }&lt;/code&gt;: a request only certain people may decide carries a badge saying who, with the reason shown and read to screen readers. - &lt;code&gt;density=&amp;quot;compact&amp;quot;&lt;/code&gt; for a narrow column, a phone or a notification: the values or summary, where, how many things it touches, the hash, expiry and what happens if nobody answers. Nothing is pre-selected. A change that can't be undone, or that changes production, has no Approve there; &lt;code&gt;onOpen&lt;/code&gt; opens the full request.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;TypeToConfirm&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;type-to-confirm&lt;/code&gt;): a step that can't be undone, confirmed by typing a name exactly. Pasting is allowed. &lt;code&gt;DataControls&lt;/code&gt; now uses it; its string keys are unchanged.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New: &lt;code&gt;PermissionMode&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;permission-mode&lt;/code&gt;): the agent's permission mode with what each mode allows written out, as a list or a compact toolbar button. &amp;quot;Allow everything&amp;quot; and &amp;quot;Automatic&amp;quot; ask &amp;quot;Switch to …?&amp;quot; first; a mode your policy turns off is locked with the reason (enforce the same policy on the server). It shows the mode the agent last reported, never the one just picked. One tab stop; arrow keys move between modes, Space or Enter changes it.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ClarifyingQuestions&lt;/code&gt;: a choice can offer &lt;code&gt;other&lt;/code&gt; (the person's own words, sent as &lt;code&gt;text&lt;/code&gt;), a &lt;code&gt;tag&lt;/code&gt; above the question, and &lt;code&gt;during&lt;/code&gt; drops &amp;quot;Before I plan&amp;quot; from the heading when the agent asks mid-run.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Changed type:&lt;/strong&gt; &lt;code&gt;AuditAction&lt;/code&gt; is now open: Candor's known actions (&lt;code&gt;KnownAuditAction&lt;/code&gt;) or any string. &lt;code&gt;AuditLog&lt;/code&gt; takes &lt;code&gt;actions&lt;/code&gt; to label and group your own; one with no label shows its code. An &amp;quot;Other&amp;quot; filter appears only when a row needs it. Code that switched over every &lt;code&gt;AuditAction&lt;/code&gt; should add a &lt;code&gt;default&lt;/code&gt; branch, and a &lt;code&gt;Record&amp;lt;AuditAction, …&amp;gt;&lt;/code&gt; map in your code no longer type-checks: key it by &lt;code&gt;KnownAuditAction&lt;/code&gt;, with a fallback for other actions.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;AG-UI 1.0 (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;STATE_SNAPSHOT&lt;/code&gt; and &lt;code&gt;STATE_DELTA&lt;/code&gt; fold into &lt;code&gt;state&lt;/code&gt; (on &lt;code&gt;fromAgUiEvents&lt;/code&gt; and &lt;code&gt;useAgUi&lt;/code&gt;). Deltas apply all or nothing; a patch that fails keeps the last good state and sets &lt;code&gt;stateOutOfDate&lt;/code&gt; with the reason until the next snapshot.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ACTIVITY_SNAPSHOT&lt;/code&gt; and &lt;code&gt;ACTIVITY_DELTA&lt;/code&gt; become &lt;code&gt;activities&lt;/code&gt;, in arrival order. Steps map to &lt;code&gt;plan&lt;/code&gt; (shaped like &lt;code&gt;PlanStep&lt;/code&gt;) and status content to &lt;code&gt;agentActivity&lt;/code&gt; (shaped like &lt;code&gt;AgentActivityEntry&lt;/code&gt;), only when every status is a known word.&lt;/li&gt;&lt;li&gt;New &lt;code&gt;applyJsonPatch&lt;/code&gt;, a small RFC 6902 patcher that never changes its input. &lt;code&gt;fromAgUiEvents&lt;/code&gt; and &lt;code&gt;useAgUi&lt;/code&gt; take &lt;code&gt;agents&lt;/code&gt; and &lt;code&gt;initialState&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Citations from tool output (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Claude adapter fills &lt;code&gt;Message.sources&lt;/code&gt; from Claude's own citations and web search results, and places [n] only where a citation is, never from numbers in the text.&lt;/li&gt;&lt;li&gt;Both the Claude and the AI SDK adapters take &lt;code&gt;sourcesFrom(tool, input, output)&lt;/code&gt; to read sources from your own tools' results. The &lt;code&gt;ToolSource&lt;/code&gt; type is in &lt;code&gt;lib/chat&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs MCP server&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/mcp&lt;/code&gt; speaks MCP 2026-07-28: no handshake, &lt;code&gt;server/discover&lt;/code&gt;, the version checked on every request (&lt;code&gt;MCP-Protocol-Version&lt;/code&gt; must match &lt;code&gt;_meta&lt;/code&gt;, else 400 &lt;code&gt;HeaderMismatch&lt;/code&gt; -32020), and an unsupported version answered with -32022 listing the supported ones. A 2026-07-28 request must send &lt;code&gt;Mcp-Method&lt;/code&gt;, and &lt;code&gt;Mcp-Name&lt;/code&gt; for the methods that name something (400 &lt;code&gt;HeaderMismatch&lt;/code&gt; without them); both are checked against the body. GET and DELETE answer 405, and no session is kept.&lt;/li&gt;&lt;li&gt;Older clients (2025-11-25 back to 2024-11-05) work as before, with &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;ping&lt;/code&gt; and batches.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;New pages: &amp;quot;Coming from AI Elements&amp;quot; (which Candor item does each job, what Candor adds, and how it sits beside shadcn's Trace and Message Scroller), &amp;quot;Durable approvals for long-running agents&amp;quot; and &amp;quot;Telling people they're talking to an AI&amp;quot;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Accessibility (WCAG 2.2 AA audit)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Every control now has a pointer target of at least 24×24 px (2.5.8), including the Dialog and Sheet close buttons, radios, chip remove buttons, tree chevrons, the approval's hash and the small text buttons. The look is unchanged, except that ProseDiff's accept and reject buttons now sit further apart.&lt;/li&gt;&lt;li&gt;AppLayout's side panel can be resized without dragging: a click on the divider steps through its widths, and Home and End jump to either end (2.5.7).&lt;/li&gt;&lt;li&gt;SignIn: pasting a code with a space or a dash (&amp;quot;123 456&amp;quot;) works. Thread keeps a focused message clear of the &amp;quot;Jump to latest&amp;quot; button (2.4.11).&lt;/li&gt;&lt;li&gt;Scrolling code, excerpts, result tables, chart tables, logs and the restore dialog's lists can be reached and scrolled from the keyboard. Popovers fit a 320px screen, and charts show a clear focus outline.&lt;/li&gt;&lt;li&gt;What's left (the focus ring's contrast, segmented controls, toasts over focused controls, a few wide tables) is listed for 1.6 in &lt;code&gt;internal/ACCESSIBILITY-2026-11.md&lt;/code&gt;, with the public conformance statement.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI (candor-ui 0.3.0)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Monorepos (pnpm and Turborepo, &lt;code&gt;packages/ui&lt;/code&gt; plus &lt;code&gt;apps/web&lt;/code&gt;) now work: - &lt;code&gt;init&lt;/code&gt; from an app puts the theme in the shared UI package next to its CSS, imports it with a correct relative path (it used to be resolved from where candor-ui was launched), and adds the registry to both &lt;code&gt;components.json&lt;/code&gt; files. - The licence key reaches shadcn when it runs in or writes to the shared package. - Run at the repository root, &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;key&lt;/code&gt; stop, name the workspaces and say which &lt;code&gt;--cwd&lt;/code&gt; to use; &lt;code&gt;doctor&lt;/code&gt; checks every workspace with a &lt;code&gt;components.json&lt;/code&gt;. - A root &lt;code&gt;.gitignore&lt;/code&gt; that already covers &lt;code&gt;.env*.local&lt;/code&gt; counts; React given as &lt;code&gt;catalog:&lt;/code&gt; and Tailwind in the shared package are found; install commands use the project's package manager (&lt;code&gt;pnpm --filter … add …&lt;/code&gt;). - &lt;code&gt;candor-lock.json&lt;/code&gt; stays beside the app's &lt;code&gt;components.json&lt;/code&gt;; &lt;code&gt;update&lt;/code&gt; run from the shared package says where it is.&lt;/li&gt;&lt;li&gt;&lt;code&gt;doctor&lt;/code&gt; says which base the project uses (Radix, Base UI or React Aria). Candor's components are built on Radix, so on React Aria it says what breaks and which of the project's primitives Candor's would replace. It checks that &lt;code&gt;cn&lt;/code&gt; resolves, including after shadcn's &lt;code&gt;migrate cn&lt;/code&gt; to the &lt;code&gt;cn&lt;/code&gt; package, and gives the line and the install command when it doesn't.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.4.0</title>
      <link>https://candor.themethodic.com/changelog#1-4-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-4-0</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The gaps the 1.3 blocks worked around, and a limit on the docs server. New optional props only: existing code renders as before, except that &lt;code&gt;FailureClusters&lt;/code&gt; now prints a change of 0 as &amp;quot;0&amp;quot; instead of a dash (see below).&lt;/p&gt;&lt;h3&gt;Knowledge and evals (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ProseDiff&lt;/code&gt; takes &lt;code&gt;readOnly&lt;/code&gt;: the changes between two texts with no accept or reject, headed &amp;quot;Changes&amp;quot; with a count (&amp;quot;3 changes&amp;quot;), and &lt;code&gt;onResolve&lt;/code&gt; is never called. Use it to show what changed between two published versions.&lt;/li&gt;&lt;li&gt;&lt;code&gt;RetrievalInspector&lt;/code&gt; takes &lt;code&gt;verb&lt;/code&gt;, the word before each passage's date, for what its &lt;code&gt;readAt&lt;/code&gt; records: &amp;quot;Reviewed&amp;quot;, &amp;quot;Published&amp;quot;, &amp;quot;Synced&amp;quot;. The default is still &amp;quot;Read&amp;quot;. The knowledge-base blocks pass &amp;quot;Reviewed&amp;quot;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;FailureClusters&lt;/code&gt;: - A cluster's &lt;code&gt;delta&lt;/code&gt; can be &lt;code&gt;null&lt;/code&gt; when there's nothing to compare with, shown as a dash and read as &amp;quot;change unknown&amp;quot;. The new &lt;code&gt;FailureClusterInput&lt;/code&gt; type (a &lt;code&gt;FailureCluster&lt;/code&gt; whose &lt;code&gt;delta&lt;/code&gt; may be null) is what it takes; &lt;code&gt;FailureCluster&lt;/code&gt; itself is unchanged. - &lt;strong&gt;Changed:&lt;/strong&gt; a change of 0 is now printed &amp;quot;0&amp;quot; and read as &amp;quot;no change since last period&amp;quot;. Before, it showed a dash, the same as you'd now see for an unknown change. - &lt;code&gt;since&lt;/code&gt; says what the change is measured against (&amp;quot;production's run&amp;quot;), read after &amp;quot;more than&amp;quot; and &amp;quot;fewer than&amp;quot;. The default is &amp;quot;last period&amp;quot;. New strings: &lt;code&gt;since&lt;/code&gt;, &lt;code&gt;unknown&lt;/code&gt;; &lt;code&gt;more&lt;/code&gt;, &lt;code&gt;fewer&lt;/code&gt; and &lt;code&gt;noChange&lt;/code&gt; now take &lt;code&gt;{since}&lt;/code&gt;. - The eval-dashboard blocks pass &lt;code&gt;null&lt;/code&gt; before there's a production run to compare with, and &lt;code&gt;since=&amp;quot;production's run&amp;quot;&lt;/code&gt;. Before, they showed no change. If your own code passed 0 to mean &amp;quot;nothing to compare with&amp;quot;, pass &lt;code&gt;null&lt;/code&gt; now. - &lt;code&gt;FailureClusterInput&lt;/code&gt; lives in &lt;code&gt;ops&lt;/code&gt;, so update &lt;code&gt;ops&lt;/code&gt; with it: &lt;code&gt;npx candor-ui update failure-clusters ops&lt;/code&gt; (a plain &lt;code&gt;npx candor-ui update&lt;/code&gt; updates everything). candor-ui 0.2.3 says so when you leave one behind.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs MCP server&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;/mcp&lt;/code&gt; allows each client 120 messages a minute per server instance, counting every message in a batch, and answers past that with HTTP 429, &lt;code&gt;Retry-After&lt;/code&gt; (readable from a browser) and a JSON-RPC error. A client is an IP address, or an IPv6 /64. &lt;code&gt;createDocsMcpHandler&lt;/code&gt; takes &lt;code&gt;rateLimit&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;CLI (candor-ui 0.2.3)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; now says when an item it updates uses another installed item that stays on an older version, and gives the command to update it too. Before, it only listed dependencies you hadn't installed.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.3.0</title>
      <link>https://candor.themethodic.com/changelog#1-3-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-3-0</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;h3&gt;Docs for coding agents&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Every docs page is also Markdown at its address plus &lt;code&gt;.md&lt;/code&gt;: &lt;code&gt;/docs/&amp;lt;name&amp;gt;.md&lt;/code&gt; for every item, &lt;code&gt;/patterns/&amp;lt;slug&amp;gt;.md&lt;/code&gt; and &lt;code&gt;/get-started.md&lt;/code&gt;. A page has the item's tier, its install command, its example with the import paths your app uses, every prop, function and type, and the &lt;code&gt;LocaleProvider&lt;/code&gt; string keys. &lt;code&gt;llms.txt&lt;/code&gt; lists them, and each web page links its Markdown version in its &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; and from a Markdown button. &amp;quot;Copy for a coding agent&amp;quot; copies the same text. Pages are built from the docs data, never from source; the build fails if a line of a paid item's code would appear in one.&lt;/li&gt;&lt;li&gt;A docs MCP server at &lt;code&gt;https://candor.themethodic.com/mcp&lt;/code&gt;, free and read-only, with no licence key. Coding agents can search the docs, read any page, list items by group, read patterns and setup, and &lt;code&gt;suggest_components&lt;/code&gt; for a task, with one install command. In Claude Code: &lt;code&gt;claude mcp add --transport http candor https://candor.themethodic.com/mcp&lt;/code&gt;. Other clients add the URL as a remote (streamable HTTP) server. The agent skill and the Get started page point to it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Composer (free)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;tools&lt;/code&gt; puts your own controls in the composer's toolbar, after the attach button.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Dictation (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;DictationButton&lt;/code&gt; and &lt;code&gt;useDictation&lt;/code&gt; (new, &lt;code&gt;dictation&lt;/code&gt;) let a person speak into the composer. It's opt-in: put &lt;code&gt;&amp;lt;DictationButton value={value} onChange={setValue} /&amp;gt;&lt;/code&gt; in the composer's &lt;code&gt;tools&lt;/code&gt;. Words appear in the box as they're recognised, then settle, and stay plain text the person can edit before they send. Nothing sends by itself. Editing while it listens keeps the edit. Emptying the box (sending) stops it with either engine and drops what it hadn't written yet, so nothing lands in the next message.&lt;/li&gt;&lt;li&gt;Audio goes only where your app chooses. With &lt;code&gt;transcribe(audio, { lang, signal })&lt;/code&gt;, it records and hands the audio to your own speech-to-text. Without it, it uses the browser's speech recognition only where that runs on the device. &lt;code&gt;allowBrowserService&lt;/code&gt; opts in to the browser's own service, which in some browsers sends audio to the browser maker.&lt;/li&gt;&lt;li&gt;While it records, the button is pressed and red, the state is written beside it and announced, and Escape is never taken from the composer. Where dictation can't run, the button is hidden, or with &lt;code&gt;whenUnsupported=&amp;quot;explain&amp;quot;&lt;/code&gt; it is locked with the reason. A blocked microphone, no microphone, nothing heard, a network or language problem, and a failed transcription each say what happened. It stops after &lt;code&gt;maxSeconds&lt;/code&gt; (120, counted from when it starts listening) and when &lt;code&gt;disabled&lt;/code&gt;, and pressing it again while the microphone is starting cancels it. Unmounting releases the microphone, even one granted after the component went away. Every word is in &lt;code&gt;dictationStrings&lt;/code&gt;, under &lt;code&gt;dictation&lt;/code&gt; in &lt;code&gt;LocaleProvider&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Why Pro: the free tier stays the chat core, and dictation is an add-on to it. A separate item keeps free installs as they are, since a free item can't depend on a paid one. The free Composer gains only the generic &lt;code&gt;tools&lt;/code&gt; slot.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Knowledge base&lt;/strong&gt; (new, &lt;code&gt;knowledge-base&lt;/code&gt; and &lt;code&gt;knowledge-base-claude&lt;/code&gt;): - An agent answers only from published help-article versions and cites the article and version. The code checks each citation against what &lt;code&gt;search_articles&lt;/code&gt; actually returned earlier in the same run, not against a question the model supplies, and the answer card shows the question that search was for. - Retrieval is deterministic word scoring, shown in the retrieval inspector. - Questions it can't answer are recorded as gaps. - The changes it drafts publish as a new version only after a person approves, and only against the version they were written for. - On a second page, people edit articles under the same conflict rule, mark them reviewed and dismiss gaps. - Data is kept in memory, or in Postgres in the &lt;code&gt;kb_&lt;/code&gt; tables.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Eval dashboard&lt;/strong&gt; (new, &lt;code&gt;eval-dashboard&lt;/code&gt; and &lt;code&gt;eval-dashboard-claude&lt;/code&gt;): offline regression evals for an agent's versions. - A suite of cases, checked in code, runs against a version through a runner you plug in (&lt;code&gt;setCaseRunner&lt;/code&gt;). The demo replays recorded outputs and says no model was called. A case the runner couldn't run is recorded as that, not as a fail. - The page shows the pass rate over runs, a run's scorecard against production's latest run, failure clusters, and regressions and fixes case by case. A second page compares any two runs. - The agent reads, compares and starts runs. Promoting a version needs a person's approval, and the server still refuses it when the version has no finished run on the current suite, production moved since it was asked, or its latest run fails a case production passes, naming the cases. - Data is kept in memory, or in Postgres in the &lt;code&gt;evdash_&lt;/code&gt; tables.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.2.1</title>
      <link>https://candor.themethodic.com/changelog#1-2-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-2-1</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;A patch: no component changes.&lt;/p&gt;&lt;h3&gt;CLI (candor-ui 0.2.2)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Behind a proxy, &lt;code&gt;key&lt;/code&gt;, &lt;code&gt;doctor&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt; now send their own requests through &lt;code&gt;HTTPS_PROXY&lt;/code&gt; (honouring &lt;code&gt;NO_PROXY&lt;/code&gt;) on Node 24.14 or later. On Node 22.21+ and 24.0+, candor-ui says to set &lt;code&gt;NODE_USE_ENV_PROXY=1&lt;/code&gt;; on older Node, to upgrade. shadcn already used the proxy.&lt;/li&gt;&lt;li&gt;&lt;code&gt;update&lt;/code&gt; and the lockfile record matched each item file to an installed path by name and took the first match. When an item and one of its dependencies have a file of the same name, the file's type (ui, lib or component) now decides, and if that still leaves two, it stops rather than pick one.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Checks&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;CI now follows the Get started page in a brand-new Next.js app on every change: &lt;code&gt;create-next-app&lt;/code&gt;, &lt;code&gt;candor-ui init --yes&lt;/code&gt;, &lt;code&gt;candor-ui add thread message composer&lt;/code&gt;, the &amp;quot;Render it&amp;quot; code as &lt;code&gt;app/page.tsx&lt;/code&gt;, and &lt;code&gt;next build&lt;/code&gt;, against that change's registry and CLI. It also checks that &lt;code&gt;add&lt;/code&gt; recorded the items in &lt;code&gt;candor-lock.json&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Docs&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The agent skill explains theme nesting: &lt;code&gt;dark&lt;/code&gt; and &lt;code&gt;hc&lt;/code&gt; work on an inner element, &lt;code&gt;light&lt;/code&gt; doesn't switch back inside a dark one.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.2.0</title>
      <link>https://candor.themethodic.com/changelog#1-2-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-2-0</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;h3&gt;App shell (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;CommandPalette&lt;/code&gt; takes &lt;code&gt;filter&lt;/code&gt;, passed to cmdk as &lt;code&gt;(value, search, keywords) =&amp;gt; score&lt;/code&gt;. The new &lt;code&gt;matchEveryWord&lt;/code&gt; is a strict matcher: every word typed must start a word of the item's label, detail or keywords, in any order, ignoring case and accents. It reads &lt;code&gt;keywords&lt;/code&gt; only, never cmdk's &lt;code&gt;value&lt;/code&gt;, which holds ids.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Fixed:&lt;/strong&gt; closing &lt;code&gt;CommandPalette&lt;/code&gt; now puts focus back on what had it when the palette opened. Before, a palette opened by a shortcut (no &lt;code&gt;DialogTrigger&lt;/code&gt;) dropped focus to the page. A chosen item now runs after focus is back and the closing animation is done, so an item that moves focus (to a tab, a field) keeps it there. Before, the return could undo it. &lt;code&gt;onCloseAutoFocus&lt;/code&gt; lets you steer focus yourself.&lt;/li&gt;&lt;li&gt;&lt;code&gt;AppLayout&lt;/code&gt; takes &lt;code&gt;resizable&lt;/code&gt; (default true). With &lt;code&gt;resizable={false}&lt;/code&gt; the panel stays at &lt;code&gt;defaultPanel&lt;/code&gt;'s width and the divider is a plain border with no handle.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SidePanel&lt;/code&gt;: a tab can carry a &lt;code&gt;count&lt;/code&gt; (hidden at 0), read by screen readers as &lt;code&gt;countLabel&lt;/code&gt; (&amp;quot;2 need you&amp;quot;) or the &lt;code&gt;sidePanel.count&lt;/code&gt; string (joined to the name by &lt;code&gt;sidePanel.countAfterName&lt;/code&gt;), with &lt;code&gt;countTone=&amp;quot;attention&amp;quot;&lt;/code&gt; for things waiting on the person. &lt;code&gt;actions&lt;/code&gt; puts buttons at the end of the tab row (hide the panel, open full width), outside the tab list.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SessionList&lt;/code&gt; takes &lt;code&gt;groupBy&lt;/code&gt; (your own headings instead of pinned and days) with &lt;code&gt;groupOrder&lt;/code&gt;, and &lt;code&gt;showStatus&lt;/code&gt; to print each session's status in words with its dot. &lt;code&gt;Session&lt;/code&gt; gains &lt;code&gt;detail&lt;/code&gt; (a second line, such as what it is doing now) and &lt;code&gt;statusLabel&lt;/code&gt; (your word for the status). Without these the list looks as before.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Artifact panel (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ArtifactPanel&lt;/code&gt; (new, &lt;code&gt;artifact-panel&lt;/code&gt;) reads a document or file beside the work, as a &lt;code&gt;SidePanel&lt;/code&gt; tab or full width. A document's &lt;code&gt;text&lt;/code&gt; is read into safe blocks with &lt;code&gt;markdownBlocks(text, { headings: true })&lt;/code&gt;, or you pass &lt;code&gt;blocks&lt;/code&gt;. It is never rendered as HTML, so markup in a model's document stays text and its links aren't made. A file with no text shows its type and size, and an image shows the preview your app serves. &lt;code&gt;onDownload&lt;/code&gt; gets the artifact's id and the chosen format (&lt;code&gt;formats&lt;/code&gt;: Word, PDF…), and &lt;code&gt;onFullWidthChange&lt;/code&gt; adds Open full width / Back to the panel. &lt;code&gt;headingLevel&lt;/code&gt; (default 2) fits the title into your page's outline. New types in &lt;code&gt;work&lt;/code&gt;: &lt;code&gt;Artifact&lt;/code&gt; and &lt;code&gt;FileFormat&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Variants (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Plan&lt;/code&gt; takes &lt;code&gt;density=&amp;quot;compact&amp;quot;&lt;/code&gt; for inside a thread: a smaller header and tighter rows, and a step's summary only while it's running or waiting (the &amp;quot;now&amp;quot; line). &lt;code&gt;actions&lt;/code&gt; puts buttons under the steps (Pause, Stop) in any mode, beside Accept when proposed.&lt;/li&gt;&lt;li&gt;&lt;code&gt;UsageMeters&lt;/code&gt;: a usage's &lt;code&gt;estimate&lt;/code&gt; (your own figure, such as a quote) is a tick on the bar, printed under it as &amp;quot;Estimate: 2.6 USD&amp;quot;, or with your &lt;code&gt;estimateLabel&lt;/code&gt; (&amp;quot;My guess&amp;quot;). Without a limit it is printed with no tick. The meter never projects an estimate itself.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ApprovalDecision&lt;/code&gt; (new export of &lt;code&gt;approval-request&lt;/code&gt;) is a decision the work stops for, with two answers. It shows the question, the facts, what carries on meanwhile, and an optional deadline with what happens if nobody answers. The two answers are equal buttons. Nothing is pre-selected and neither is styled as the default. The agent's pick is marked, not chosen. It covers recording, decided and failed states, and &lt;code&gt;locked&lt;/code&gt; gives a reason. New types in &lt;code&gt;work&lt;/code&gt;: &lt;code&gt;Decision&lt;/code&gt; and &lt;code&gt;DecisionChoice&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;A setup gate from &lt;code&gt;AccountState&lt;/code&gt;: &lt;code&gt;steps&lt;/code&gt; lists what's left as a checklist in the card, &lt;code&gt;children&lt;/code&gt; holds your own controls, and an action can be &lt;code&gt;locked&lt;/code&gt; with its reason until the steps are done. &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;onSignOut&lt;/code&gt; are now optional (the signed-in line shows when both are set). &lt;code&gt;SetupChecklist&lt;/code&gt; takes &lt;code&gt;bare&lt;/code&gt; to sit inside another card.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;New components (Pro)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;AgentActivity&lt;/code&gt; (&lt;code&gt;agent-activity&lt;/code&gt;) shows who is working right now: each agent, what it is doing in plain words, and its state in words beside the dot (your &lt;code&gt;statusLabel&lt;/code&gt;, or the status's own). An agent that isn't working shows only its state, with nothing made up for it to be doing. It is a panel list, not TaskTray's pill of background jobs. New type in &lt;code&gt;work&lt;/code&gt;: &lt;code&gt;AgentActivityEntry&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;FileList&lt;/code&gt; (&lt;code&gt;file-list&lt;/code&gt;) shows what the work produced. Each file has its type, size and state (&amp;quot;Checked&amp;quot;, &amp;quot;Not yet checked&amp;quot;, with a tone), Open for files the reader can show, and Download (a menu when there are several formats). Files can be grouped (&amp;quot;Result 2&amp;quot;, &amp;quot;Sources&amp;quot;), with group headings at &lt;code&gt;headingLevel&lt;/code&gt; (default 3). Nothing is a link: open and download go through your handlers. New type in &lt;code&gt;work&lt;/code&gt;: &lt;code&gt;Deliverable&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ResultCard&lt;/code&gt; (&lt;code&gt;result-card&lt;/code&gt;) is a finished piece of work, handed over. It shows the answer first, as safe blocks, then a receipt of your own values as given (cost, time, what checked it), then the files, then your actions. Lines you don't pass aren't shown. New type in &lt;code&gt;work&lt;/code&gt;: &lt;code&gt;ReceiptLine&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Long histories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Thread&lt;/code&gt; takes &lt;code&gt;virtualize&lt;/code&gt; (free): only the messages in or near view are rendered, each child being one item keyed by its &lt;code&gt;key&lt;/code&gt;. The column stays a &lt;code&gt;log&lt;/code&gt;, the message holding focus stays rendered as it scrolls away (with its neighbours, so Tab still reaches the next one, and by key, so it survives older messages being added), and Jump to latest works as before. The server and the first browser render show the newest 20, so hydration matches.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SessionList&lt;/code&gt; takes &lt;code&gt;virtualize&lt;/code&gt; (Pro): only the rows in or near view, with their group headings. It starts from the top before it can be measured. Search still covers every session, and the focused row stays rendered.&lt;/li&gt;&lt;li&gt;Both use &lt;code&gt;useVirtualList&lt;/code&gt; (new free item, &lt;code&gt;use-virtual-list&lt;/code&gt;), which keeps measured heights by key, so a list that grows at either end keeps its place. Without &lt;code&gt;virtualize&lt;/code&gt;, nothing changes.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Project workspace template (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;project-workspace&lt;/code&gt; (Vercel AI SDK) and &lt;code&gt;project-workspace-claude&lt;/code&gt; (Claude Agent SDK) install under &lt;code&gt;app/project-workspace/&lt;/code&gt;. Each project is a conversation with an agent team. The rail lists projects grouped into Needs you, Projects and Finished (&lt;code&gt;SessionList&lt;/code&gt; &lt;code&gt;groupBy&lt;/code&gt;, with each state in words and a live line). The thread is in the middle. A fixed panel (&lt;code&gt;AppLayout resizable={false}&lt;/code&gt;, 404px) has four tabs: Overview (spend against the limit with the agent's estimate marked as its own, steps done, &lt;code&gt;AgentActivity&lt;/code&gt;), Plan, Files (&lt;code&gt;FileList&lt;/code&gt;, with &lt;code&gt;ArtifactPanel&lt;/code&gt; as the reader and Open full width) and History. The ⌘K palette uses &lt;code&gt;matchEveryWord&lt;/code&gt; and opens panel tabs.&lt;/li&gt;&lt;li&gt;The rules it shows, enforced on the server: - No run goes past a project's spending limit without the person. At the limit the next run is refused and a decision opens: raise the limit, or finish with what's done. - While a decision waits (&lt;code&gt;ApprovalDecision&lt;/code&gt;, nothing pre-selected), the agent doesn't work on the project. An answer is recorded once. - Files say whether they've been handed over. - The result (&lt;code&gt;ResultCard&lt;/code&gt;) puts the answer first. Its receipt comes only from what was recorded: spend against the limit, steps done, and time from start to hand-over.&lt;/li&gt;&lt;li&gt;Spend comes from the AI SDK's token counts at list price (a model with no price set is refused, since its spend couldn't be kept to the limit), or from the Claude Agent SDK's own &lt;code&gt;total_cost_usd&lt;/code&gt;. That figure is the session's running total, so each run adds only its change since the last total seen for the session. A file saved again under the same name replaces the earlier text. An answered decision stays in the thread, decided, with focus on it.&lt;/li&gt;&lt;li&gt;Storage runs in memory with no setup, or on Postgres through Drizzle when &lt;code&gt;DATABASE_URL&lt;/code&gt; is set (tables start with &lt;code&gt;workspace_&lt;/code&gt;, with migrations and a seed). It is tested on both, including two answers racing and two questions asked at once.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.1.1</title>
      <link>https://candor.themethodic.com/changelog#1-1-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-1-1</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;h3&gt;Fixed&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Getting started works as pasted.&lt;/strong&gt; /get-started has a &amp;quot;Render it&amp;quot; step, and every docs example is shown and copied with the import paths an app has after &lt;code&gt;add&lt;/code&gt; (&lt;code&gt;@/components/…&lt;/code&gt;, &lt;code&gt;@/lib/…&lt;/code&gt;) and &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt;. A test checks every example's imports against where shadcn installs each file.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The theme wins over shadcn's defaults.&lt;/strong&gt; In a fresh Next.js app, the colour blocks and &lt;code&gt;.dark&lt;/code&gt; variant that &lt;code&gt;shadcn init&lt;/code&gt; writes came after the &lt;code&gt;candor.css&lt;/code&gt; import and replaced Candor's theme (only system dark mode survived). &lt;code&gt;candor-ui init --yes&lt;/code&gt; now comments out shadcn's default &lt;code&gt;:root&lt;/code&gt; and &lt;code&gt;.dark&lt;/code&gt; colour blocks and its dark variant; &lt;code&gt;doctor&lt;/code&gt; flags them. Overrides you wrote yourself, and a dark variant of your own, are left alone, and overriding Candor's tokens after &lt;code&gt;candor.css&lt;/code&gt; works as before.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui add&lt;/code&gt; records what it installs.&lt;/strong&gt; Most fresh installs were reported as &amp;quot;already installed, with changes&amp;quot; and left out of &lt;code&gt;candor-lock.json&lt;/code&gt;, so &lt;code&gt;update&lt;/code&gt; couldn't merge them. The CLI is 0.2.1.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;candor-ui key&lt;/code&gt; checks the key&lt;/strong&gt; with the registry (10-second timeout) and says whether it's valid and for which tier; &lt;code&gt;doctor&lt;/code&gt; does the same.&lt;/li&gt;&lt;li&gt;A paid item without a key now says to run &lt;code&gt;npx candor-ui key &amp;lt;your key&amp;gt;&lt;/code&gt; and where the key is; errors carry a &lt;code&gt;message&lt;/code&gt; so shadcn no longer prints &amp;quot;undefined&amp;quot;.&lt;/li&gt;&lt;li&gt;One install story: docs pages, llms.txt and the skill use the &lt;code&gt;candor-ui&lt;/code&gt; CLI, say where files land and which import paths to use, and the skill covers AG-UI. Twelve items' one-line descriptions now describe the item, not a helper in its file.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.1.0</title>
      <link>https://candor.themethodic.com/changelog#1-1-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-1-0</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;h3&gt;Languages and right to left&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;LocaleProvider&lt;/code&gt; (new free item, &lt;code&gt;locale&lt;/code&gt;) sets the interface's words, the locale for dates and numbers, and the text direction. Every fixed string in the kit (labels, buttons, empty states, screen-reader text, &amp;quot;just now&amp;quot;) is in a table per component, English by default, and you override any of them by the component's name: &lt;code&gt;&amp;lt;LocaleProvider locale=&amp;quot;fr&amp;quot; strings={{ thread: { jumpToLatest: &amp;quot;Aller au plus récent&amp;quot; } }}&amp;gt;&lt;/code&gt;. Strings take &lt;code&gt;{name}&lt;/code&gt; placeholders and plural forms, so overrides stay plain data. Each docs page lists its keys. &lt;code&gt;TermsProvider&lt;/code&gt; still names your nouns.&lt;/li&gt;&lt;li&gt;Right-to-left layouts: components use logical spacing and edges (&lt;code&gt;ms-&lt;/code&gt;, &lt;code&gt;ps-&lt;/code&gt;, &lt;code&gt;start-&lt;/code&gt;, &lt;code&gt;border-s&lt;/code&gt;), directional icons mirror, tree, inbox and the layout's resize handle swap their arrow keys, and AppLayout's navigation and panel sheets slide in from the matching sides. &lt;code&gt;Sheet&lt;/code&gt;'s &lt;code&gt;side&lt;/code&gt; stays the physical edge you name. &lt;code&gt;dir&lt;/code&gt; follows the locale (Arabic, Hebrew, Persian, Urdu…) or is set on the provider; set it on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; as well.&lt;/li&gt;&lt;li&gt;&lt;code&gt;RelativeTime&lt;/code&gt; takes &lt;code&gt;format=&amp;quot;date&amp;quot; | &amp;quot;datetime&amp;quot; | &amp;quot;time&amp;quot;&lt;/code&gt; for an absolute time, and its words and units follow the locale.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Messages&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Message&lt;/code&gt; takes &lt;code&gt;actions&lt;/code&gt;: &lt;code&gt;false&lt;/code&gt; hides the row under an agent reply (copy, retry, rating), a node replaces it. Either way the model and cost stay visible, on their own line (&lt;code&gt;MessageAttribution&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;Message's parts are exported: &lt;code&gt;MessageHeader&lt;/code&gt; (name, detail, time, and a slot for more), &lt;code&gt;MessageBody&lt;/code&gt; (reasoning, blocks, the streaming caret) and &lt;code&gt;MessageFooter&lt;/code&gt; (stopped and failed states, sources, who checked it, actions), to rebuild a message your way. App content still goes in a &lt;code&gt;card&lt;/code&gt; block, so messages stay plain data.&lt;/li&gt;&lt;li&gt;Thread pieces (free): &lt;code&gt;ThreadDivider&lt;/code&gt; marks a day (&amp;quot;Today&amp;quot;, &amp;quot;Yesterday&amp;quot;, a date) or a chapter; &lt;code&gt;ThreadEvent&lt;/code&gt; is a quiet centred line for something that happened (&amp;quot;Sam joined&amp;quot;), with an &lt;code&gt;attention&lt;/code&gt; tone and a time, and system messages are now drawn with it; &lt;code&gt;FoldedTurns&lt;/code&gt; folds a run of turns into one line with your summary and opens them in place.&lt;/li&gt;&lt;li&gt;Attachments (free, &lt;code&gt;attachment-preview&lt;/code&gt;): a new &lt;code&gt;attachments&lt;/code&gt; message block shows sent files as tiles, with an image preview when your app supplies a &lt;code&gt;previewUrl&lt;/code&gt;, an icon by type otherwise, and the size in the locale. A file is never a link: &lt;code&gt;onOpenAttachment&lt;/code&gt; on &lt;code&gt;Message&lt;/code&gt; makes each tile a button. &lt;code&gt;AttachmentChip&lt;/code&gt; is the composer's chip, &lt;code&gt;AttachmentList&lt;/code&gt; a row of tiles. &lt;code&gt;Attachment&lt;/code&gt; gains optional &lt;code&gt;mediaType&lt;/code&gt; and &lt;code&gt;previewUrl&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Composer&lt;/code&gt; attaches files that are pasted or dropped on it (with a drop target while dragging), and takes &lt;code&gt;accept&lt;/code&gt; for the picker.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;New block kind.&lt;/strong&gt; &lt;code&gt;MessageBlock&lt;/code&gt; has a new kind, &lt;code&gt;attachments&lt;/code&gt;. If you &lt;code&gt;switch&lt;/code&gt; over block kinds in your own code, the &lt;code&gt;default&lt;/code&gt; branch the 1.0 notes asked for covers it; without one, TypeScript will point at the switch.&lt;/li&gt;&lt;li&gt;Syntax highlighting in &lt;code&gt;Payload&lt;/code&gt; (free, &lt;code&gt;highlight&lt;/code&gt;): code is split into tokens (keywords, strings, comments, numbers, keys, tags) and rendered as spans of text, never HTML, by a small built-in tokenizer for JS/TS, Python, SQL, JSON, shell, YAML, CSS, HTML/XML, Go, Rust, Java and C. Off by default so nothing changes: turn it on with &lt;code&gt;&amp;lt;Payload highlight&amp;gt;&lt;/code&gt; or &lt;code&gt;data-syntax=&amp;quot;highlight&amp;quot;&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;. Its colours are in the theme's contrast checks.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Payload&lt;/code&gt; takes &lt;code&gt;bare&lt;/code&gt;: just the code, without the frame, language label or copy button, for inside a card.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Theme&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Size tokens on the &lt;code&gt;--cd-*&lt;/code&gt; scheme: &lt;code&gt;--cd-text-prose&lt;/code&gt; (conversation text, Tailwind &lt;code&gt;text-prose&lt;/code&gt;; it follows &lt;code&gt;--cd-text-md&lt;/code&gt;, 14px, as before), &lt;code&gt;--cd-thread-width&lt;/code&gt; (48rem, the message column and composer) and &lt;code&gt;--cd-sidebar-width&lt;/code&gt; (16rem, AppLayout's sidebar). Set them after &lt;code&gt;candor.css&lt;/code&gt; to fit your brand.&lt;/li&gt;&lt;li&gt;A compact preset: &lt;code&gt;data-density=&amp;quot;compact&amp;quot;&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or any container gives 14px conversation text, 13px body and label text (&lt;code&gt;text-base&lt;/code&gt; and below; headings keep their sizes), a 44rem thread and a 14rem sidebar.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Updates&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;npx candor-ui update&lt;/code&gt; (CLI 0.2.0) updates installed items and keeps your changes, with a three-way merge and a clear conflict report; &lt;code&gt;add&lt;/code&gt; now writes &lt;code&gt;candor-lock.json&lt;/code&gt;. See &amp;quot;How versions work&amp;quot; above.&lt;/li&gt;&lt;li&gt;The registry serves every release at &lt;code&gt;/r/v/&amp;lt;version&amp;gt;/&amp;lt;name&amp;gt;.json&lt;/code&gt;, gated exactly like the latest, from 1.0.0 on.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Fixed&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Dates and numbers no longer cause hydration mismatches when the server's locale or time zone differs from the browser's. Without a &lt;code&gt;locale&lt;/code&gt;, numbers render as en-US on the server and switch to the browser's locale after hydration, and absolute times show their ISO date (UTC) until then. Set &lt;code&gt;locale&lt;/code&gt; and &lt;code&gt;timeZone&lt;/code&gt; on the provider to render the final text on the server.&lt;/li&gt;&lt;li&gt;Counts of one read in the singular where the English used to say &amp;quot;1 steps&amp;quot;, &amp;quot;1 runs&amp;quot;, &amp;quot;1 tests&amp;quot;.&lt;/li&gt;&lt;li&gt;Product words that leaked from another app are gone: Know's labels read &amp;quot;Knowledge sources&amp;quot;, &amp;quot;Nothing has been read yet.&amp;quot;, &amp;quot;What was retrieved&amp;quot; and &amp;quot;Add knowledge&amp;quot;; doc comments no longer mention Salesforce or Know.&lt;/li&gt;&lt;li&gt;&lt;code&gt;MetadataDiff&lt;/code&gt; is now &lt;code&gt;ChangeDiff&lt;/code&gt;, labelled &amp;quot;Changes&amp;quot;; the old name still works and is deprecated until 2.0 (the item is still installed as &lt;code&gt;metadata-diff&lt;/code&gt;). Doc comments in the work and chat types no longer use Salesforce examples.&lt;/li&gt;&lt;li&gt;&lt;code&gt;AccessRequest&lt;/code&gt; shows the environment a request was sent for by its name (and Production or its detail), not the id &lt;code&gt;onSend&lt;/code&gt; returned.&lt;/li&gt;&lt;li&gt;&lt;code&gt;BulletBar&lt;/code&gt; bands now shade from the end when &lt;code&gt;higherIsBetter={false}&lt;/code&gt;, so the darkest end is always the worst.&lt;/li&gt;&lt;li&gt;&lt;code&gt;EmailPreview&lt;/code&gt; shows an email inline, without a whole &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; document, with its title at your page's heading level. &lt;code&gt;renderEmail&lt;/code&gt; and &lt;code&gt;EmailLayout&lt;/code&gt; take the email's language and words.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ChartFrame&lt;/code&gt; and &lt;code&gt;AppLayout&lt;/code&gt; take &lt;code&gt;defaultWidth&lt;/code&gt;, used until they can measure themselves (on the server, and in jsdom tests, which measure everything as 0). &lt;code&gt;ChartSizeProvider&lt;/code&gt; sets it for every chart inside.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SsoSetup&lt;/code&gt; and &lt;code&gt;SubscriptionStatus&lt;/code&gt; take a &lt;code&gt;label&lt;/code&gt; for their landmark, so two on one page can be told apart.&lt;/li&gt;&lt;li&gt;Dates in the audit log, downgrade impact and subscription status use the locale's medium date style (&amp;quot;Nov 5, 2026&amp;quot;), the same as the rest of the kit.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Notes&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Components that now read the provider call hooks, so about two dozen that were server components gained &lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt;. They still render in React Server Components apps. &lt;code&gt;EmailLayout&lt;/code&gt; stays server-safe: it takes &lt;code&gt;strings&lt;/code&gt; and &lt;code&gt;lang&lt;/code&gt; as props, and so does &lt;code&gt;renderEmail&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Text the adapters produce (tool errors, approval titles), the A2UI standard cards and &lt;code&gt;applyA2uiMessage&lt;/code&gt;'s diagnostics are data, not interface chrome, and stay English in this release.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.0.1</title>
      <link>https://candor.themethodic.com/changelog#1-0-1</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-0-1</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;h3&gt;Fixed&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;npx candor-ui init --yes&lt;/code&gt; sets up shadcn in a new project without stopping for questions; at a terminal, &lt;code&gt;init&lt;/code&gt; runs shadcn's own setup. The CLI is 0.1.2.&lt;/li&gt;&lt;li&gt;Pro's pricing card counts what a Pro key unlocks (the full-stack blocks and templates are Premium).&lt;/li&gt;&lt;li&gt;Docs pages for blocks no longer scroll sideways on phones, inline code reads as code, and names read as written (AG-UI, MCP, SSO).&lt;/li&gt;&lt;li&gt;Unknown pages answer 404.&lt;/li&gt;&lt;li&gt;A malformed licence key is reported as not valid, and the no-key message says where to buy one.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Candor UI 1.0.0</title>
      <link>https://candor.themethodic.com/changelog#1-0-0</link>
      <guid isPermaLink="true">https://candor.themethodic.com/changelog#1-0-0</guid>
      <pubDate>Thu, 05 Nov 2026 00:00:00 GMT</pubDate>
      <description>&lt;p&gt;The first public release.&lt;/p&gt;&lt;h3&gt;Components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;201 registry items: chat, agent work (plans, approvals, diffs, runs, recovery), the app shell, team and admin screens, knowledge, data and charts, ops and cost, evals and billing.&lt;/li&gt;&lt;li&gt;Honest by design: unknown values show as unknown, a control that can't be used says why, nothing is pre-selected in a decision, and model output is never rendered as HTML or a clickable link.&lt;/li&gt;&lt;li&gt;Light, dark and high-contrast themes, with 120 contrast checks. Every component has a live docs example, and CI runs axe on each one; tab lists, the toast and side panel also have keyboard and screen-reader tests.&lt;/li&gt;&lt;li&gt;Works in Vite and in Next.js with React Server Components (&lt;code&gt;&amp;quot;use client&amp;quot;&lt;/code&gt; where needed, a hydration-safe clock).&lt;/li&gt;&lt;li&gt;Works in shadcn projects on Radix or Base UI styles: primitives take &lt;code&gt;asChild&lt;/code&gt; and Base UI's &lt;code&gt;render&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Adapters and agent UI&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Vercel AI SDK 7, Claude Agent SDK and AG-UI adapters, all with the same shape: messages, a composer, and tool calls waiting for a person.&lt;/li&gt;&lt;li&gt;A person's own words are kept exactly as typed (a &lt;code&gt;plain&lt;/code&gt; block: line breaks kept, nothing parsed); only an agent's text is read as safe markdown. &lt;code&gt;markdownBlocks(text, { headings: true })&lt;/code&gt; turns &lt;code&gt;#&lt;/code&gt; lines into &lt;code&gt;heading&lt;/code&gt; blocks. If you &lt;code&gt;switch&lt;/code&gt; over &lt;code&gt;MessageBlock&lt;/code&gt; kinds in your own code, give it a &lt;code&gt;default&lt;/code&gt; branch: new kinds can arrive in a minor release.&lt;/li&gt;&lt;li&gt;The inline node for a value read from the user's system is &lt;code&gt;measured&lt;/code&gt; (it was &lt;code&gt;orgData&lt;/code&gt;, which still works and is deprecated until 2.0).&lt;/li&gt;&lt;li&gt;A2UI surfaces drawn with Candor's components, and an MCP Apps frame that runs only behind a separate-origin sandbox.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Blocks and templates (Premium)&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Eight full-stack blocks, each for the Vercel AI SDK and the Claude Agent SDK: approval-gated change, plan-build- review, run console, eval review loop, cost guard, agent admin, audit and data controls, human handoff.&lt;/li&gt;&lt;li&gt;Three templates: an agent ops console, an approvals inbox and a support copilot.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For coding agents&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;A Candor skill (&lt;code&gt;npx skills add MethodicDev/candor&lt;/code&gt;), llms.txt and llms-full.txt, and setup for shadcn's MCP server.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Licences&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The free tier (43 items) is MIT. Everything else is under the Candor UI Commercial Licence.&lt;/li&gt;&lt;/ul&gt;</description>
    </item>
  </channel>
</rss>
