<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cerb</title>
    <description>Shared inboxes for human + AI teams. Route, automate, and integrate the work, with AI teammates built in. Refined over 24 years. Free to self-host.</description>
    <link>https://cerb.ai/</link>
    <atom:link href="https://cerb.ai/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 15 Sep 2026 03:32:51 +0000</pubDate>
    <lastBuildDate>Tue, 15 Sep 2026 03:32:51 +0000</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
    
      <item>
        <title>11.1.11</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.11.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.11)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on September 13, 2026. It includes &lt;strong&gt;9&lt;/strong&gt; minor features, fixes, and security patches from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;added&quot;&gt;Added&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[Data Queries/Tickets]&lt;/strong&gt; In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worklist.subtotals&lt;/code&gt; data queries, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;of:ticket&lt;/code&gt; now supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;by:sender.first&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;by:sender.last&lt;/code&gt;. These keys were suggested by autocompletion but returned an &quot;Unknown by: field&quot; error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data Queries]&lt;/strong&gt; Fixed an issue with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worklist.subtotals&lt;/code&gt; data queries when grouping time-series data by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@quarter&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@quarterofyear&lt;/code&gt; against a &apos;date&apos; custom field.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mailboxes]&lt;/strong&gt; Fixed an issue with mailboxes where consecutive failure counts could exceed the field range of (0-127).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded guzzlehttp/guzzle to 7.15.3 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded smarty/smarty to 4.5.7 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded league/commonmark to 2.10.0 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[OAuth Apps/Security]&lt;/strong&gt; The OAuth2 authorization flow now returns to the hostname in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_HOSTNAME&lt;/code&gt; after a worker signs in or grants consent. On instances where the server sees a different hostname than workers browse, clients no longer get bounced to that other address partway through the flow.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[OAuth/Security]&lt;/strong&gt; OAuth2 consent is now bound to the app and scopes it was granted for. An approval left behind by an abandoned authorization flow can no longer approve a different app in the same browser session.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Support Center/Security]&lt;/strong&gt; Confirmation codes for password recovery, registration, and adding an email address now expire in sync with the rate-limit window. Thanks to kta1kri for the report.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 13 Sep 2026 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.11/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.11/</guid>
        
        
      </item>
    
      <item>
        <title>In Development: 12.0</title>
        <description>
&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/12.0.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (12.0)&lt;/strong&gt; is a &lt;strong&gt;platform upgrade&lt;/strong&gt; in development as of September 07, 2026.  It includes more than &lt;strong&gt;479&lt;/strong&gt; new features and improvements from community feedback.&lt;/p&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/OkYu0Z-VskU&quot; title=&quot;Cerb 12.0 in 5 mins: 500 features, AI workers, free to self-host&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#important-release-notes&quot; id=&quot;markdown-toc-important-release-notes&quot;&gt;Important Release Notes&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#added&quot; id=&quot;markdown-toc-added&quot;&gt;Added&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#licensing&quot; id=&quot;markdown-toc-licensing&quot;&gt;Licensing&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#ai-agents&quot; id=&quot;markdown-toc-ai-agents&quot;&gt;AI agents&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#automations&quot; id=&quot;markdown-toc-automations&quot;&gt;Automations&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#queues&quot; id=&quot;markdown-toc-queues&quot;&gt;Queues&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#search-indexes&quot; id=&quot;markdown-toc-search-indexes&quot;&gt;Search indexes&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#cerb-ui&quot; id=&quot;markdown-toc-cerb-ui&quot;&gt;Cerb UI&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#charts-and-dashboards&quot; id=&quot;markdown-toc-charts-and-dashboards&quot;&gt;Charts and dashboards&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#tasks-and-projects&quot; id=&quot;markdown-toc-tasks-and-projects&quot;&gt;Tasks and projects&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#setup-and-developers&quot; id=&quot;markdown-toc-setup-and-developers&quot;&gt;Setup and developers&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#worklists&quot; id=&quot;markdown-toc-worklists&quot;&gt;Worklists&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#metrics&quot; id=&quot;markdown-toc-metrics&quot;&gt;Metrics&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#workspaces&quot; id=&quot;markdown-toc-workspaces&quot;&gt;Workspaces&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#service-tokens&quot; id=&quot;markdown-toc-service-tokens&quot;&gt;Service tokens&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#scheduler&quot; id=&quot;markdown-toc-scheduler&quot;&gt;Scheduler&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#security&quot; id=&quot;markdown-toc-security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#plugins&quot; id=&quot;markdown-toc-plugins&quot;&gt;Plugins&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#miscellaneous&quot; id=&quot;markdown-toc-miscellaneous&quot;&gt;Miscellaneous&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#changed&quot; id=&quot;markdown-toc-changed&quot;&gt;Changed&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#deprecated&quot; id=&quot;markdown-toc-deprecated&quot;&gt;Deprecated&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#removed&quot; id=&quot;markdown-toc-removed&quot;&gt;Removed&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#fixed&quot; id=&quot;markdown-toc-fixed&quot;&gt;Fixed&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#platform&quot; id=&quot;markdown-toc-platform&quot;&gt;Platform&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#security-1&quot; id=&quot;markdown-toc-security-1&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;cerb-box note&quot;&gt;
	&lt;p&gt;
		&lt;b&gt;This upgrade is free for everyone.&lt;/b&gt; You never need a current subscription to run the
		latest version of Cerb, and there&apos;s nothing to renew before upgrading. Cerb Cloud
		subscribers will be upgraded automatically.
	&lt;/p&gt;
&lt;/div&gt;

&lt;h1 id=&quot;important-release-notes&quot;&gt;Important Release Notes&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/docs/backups/&quot;&gt;&lt;strong&gt;Always make a backup before upgrading!&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Cerb 12.0&lt;/strong&gt; requires &lt;strong&gt;PHP 8.5+&lt;/strong&gt; and &lt;strong&gt;MySQL 8.0+&lt;/strong&gt; (or &lt;strong&gt;MariaDB 10.5+&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;To upgrade your installation, &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;added&quot;&gt;Added&lt;/h2&gt;

&lt;h3 id=&quot;licensing&quot;&gt;Licensing&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Licensing]&lt;/strong&gt; &lt;strong&gt;Self-hosted Cerb is now free, with unlimited workers and unlimited seats.&lt;/strong&gt; Cerb has always been free to self-host, but Community Edition allowed only a single simultaneous worker login, and that limit is gone – there&apos;s no seat enforcement anywhere, and no worker is displaced to make room for another. What a license raises instead, at &lt;strong&gt;Setup » Configure » Subscription&lt;/strong&gt;, is &lt;strong&gt;concurrency&lt;/strong&gt;: how much background work and how many AI agent turns your installation can run at once. Every install, licensed or not, gets a floor of three concurrency slots, and a license carrying fewer than three grants three. A license removes the ceiling on that pool – a licensed installation sets its own slot count on &lt;strong&gt;Setup » Configure » &lt;a href=&quot;/docs/setup/configure/queues/&quot;&gt;Queues&lt;/a&gt;&lt;/strong&gt; – and unlocks &lt;a href=&quot;/docs/setup/configure/queues/&quot;&gt;lane configuration&lt;/a&gt;, so the pool can be divided between batch work and agent turns rather than following a fixed formula. A license also raises how many agent turns a single slot carries at once, from two to six – an agent turn spends nearly all of its life waiting on a model provider, so that multiplier is most of what a busy install feels. Licensed-only plugins will join that list by release. An expired license drops concurrency back to the community floor – three slots and the default lane split, with a stored split preserved and reapplied if the subscription returns – while every feature keeps working and workers and seats stay unlimited, so lapsed coverage slows an installation down rather than locking anyone out.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/subscription-concurrency.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;ai-agents&quot;&gt;AI agents&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/TPSTDjX6Unw&quot; title=&quot;AI agents in the sidebar of Cerb editors&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents]&lt;/strong&gt; Added &lt;strong&gt;&lt;a href=&quot;/docs/agents/&quot;&gt;AI workers&lt;/a&gt;&lt;/strong&gt;. An agent is an ordinary &lt;a href=&quot;/docs/workers/&quot;&gt;worker&lt;/a&gt; record with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_ai&lt;/code&gt; flag rather than a separate record type, so it can own tickets, be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mentioned&lt;/code&gt;, join groups, and hold API credentials like anyone else. An AI worker never has an interactive session (logins and SSO are refused), and doesn&apos;t require an email address.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/ai-worker.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent Models/LLMs]&lt;/strong&gt; Added &lt;strong&gt;&lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;Agent Model&lt;/a&gt;&lt;/strong&gt; records for configuring the LLM models available to automations and agents. A model record holds its provider, model ID, optional API endpoint URL, an encrypted &lt;a href=&quot;/docs/records/types/connected_account/&quot;&gt;connected account&lt;/a&gt; for credentials, its context window, a display icon and color, and a block of provider-specific parameters. It also carries an availability status – &lt;strong&gt;Available&lt;/strong&gt;, &lt;strong&gt;Unlisted&lt;/strong&gt;, or &lt;strong&gt;Disabled&lt;/strong&gt; – and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;priority&lt;/code&gt;. Unlisted is the state for a model you want reachable by name without it turning up wherever something asks for &quot;a model&quot;, and priority is the order models are offered in when nothing names one. Automations reference a model by name instead of repeating a provider block inline, so credentials and tuning live in one place. Because the endpoint is overridable, an OpenAI-compatible provider entry can point at a self-hosted or proxied server, which is how a locally served model is configured. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test&lt;/code&gt; button sends one short message to verify the credentials and model string before the record is used.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent Models/LLMs]&lt;/strong&gt; The model ID field on an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; record autocompletes. It starts from the IDs shipped with each provider, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Refresh&lt;/code&gt; button replaces those with your own account&apos;s catalog – fetched live from the provider using the credentials in the form, so it works before the record has ever been saved. The field stays free text either way, so a model ID works the day it ships whether or not it&apos;s in a list. Picking a model fills in the record&apos;s name, along with its context window and image support wherever the provider publishes them, and shows the provider&apos;s own description of it as a hint. A refresh that fails says why, reporting the provider&apos;s own error rather than quietly falling back to the shipped list.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-model.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agent Models]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;Agent models&lt;/a&gt; now record what they can do and how they compare, so an &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; can describe the model it needs instead of naming one. The idea is one line: hard requirements belong to the pool, and best-effort preferences belong to the caller. A model that can&apos;t accept images isn&apos;t eligible at all, because sending it one is an error; asking a model to think harder costs nothing on a model that thinks less.&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;Capabilities&lt;/strong&gt; are facts about the model – whether it accepts images (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVision:&lt;/code&gt;) and whether it supports extended thinking (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasThinking:&lt;/code&gt;) – and they filter, yes or no. &lt;strong&gt;Ratings&lt;/strong&gt; are comparisons, set as a row of four glyphs you fill in like a star rating: Intelligence in brains, Speed in bolts, Privacy in locks, and Cost in coins. They work as floors and as sort orders, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;intelligence:&amp;gt;=advanced privacy:&amp;gt;=zdr cost:&amp;lt;=cheap&lt;/code&gt; is one query expressing three different kinds of requirement.&lt;/p&gt;

    &lt;p&gt;Every tier has a name you can type: intelligence runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basic&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;efficient&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;advanced&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frontier&lt;/code&gt;; speed runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slow&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;moderate&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fast&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instant&lt;/code&gt;; cost runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;free&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cheap&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;moderate&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;premium&lt;/code&gt;. Privacy is a ladder where each step includes the ones below it – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;standard&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no-training&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zdr&lt;/code&gt;, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local&lt;/code&gt; – so asking for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privacy:&amp;gt;=zdr&lt;/code&gt; picks up self-hosted models too without naming them. It&apos;s a hard requirement rather than a preference on purpose: a retention rule that was requested and quietly ignored looks exactly like one that was honored. Cost is the one rating where less is better, and the editor says so; it&apos;s a rough tier for routing, not billing.&lt;/p&gt;

    &lt;p&gt;The tier names are deliberately separate from the values behind them, which means the scale can move as the field does – when today&apos;s frontier models become ordinary, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frontier&lt;/code&gt; is repointed and existing records read as the tier below it without a single row being rewritten. Ratings start blank and unrated models sort last, so an installation that never fills them in behaves exactly as it did before. The free-text Description field is gone: these fields say more about a model than a sentence did, and unlike prose they can be searched and routed on. The provider&apos;s own description of a model still appears as a hint while you&apos;re picking one.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-model-ratings.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agent Models]&lt;/strong&gt; An &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt;&apos;s ratings draw as meters wherever they appear, with one color per rating so you can tell them apart without reading the labels: intelligence is purple, speed is orange, privacy is blue, and cost is green. Cost reads as money rather than as a score because it&apos;s the one rating where a higher tier is worse. You&apos;ll see them on the agent model worklist, profile, and card, matching the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;agent prompt&lt;/a&gt;&apos;s model picker, and the model editor keeps its glyphs tinted to the same colors. Each meter names its tier in a tooltip. The worklist shows all four ratings by default, since four compact meters fit where four words don&apos;t. Tier names are capitalized for display only, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ZDR&lt;/code&gt; reads as an acronym while search queries and bulk updates use the lowercase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zdr&lt;/code&gt; you type.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-model-worklist.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agent Models]&lt;/strong&gt; The &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agentPrompt&lt;/code&gt;&lt;/a&gt; model picker now shows what each model can do and how it compares, so the choice is informed before it&apos;s made. Picking a model used to mean reading a list of names: everything that would inform the choice – whether it can see an image, whether it thinks, how capable or fast or private or expensive it is – lived on the model record, one navigation away from the moment you were deciding.&lt;/p&gt;

    &lt;p&gt;Vision and thinking now appear beside each model&apos;s name, with intelligence, speed, privacy, and cost as small meters underneath. Capability marks appear only when a model has them, so a model that can&apos;t accept images is visibly bare beside one that can – and that absence is the useful signal, because it&apos;s the difference between choosing a text-only model on purpose and choosing it by accident.&lt;/p&gt;

    &lt;p&gt;Ratings draw as four blocks per measure at the same position on every row. Blocks rather than a bar on purpose: there are exactly four tiers and nothing between them, and three-of-four against four-of-four is a count you take in at a glance where a length is a judgement call. It&apos;s also how you set the rating on the model itself, so the two places you meet a rating look like the same thing. An unrated model keeps its blocks in gray rather than leaving a gap, which is what makes a partly rated set still readable. The ratings are what the model record claims, not measurements, and the tooltips say so.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-model-picker.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Models]&lt;/strong&gt; The pool of &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent models&lt;/a&gt; an automation may use is resolved by &lt;strong&gt;searching&lt;/strong&gt; them rather than from a hand-maintained list. Adding a model puts it in every pool it qualifies for with no edit anywhere, and a pool can ask about anything a model records – its capabilities, its ratings, its context window, or your own custom fields. This is the resolver the &lt;a href=&quot;/docs/automations/commands/llm.router/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.router:&lt;/code&gt;&lt;/a&gt; command and the implicit default are both built on. A search can only ever &lt;em&gt;narrow&lt;/em&gt; a pool: unlisted and disabled models are excluded before the caller&apos;s search is applied, and each model&apos;s status is re-checked on every resolve, so unlisting a model takes it out of every pool immediately. That&apos;s what makes it safe to let an &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; write one. Omit a search entirely and you get every available model, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;priority&lt;/code&gt; order an admin set.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; In &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt;, added the &lt;a href=&quot;/docs/automations/commands/llm.router/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.router:&lt;/code&gt;&lt;/a&gt; command. It resolves one or more &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; searches to a list of models a script can work with as data – to round-robin them, weight them by cost, skip one that&apos;s over a rate or spend budget, balance across credentials, or feed two commands from a single resolution. Nothing names a model and nothing names a router record, so a shared automation asks for what the &lt;em&gt;work&lt;/em&gt; needs rather than for something that has to already exist on the installation it&apos;s running on.&lt;/p&gt;

    &lt;p&gt;Each search is its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models_query/&amp;lt;name&amp;gt;:&lt;/code&gt; key: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models_query/work: hasVision:y&lt;/code&gt; says this turn is sending an image, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models_query/pool:&lt;/code&gt; can carry what an admin allows through a &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt; config value. The first query decides the set and its order and every later one only narrows it, so there&apos;s never a question of whose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sort:&lt;/code&gt; wins. Omit the input entirely and you get the zero-config pool.&lt;/p&gt;

    &lt;p&gt;A blank query is deliberately kept rather than dropped – a restriction that quietly disappears when a setting happens to be empty looks exactly like one being honored – so annotate a key &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@optional:&lt;/code&gt; when you mean to drop it. To simply &lt;em&gt;use&lt;/em&gt; models, let &lt;a href=&quot;/docs/automations/commands/llm.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt;&lt;/a&gt; fall through to the default pool instead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Agents]&lt;/strong&gt; The &lt;a href=&quot;/docs/automations/commands/llm.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt;&lt;/a&gt; command takes an optional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent:&lt;/code&gt; input naming the AI worker a turn runs as. The transcript picks up that worker&apos;s name and image, and the conversation uses that agent&apos;s memory and credentials. An agent is &lt;strong&gt;identity, not model policy&lt;/strong&gt; – naming one says who the work is attributed to, never what it may run, so the same agent can do cheap work and expensive work and which models a turn may use depends on the work rather than on whose name is on it. A human or disabled worker is rejected.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; &lt;a href=&quot;/docs/automations/commands/llm.chat/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.chat:&lt;/code&gt;&lt;/a&gt; accepts an agent model by name through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model:&lt;/code&gt; instead of repeating a provider block inline. Autocompletion reads the records rather than a static list, so a newly added model appears on reload. Disabled records are excluded, since they can&apos;t be referenced.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Interactions]&lt;/strong&gt; Added the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agentPrompt&lt;/code&gt;&lt;/a&gt; form element for &lt;a href=&quot;/docs/interactions/&quot;&gt;worker interactions&lt;/a&gt; – the composer a worker types into when an automation runs an agent conversation. It supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mention&lt;/code&gt; completion for workers and filesystem files, image paste and attachment, model selection, and custom slash commands, including rewrite commands that expand in the browser before the turn is submitted.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-prompt.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents]&lt;/strong&gt; Added &lt;strong&gt;&lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;Agent Filesystem&lt;/a&gt;&lt;/strong&gt; records – named volumes of &lt;a href=&quot;/docs/records/types/agent_file/&quot;&gt;files&lt;/a&gt; that agents and workers can both read and write. Each volume tracks its file count and total size.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Automations]&lt;/strong&gt; Agents can &lt;a href=&quot;/docs/agents/#agent-filesystems&quot;&gt;mount virtual filesystems&lt;/a&gt; through a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent_terminal&lt;/code&gt; tool. An automation lists the volumes to mount under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mounts:&lt;/code&gt;, and the agent can read and write them for the rest of the conversation. Each mount can be read-only (the default) or read-write, mounted at a chosen path, and provisioned on first use. Because one tool covers every volume, the tool schema stays constant as mounts change – which keeps the cached prompt prefix intact.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents]&lt;/strong&gt; &lt;a href=&quot;/docs/agents/#filesystem-commands&quot;&gt;Agent filesystems&lt;/a&gt; are worked with using familiar file commands: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edit&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pwd&lt;/code&gt;. The same command set is available to an agent through its tool and to a worker through the Setup terminal, so the two can&apos;t drift. Command output can be piped through a Twig filter chain, and oversized output spools to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; scratch area.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-filesystem-terminal.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Filesystem]&lt;/strong&gt; Added ZIP bulk import for agent filesystems. Upload an archive and its files are imported by a background &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt;, with progress shown on the filesystem record.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Filesystem]&lt;/strong&gt; Added an &apos;Agent Filesystem&apos; card widget. It shows a volume&apos;s file count and size, imports a ZIP archive, and displays a history of past imports.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents]&lt;/strong&gt; Where an agent chat appears is part of the &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt;, not a separate list to keep in sync with it. Every &lt;a href=&quot;/docs/toolbars/interactions/agent.pane/&quot;&gt;agent pane&lt;/a&gt; and the command bar lists the agents enabled for &lt;em&gt;that&lt;/em&gt; surface, each with its own name and picture and a second line saying what it&apos;s for. An agent is enabled somewhere by having a block for that surface in its own configuration, so setting one up is one record rather than a record and a toolbar section that have to agree – and one shared &lt;a href=&quot;/docs/interactions/&quot;&gt;interaction&lt;/a&gt; serves every agent instead of being copied per agent.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Interactions]&lt;/strong&gt; Added the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/uiCommand/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uiCommand&lt;/code&gt;&lt;/a&gt; await for driving a host editor from an &lt;a href=&quot;/docs/interactions/&quot;&gt;interaction&lt;/a&gt;. An agent chat can read and write the editor it was launched beside. A single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await:form:&lt;/code&gt; can carry several commands, each gated on what the agent actually asked for.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; An &lt;a href=&quot;/docs/automations/commands/llm.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt;&lt;/a&gt; turn can join an existing conversation. A script mints one session id and hands it to the agent, the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;composer&lt;/a&gt;, and the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/llmTranscript/&quot;&gt;transcript&lt;/a&gt;, so all three work on the same conversation instead of the agent starting its own.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; Added &lt;a href=&quot;/docs/agents/#long-conversations&quot;&gt;transcript compaction&lt;/a&gt; for long agent sessions. A conversation that outgrows the model&apos;s context window folds older turns behind a summary instead of failing. By default this triggers at 90% of the context window and keeps roughly the last 5% verbatim, both configurable per model under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compaction:&lt;/code&gt;. A worker can also fold a session on demand with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/compact&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; Agent turns can run off-request through a &lt;a href=&quot;/docs/queues/&quot;&gt;queue&lt;/a&gt;. A long turn survives navigating away and finishes in the background.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/LLM]&lt;/strong&gt; Added Server-Sent Event streaming for LLM turns. A long generation is no longer killed by a request timeout partway through, and a running turn can be stopped. Streaming landed first on the Anthropic provider and now covers every chat provider Cerb ships.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added &lt;a href=&quot;/docs/agents/#long-conversations&quot;&gt;prompt caching&lt;/a&gt; for agent turns, on by default. A long conversation re-sends the same prefix every turn, and caching it cuts what that costs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added per-turn token usage accounting. What each turn consumed is recorded and shown in agent transcripts, along with the conversation&apos;s current size and session totals that separate full-price input from cached reads and writes – so it&apos;s visible at a glance whether &lt;a href=&quot;/docs/agents/#long-conversations&quot;&gt;prompt caching&lt;/a&gt; is actually earning its keep on a long conversation.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-transcript.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Transcripts]&lt;/strong&gt; Effort level and reasoning tokens are now shown on LLM agent transcripts, alongside the per-turn token usage already reported there.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Standardized reasoning configuration on a canonical &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; key plus a grouped &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking:&lt;/code&gt; block. One authoring form now drives reasoning across every provider that supports it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Reasoning]&lt;/strong&gt; Reasoning effort now reaches every model provider, and a level you pick is either sent or refused instead of quietly ignored. Set it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm:&lt;/code&gt; block, or from the effort submenu on the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agentPrompt&lt;/code&gt;&lt;/a&gt; model picker.&lt;/p&gt;

    &lt;p&gt;Four providers were dropping the level on the floor: Groq, Together AI, and Hugging Face never forwarded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; at all; Ollama collected a model&apos;s reasoning out of the response but never asked for it, so none ever arrived; and on Gemini, any turn carrying tools had the level stripped before it went out, which silently ran agent loops with reasoning off. The composer could lose it too – a model whose entry declared no effort choices accepted whatever the picker posted and then sent nothing, so the conversation ran at the provider&apos;s default while the interface showed the level the worker had chosen.&lt;/p&gt;

    &lt;p&gt;The picker now offers the levels that particular model takes, an unavailable level is an error you can see rather than a silent fallback, and a model Cerb can&apos;t identify offers no levels at all rather than a plausible guess. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; autocompletion covers every chat provider, each offering the levels it actually documents instead of a generic list.&lt;/p&gt;

    &lt;p&gt;Two upgrade notes: if you already set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; on a Groq, Together AI, or Hugging Face model it was being ignored and will now genuinely be sent, which can surface as a rejection from a model that doesn&apos;t accept the parameter; and Ollama&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;think&lt;/code&gt; isn&apos;t a graded scale like the others, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;none&lt;/code&gt; turns reasoning off, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;low&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;medium&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;high&lt;/code&gt; map across directly, and anything above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;high&lt;/code&gt; is sent as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;high&lt;/code&gt; rather than rejected.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added image support to LLM chats. Images can be attached to a turn or pasted into an &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;agent prompt&lt;/a&gt;, and they render inline in transcripts.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-images.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Tools]&lt;/strong&gt; Agent tools can define display &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;labels:&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;summary:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;active:&lt;/code&gt;) and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icon:&lt;/code&gt; for transcripts, so a tool call reads as &quot;Searching the knowledge base&quot; rather than as a raw function name. A label can also carry placeholders, resolved against that call&apos;s own parameters, so the row reports what the agent actually asked for rather than a fixed phrase. The agent never sees either; the icon defaults to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hammer&lt;/code&gt;.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-tool-labels.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/LLM]&lt;/strong&gt; Added a neutral &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;finish_reason&lt;/code&gt; to LLM chat responses. This is what tells a truncated or interrupted turn apart from a completed one, and it&apos;s shown in the transcript viewer.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added Qwen Cloud and z.ai as first-class &lt;a href=&quot;/docs/agents/#providers&quot;&gt;LLM providers&lt;/a&gt;. Both appear in the provider list with their own endpoints, model hints, and brand icons.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added &lt;a href=&quot;/docs/agents/#providers&quot;&gt;OpenRouter&lt;/a&gt; as a first-class LLM provider. One account reaches nearly every frontier model, and until now using it meant configuring a generic OpenAI-compatible provider: type the endpoint URL by hand, and accept that every model showed the OpenAI logo in transcripts and pickers. Selecting OpenRouter from the provider list fills that in. The bigger gain is configuration – OpenRouter publishes a context window and the accepted input types for every model it serves, so refreshing the model list on an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; record fills in the context window and image support for whichever model you pick, across every vendor it fronts. Most providers don&apos;t report that much about their own models. Model IDs are namespaced by vendor, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anthropic/claude-sonnet-5&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openai/gpt-5.6-terra&lt;/code&gt;, and transcripts and pickers show the OpenRouter mark rather than the underlying vendor&apos;s, since that&apos;s the route the request and the bill actually took; add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display:&lt;/code&gt; block to the model record if you&apos;d rather see the vendor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Updated the Claude model IDs offered by autocompletion for the Anthropic and AWS Bedrock providers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Toolbars/Search]&lt;/strong&gt; A &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt; search bar can now host an AI agent that reads, rewrites, and runs your query. Search syntax is the single hardest thing in Cerb to learn, and the cost of that lands on exactly the people least equipped to pay it – describing what you want in plain language is a large win, and it&apos;s a win everywhere a worklist appears.&lt;/p&gt;

    &lt;p&gt;An agent icon sits at the right of the search bar; click it and a floating window opens over the list, offering the chats available there, and picking one starts the conversation. The icon appears once an &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; is enabled on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worklist&lt;/code&gt; surface; a search bar with no agent to offer hides it rather than showing an empty one. The agent also needs an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; under &lt;strong&gt;Search » Agent Models&lt;/strong&gt;, without which the chat opens but every turn errors. The window can be dragged wherever suits you.&lt;/p&gt;

    &lt;p&gt;The agent can read what&apos;s currently in the field, propose a replacement, write it back, and run it, and it can look up the record type&apos;s searchable fields and preview how many results a candidate query would return before touching your screen. Nothing about the worklist is rearranged to make room – it keeps its full width and stays usable underneath, so you can keep paging and refining with the chat open. Which agents a search bar offers is set on each agent, in the &lt;strong&gt;AI&lt;/strong&gt; tab of its worker record.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/worklist-search-agent.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Interactions]&lt;/strong&gt; Added an &lt;a href=&quot;/docs/automations/triggers/interaction.worker.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction.worker.agent&lt;/code&gt;&lt;/a&gt; trigger for &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt; that drive an editor from an agent pane. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction.internal&lt;/code&gt; exists to hide the automations Cerb runs on its own behalf – record choosers, autocomplete helpers, the dialogs inside the automation and metric builders – so you can filter them out of a worklist and never think about them again. Agent chats had been sharing that trigger for one reason: it was the only one offering &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/uiCommand/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uiCommand&lt;/code&gt;&lt;/a&gt;, which put a worker&apos;s own conversations in the bucket meant for machinery. They now have a trigger of their own. Script autocompletion offers the element and its options, the Form Builder gives it a real inspector instead of a raw KATA box, and a toolbar&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction: uri:&lt;/code&gt; autocompletion lists agent interactions alongside ordinary worker ones. In every other respect it&apos;s an ordinary worker &lt;a href=&quot;/docs/interactions/&quot;&gt;interaction&lt;/a&gt; – same form elements, same awaits, same resumable conversations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Interactions]&lt;/strong&gt; A parked conversation now describes itself in the lists that offer it back to you. Previously every one looked alike: the automation&apos;s own description on a generic clock icon, separated only by &quot;Last active 18 hours ago&quot;. Ten chats with one automation produced ten identical rows, so the list was quicker to ignore than to read, and the work quietly got redone in a fresh conversation instead. A conversation now takes its name and icon from the toolbar item that launched it, and when the form shows an &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/llmTranscript/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llmTranscript&lt;/code&gt;&lt;/a&gt; it also picks up the model provider&apos;s mark and an excerpt of your most recent message. Rename a toolbar item and its past conversations are renamed with it. None of this needs configuring; an automation that wants something different can add an optional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resume:&lt;/code&gt; block to its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await:form:&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;label:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preview:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icon:&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;color:&lt;/code&gt;. Each is sticky – a key that evaluates empty keeps what was stored rather than clearing it, so a long agent turn can&apos;t blank the name of the conversation it belongs to.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Interactions]&lt;/strong&gt; A failed agent turn now returns to the chat instead of ending the &lt;a href=&quot;/docs/interactions/&quot;&gt;interaction&lt;/a&gt;. Until now any failure on a background turn ended the conversation with a generic &quot;please try again&quot;, and whatever the worker had typed was gone – including failures that clear on their own in seconds, like a rate limit that came back in a third of a second having generated nothing and billed nothing. The reason now appears above the composer, led by what to do about it and followed by the provider&apos;s own text, which is often the only thing that names the model or the region. The message is restored to the composer, so sending again is a click instead of a retyped paragraph, and the session is rewound to where it stood before Send so a resend can&apos;t leave behind a duplicate of a message the model never answered. Automation authors reach the same failure through the &lt;a href=&quot;/docs/automations/commands/llm.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt;&lt;/a&gt; node&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_error:&lt;/code&gt; branch, whose output var carries &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error_status&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;retryable&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;retry_prompt&lt;/code&gt; for branching on the failure class.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers/Interactions]&lt;/strong&gt; A rate-limited agent turn now retries itself instead of interrupting the chat. Providers with low per-minute request limits can rate limit an ordinary turn in a busy conversation, and until now that ended the turn – you had to press Send again even though nothing had been generated and the limit would clear within seconds. A rejection (429) or an overloaded provider (529) is now retried up to three times, honoring the provider&apos;s own wait when it names one and backing off 5 seconds and then 15 when it doesn&apos;t. While it waits, the conversation says why and for how long, so a pause never looks like a stalled model. Only rejections are retried, and deliberately so: those are requests a model never saw, so nothing was generated and nothing was billed. A turn that timed out is never retried, because the provider may well have produced – and charged for – a full response that we simply stopped waiting for. Rate limits from AWS Bedrock and Ollama are also reported accurately now, rather than described as the provider being unreachable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added response streaming to OpenAI and every OpenAI-compatible provider: OpenAI, Docker Model Runner, Gemini, Qwen, z.ai, Groq, Together AI, and Hugging Face. Until now only Anthropic streamed, so a turn that ran past the request timeout was cut off mid-generation and everything it had produced was paid for and thrown away. Streaming replaces that total time limit with an inactivity cutoff, so a turn that&apos;s actively producing output is never interrupted and only a genuinely stalled one is – and a running turn can be stopped, keeping whatever it had already written. Groq, Together AI, and Hugging Face each carried their own copy of the request logic and now share the OpenAI implementation, picking up the longer per-turn budget that background turns use along with failure classification, so a rate limit is retried rather than surfacing as an error. Streaming is on by default wherever it&apos;s supported; add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream@bool: no&lt;/code&gt; to a provider&apos;s block to turn it off, which is worth trying against an endpoint that doesn&apos;t stream correctly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Ollama now streams responses. A streamed turn appears as it&apos;s written and the Stop button ends it mid-generation, and a turn cut short – by a stop, a dropped connection, or a worker that dies – keeps the text and completed tool calls that arrived, recorded as truncated rather than lost. Reasoning models stream their thinking alongside the reply, and token counts and the stop reason are recorded exactly as on a non-streamed turn. Because Ollama sends no keepalive while it works, the entire wait for the first token counts as silence: a local server loading a large model off disk, or Ollama Cloud queueing behind other requests, can be quiet for a long time before anything arrives. The allowance for that is generous by default and can be raised with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_stall_secs&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; In the Ollama provider, the Ollama Cloud API endpoint is now offered as a suggestion.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Added token usage counts to the Ollama provider, so an Ollama turn reports what it consumed in transcripts like every other provider.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; &lt;a href=&quot;/solutions/integrations/bedrock/&quot;&gt;AWS Bedrock&lt;/a&gt; now runs on the Converse API, so every model family works rather than only Anthropic. DeepSeek, Qwen, GLM, Llama, Nova, Mistral, and others now return their reply text, token counts, and tool calls, and models that emit reasoning no longer leak it into the answer.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; AWS Bedrock now streams responses. It was the last chat provider still sending one blocking request, so a turn that ran past the timeout was cut off mid-generation and everything it had produced was discarded. Streaming is used automatically on the models that support it – Bedrock reports that per model, and a model that can&apos;t stream quietly falls back to a normal request instead of failing, so nothing needs configuring either way. Prompt caching, tool calls, and separated reasoning all behave exactly as they do on a non-streamed turn.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; AWS Bedrock now supports &lt;a href=&quot;/docs/agents/#long-conversations&quot;&gt;prompt caching&lt;/a&gt; on the models that offer it. Cerb checks your account&apos;s own model catalog to find them, so a model without caching is never sent a cache marker.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Extended thinking and reasoning effort can now be set on AWS Bedrock models. Until now a Bedrock model reasoned at whatever depth it chose, with no way to raise it, lower it, or turn it off – every other provider already read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking:&lt;/code&gt; block and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; key, and Bedrock ignored both, so a hard problem couldn&apos;t be given more thinking and a simple one couldn&apos;t be made cheaper. Both keys now work the way they do elsewhere: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking:&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type: adaptive&lt;/code&gt; on current Anthropic models or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type: enabled&lt;/code&gt; on older ones, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort: low|medium|high|xhigh|max&lt;/code&gt; for depth. On older models effort becomes a thinking budget sized to fit inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_tokens&lt;/code&gt;, and if there&apos;s no room for a valid budget thinking is left off rather than sent as a request that would fail. These keys are for Anthropic models only, since Bedrock forwards the parameter straight to the model. Nothing is sent unless you set one, so existing configurations are unchanged, and the provider block&apos;s autocompletion now offers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream@bool:&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; AWS Bedrock now lists its available models when you create an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; record. The list comes from your account&apos;s own Bedrock catalog and includes the cross-region inference profile IDs that most current Claude and Nova models require.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/bedrock-model-list.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; When adding an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; record, providers now suggest API endpoints as you type. This is particularly useful on AWS Bedrock, which uses regional endpoints.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; When listing models fails, the provider&apos;s own error message is now shown instead of a bare HTTP status code. On AWS Bedrock this names the exact IAM action that&apos;s missing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Long agent turns no longer time out after 30 seconds on Ollama, Groq, Hugging Face, Together AI, or AWS Bedrock. Every provider now honors the extended per-turn timeout that background turns allow, which previously only Anthropic and OpenAI did.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Terminal]&lt;/strong&gt; An agent can now ask Cerb about itself, through a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb&lt;/code&gt; command line in its &lt;a href=&quot;/docs/agents/#filesystem-commands&quot;&gt;terminal&lt;/a&gt;. Ask an agent for &quot;Kina&apos;s open tickets&quot; and it has to know that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ticket&lt;/code&gt; is a record type here, that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;status&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;owner.at&lt;/code&gt; are things you can filter by, and that your custom fields exist at all – none of which is in its training data, and none of which is a file anyone would think to import, so until now an agent guessed, and a wrong guess looks exactly like a working one until the query returns nothing.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb records types&lt;/code&gt; lists every record type defined in your installation, custom record types included, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb records filters ticket&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb records fields ticket,worker&lt;/code&gt; reports one type&apos;s search keys or writable fields, custom fields and fieldsets included. The answers come from the same reflection that powers &lt;strong&gt;Setup » Records&lt;/strong&gt;, so what an agent is told and what an admin sees can never disagree.&lt;/p&gt;

    &lt;p&gt;Output is a compact table by default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--format json&lt;/code&gt; when something needs to parse it, and it pipes like any other terminal command, so an agent can narrow a long list without spending the whole thing on context. An automation opts in by naming the namespace under its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terminal:&lt;/code&gt; input; a superuser can try the same commands at &lt;strong&gt;Setup » Developers » &lt;a href=&quot;/docs/setup/developers/agent-filesystem-terminal/&quot;&gt;Agent Filesystem Terminal&lt;/a&gt;&lt;/strong&gt;, where a Commands panel turns each namespace on or off.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-records-terminal.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Pane]&lt;/strong&gt; An AI agent chat now gets its host editor&apos;s commands as tools automatically. Until now a chat that drove an editor had to carry the whole bridge itself – a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tool/&lt;/code&gt; definition per command plus an &lt;a href=&quot;/docs/automations/triggers/interaction.worker.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_tool:&lt;/code&gt;&lt;/a&gt; branch with a &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/uiCommand/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uiCommand&lt;/code&gt;&lt;/a&gt; await to dispatch each one – which made a chat for the automation editor 279 lines before you wrote a word of your own, and which went stale silently when the editor gained a command afterwards.&lt;/p&gt;

    &lt;p&gt;The &lt;a href=&quot;/docs/automations/triggers/interaction.worker.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction.worker.agent&lt;/code&gt;&lt;/a&gt; trigger now contributes those commands itself, resolved from wherever the pane is mounted, the same way &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mounts:&lt;/code&gt; provisions the agent&apos;s terminal. A chat opened beside the automation editor, a worklist, or the &lt;a href=&quot;/docs/setup/developers/icon-builder/&quot;&gt;Icon Builder&lt;/a&gt; can read and rewrite it with nothing in its script, and an editor that gains a command reaches every existing chat on its next turn, including ones already saved.&lt;/p&gt;

    &lt;p&gt;An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_tool:&lt;/code&gt; branch still runs before every editor command, so that&apos;s still where a tool is gated behind a human: answer the call with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tool.return:&lt;/code&gt; and the editor is never touched.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Pane]&lt;/strong&gt; An agent pane can now answer a tool on the server, with no round-trip to the browser. Every tool an agent pane gave a chat used to be a question for the editor – read this field, write that one – which is the right shape when the answer is in the document in front of you, and the wrong one when the answer belongs to the installation itself. The &lt;a href=&quot;/docs/setup/developers/icon-builder/&quot;&gt;Icon Builder&lt;/a&gt;&apos;s assistant is the case that made it obvious: naming an existing icon is most of the work, and the browser has no way to say what the set contains. It now gets a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_list_icons&lt;/code&gt; tool answered on the server, returning every icon name in the set, narrowable with a filter when the list is long, so the assistant matches an existing icon instead of guessing whether one exists.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Pane]&lt;/strong&gt; The command bar can now host an AI agent chat. Every agent pane so far has sat beside an editor, with the job of reading and writing the document in front of you, which left nowhere to put a chat that follows you around the app instead of belonging to one screen. A chat written for the command bar gets two things an editor chat has no use for: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_get_page&lt;/code&gt; reads the page Cerb actually routed, which is what you&apos;re looking at even when the browser URL says otherwise, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_open_search&lt;/code&gt; puts a search popup for any record type in front of you, prefilled with a query the agent wrote – better than describing a query and asking you to paste it. Both are one-way on purpose. The command bar can put something in front of you but can&apos;t read anything back, so a chat there tells you what it searched for and lets you read the results; it never sees them itself, and it knows where you are but never what&apos;s on the screen. Which agents the command bar offers is set on each agent, the same way every other surface is, and the command bar&apos;s existing non-agentic shortcuts are untouched.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Chat]&lt;/strong&gt; An agent chat in an &lt;a href=&quot;/docs/toolbars/interactions/agent.pane/&quot;&gt;agent pane&lt;/a&gt; now follows the newest turn, and holds its place when you scroll up to read. Following the newest turn is right until you scroll up to re-read something, and then it&apos;s exactly wrong: every poll tick yanked you back to the bottom mid-sentence, and a long agent run was the worst case because the ticks never stop. The transcript now pins to the bottom only when you were already there, including across the re-render that each step of a tool loop causes, so reading something is no longer a race against the next turn. When there&apos;s newer content below you, a &quot;Jump to latest&quot; pill appears; clicking it takes you down and re-arms the follow. Sending a message re-arms it too, since nobody scrolls up in order to miss their own reply.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-transcript-jump-to-latest.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers/OpenAI]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;Agent models&lt;/a&gt; pointed at OpenAI&apos;s own API now use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/v1/responses&lt;/code&gt; endpoint, where tools and reasoning work together. The older &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/v1/chat/completions&lt;/code&gt; endpoint refuses function tools on a reasoning turn for gpt-5.4 and newer, which costs a tool-using agent its reasoning in the one configuration where it matters most. That endpoint also returns reasoning summaries, which is the only way an OpenAI model shows its thinking; it&apos;s authored as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking: display:&lt;/code&gt; – the same block and keys as Anthropic&apos;s, so it reads the same across providers – and it&apos;s on by default for a model flagged as thinking. Any other endpoint keeps using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/v1/chat/completions&lt;/code&gt;: Azure, llama.cpp, vLLM, MLX, and every OpenAI-compatible provider. Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api: chat&lt;/code&gt; on an OpenAI record to pin it to that endpoint, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api: responses&lt;/code&gt; is refused on an endpoint that can&apos;t serve it rather than quietly downgraded.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers/OpenAI]&lt;/strong&gt; LLM providers using an OpenAI-compatible API can now pass arbitrary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extra_body:&lt;/code&gt; parameters through to the inference server. The OpenAI-compatible ecosystem puts its knobs somewhere other than where the OpenAI spec does, and a fixed set of typed parameters can&apos;t keep up – Apple-silicon oMLX serving Qwen3 forwards &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chat_template_kwargs&lt;/code&gt; to the Jinja template but doesn&apos;t map the standard top-level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reasoning_effort&lt;/code&gt; into it, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;effort:&lt;/code&gt; reached the server, was dropped on the floor, and nothing said so. llama.cpp, vLLM, SGLang, and unsloth all have their own such keys. The key is named and shaped after the OpenAI SDK&apos;s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extra_body&lt;/code&gt;, deliberately, so a snippet from a server&apos;s documentation transcribes straight into &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt;: the &lt;em&gt;contents&lt;/em&gt; merge into the top level of the request body, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extra_body: chat_template_kwargs: reasoning_effort: medium&lt;/code&gt; puts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chat_template_kwargs&lt;/code&gt; on the wire rather than a key called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extra_body&lt;/code&gt;. Cerb keeps ownership of the request&apos;s structure, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;messages&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream_options&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools&lt;/code&gt; can&apos;t be overwritten.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents/Performance]&lt;/strong&gt; An agent&apos;s system prompt is composed once and frozen for the life of the conversation, so the most cacheable part of every request stops moving. It&apos;s rebuilt when someone &lt;em&gt;edits&lt;/em&gt; the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; – the authored &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system_prompt:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mounts:&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terminal:&lt;/code&gt; block – and that takes effect on the worker&apos;s next message. Nothing else rebuilds it: a host gaining a tool, or an agent writing a file into a volume it can write to, leaves an open conversation&apos;s prompt alone. The session now stores the full prompt that was sent rather than the author&apos;s fragment, so a &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/llmTranscript/&quot;&gt;transcript&lt;/a&gt; can answer what the agent actually saw. A trigger may contribute the opening of that prompt, the same way it already contributes tools, and the author&apos;s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system_prompt:&lt;/code&gt; is appended to it rather than replacing it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Terminal]&lt;/strong&gt; An agent can now ask Cerb about the installation it&apos;s running in, through a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb platform&lt;/code&gt; command line in its &lt;a href=&quot;/docs/agents/#filesystem-commands&quot;&gt;terminal&lt;/a&gt;. The documentation describes the plugins that exist; it can&apos;t tell an agent which of them are in your installation, which are switched off, or what a third party added. Ask an agent whether it can file a JIRA issue, or which automation triggers it may write for, and until now it either guessed or told you to go look.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb platform plugins&lt;/code&gt; lists every plugin with its ID, version, and whether it&apos;s enabled – disabled ones included and marked, because &quot;the JIRA plugin is here but switched off&quot; and &quot;there is no JIRA integration&quot; are different answers and only one of them is yours to fix. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb platform points&lt;/code&gt; lists every extension point with how many extensions this installation has on it, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb platform extensions cerb.automation.trigger&lt;/code&gt; lists what&apos;s on one.&lt;/p&gt;

    &lt;p&gt;That last one isn&apos;t only for plugin development. An extension ID is a value stored on ordinary records, so it&apos;s a value you search by: an &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt;&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trigger:&lt;/code&gt; filter takes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.trigger.interaction.worker&lt;/code&gt;, not the short &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction.worker&lt;/code&gt; the trigger calls itself. Listing the extensions on a point is how an agent gets from &quot;automations that run when a worker starts an interaction&quot; to a query that returns them, and the same holds for queue consumers, search indexes, connected services, and card widgets.&lt;/p&gt;

    &lt;p&gt;Output is a compact table by default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--format json&lt;/code&gt; when something needs to parse it, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--filter&lt;/code&gt; to narrow a long point, and it pipes like any other terminal command. An automation opts in by naming the namespace under its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terminal:&lt;/code&gt; input; a superuser can try the same commands at &lt;strong&gt;Setup » Developers » &lt;a href=&quot;/docs/setup/developers/agent-filesystem-terminal/&quot;&gt;Agent Filesystem Terminal&lt;/a&gt;&lt;/strong&gt;, where the Commands panel gained a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;platform&lt;/code&gt; toggle.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Terminal]&lt;/strong&gt; An agent can now validate &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; and JSON before it saves them, through a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb code&lt;/code&gt; command line in its &lt;a href=&quot;/docs/agents/#filesystem-commands&quot;&gt;terminal&lt;/a&gt;. A model writing an &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; has no feedback loop: it writes the whole thing, saves, and learns from a save error what one line got wrong – then rewrites the whole thing, because it can&apos;t tell which parts were fine. That&apos;s several turns and a lot of guessing for what a linter answers in one.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb code kata lint /tmp/draft.kata --schema automation&lt;/code&gt; reports every problem with its line and the line itself, validating against the same schemas Cerb enforces on save, so passing here means the save won&apos;t be rejected for that reason. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb code kata schemas&lt;/code&gt; lists the schemas this installation has – automations, automation policies, sheets, toolbars, workflows, charts, and the rest – and something not written to a file yet can be checked directly with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--payload&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb code json lint&lt;/code&gt; does the same for JSON, and it says &lt;em&gt;where&lt;/em&gt; the document stops being JSON and why: a trailing comma before a brace, a single-quoted key, a missing comma between two values, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; belongs. PHP&apos;s own answer to all of those is the words &quot;Syntax error&quot; with no position, which is exactly what makes a model rewrite the file instead of the line. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb code json format&lt;/code&gt; prints a document in Cerb&apos;s own JSON formatting, and refuses to format one that isn&apos;t valid.&lt;/p&gt;

    &lt;p&gt;Superusers can try all of it at &lt;strong&gt;Setup » Developers » &lt;a href=&quot;/docs/setup/developers/agent-filesystem-terminal/&quot;&gt;Agent Filesystem Terminal&lt;/a&gt;&lt;/strong&gt;, where the Commands panel gained a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code&lt;/code&gt; toggle and the Payload box holds the document being checked.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Terminal]&lt;/strong&gt; The &lt;a href=&quot;/docs/agents/#filesystem-commands&quot;&gt;agent terminal&lt;/a&gt;&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt; can now tell you which words are worth searching for. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search --terms&lt;/code&gt; counts how many files contain &lt;em&gt;each&lt;/em&gt; word instead of searching for all of them, so an agent can throw a dozen synonyms at a volume in one call, keep the winner, and refine – rather than guessing a query at a time. Prefix a word with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; to require it and count the others alongside it, which collapses the numbers fast and shows what actually co-occurs. A wildcard or stem term lists the concrete words it covers, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto*&lt;/code&gt; reports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;automations (476) automation (374) automatically (228) ...&lt;/code&gt;, which is how you learn the vocabulary a corpus actually uses instead of guessing at it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Terminal]&lt;/strong&gt; An &lt;a href=&quot;/docs/agents/#filesystem-commands&quot;&gt;agent terminal&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt; that matches nothing now answers with per-word counts rather than &quot;No matches&quot;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt; is AND – every word must appear in the same file – so a pile of near-synonyms reliably matched nothing, and the reply gave no hint of which word emptied it. The fallback prints the same table &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search --terms&lt;/code&gt; gives, naming the word that matched nothing and the ones worth keeping. It keeps any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; already in the query, so the second step of a search loop doesn&apos;t throw away the term you just established.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Filesystems]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;Agent filesystems&lt;/a&gt; can now ship with Cerb and import themselves on update, so a bundled volume automatically stays current for the version you&apos;re running. It lives in the source tree as ordinary files and is imported on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/update&lt;/code&gt;, so an agent has reference material without anyone uploading an archive. Each volume carries a manifest and only its hash is read at runtime: an update where nothing changed costs one registry read and does no work at all, while a changed volume is zipped and run through the same import job an admin upload uses, inheriting its batching, retry, prune, and &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; progress. The job is drained inline, so when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/update&lt;/code&gt; finishes the content is there. A bundled volume &lt;em&gt;mirrors&lt;/em&gt; what shipped – a file created in it by a worker or an agent is removed on the next update – while content imported by hand through the ordinary upload is never touched. &lt;strong&gt;Setup » Developers » Platform&lt;/strong&gt; gains a &apos;Reload&apos; button that reconciles every bundled volume against its rows without waiting for a version change.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Filesystems]&lt;/strong&gt; Cerb now ships a skills volume for its own AI agents. The bundled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-agents&lt;/code&gt; &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;filesystem&lt;/a&gt; carries ten skills – the agent terminal, KATA, automations, scripting, search queries, records, data queries, icons, mail replies, and the documentation – each one file an agent reads when it needs it. An agent can look up the grammar of a search filter or the shape of an automation command instead of guessing, which is where a capable model is most often subtly wrong.&lt;/p&gt;

    &lt;p&gt;Skills compose, so one agent can be an expert in several domains at once for a single request: an automation agent asked for a chart of open tickets by group reads &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;automations&lt;/code&gt; for the command shape, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-queries&lt;/code&gt; for the source and its aggregation, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripting&lt;/code&gt; for the Twig in between, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search-queries&lt;/code&gt; for the filter grammar – four short reads on the turn that needs them, rather than one prompt large enough to hold all four being re-sent on every turn of every conversation. The same volume serves every agent, so a skill improved once is improved for all of them.&lt;/p&gt;

    &lt;p&gt;Nothing is loaded up front; an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INDEX.md&lt;/code&gt; says what each skill covers and when to reach for it. Reading a skill grants knowledge, not a new role – an agent&apos;s identity and tools come from its system prompt and stay fixed for the conversation, and work that genuinely belongs to another role belongs to a subagent.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Filesystems]&lt;/strong&gt; Cerb now ships its own documentation as a bundled &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;agent filesystem&lt;/a&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-docs&lt;/code&gt; volume carries the complete documentation as Markdown – the reference manual, &lt;a href=&quot;/guides/&quot;&gt;guides&lt;/a&gt;, worked &lt;a href=&quot;/solutions/&quot;&gt;solutions&lt;/a&gt;, &lt;a href=&quot;/tips/&quot;&gt;tips&lt;/a&gt;, &lt;a href=&quot;/docs/workflows/&quot;&gt;workflows&lt;/a&gt;, and release notes – and imports itself on update like any other bundled volume.&lt;/p&gt;

    &lt;p&gt;Mount it on an agent and it can look a feature up rather than recall it, which matters most exactly where a capable model is subtly wrong: &lt;a href=&quot;/docs/search/&quot;&gt;search query&lt;/a&gt; syntax, &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; keys, &lt;a href=&quot;/docs/api/&quot;&gt;API&lt;/a&gt; endpoints, and &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; commands. It&apos;s over a thousand files, so it&apos;s something to search rather than browse – an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INDEX.md&lt;/code&gt; at the volume root says what lives in each directory, which paths are predictable enough to read directly, and what each page&apos;s front matter carries, which is enough to orient an agent that mounts the documentation and nothing else.&lt;/p&gt;

    &lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docs&lt;/code&gt; skill in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-agents&lt;/code&gt; volume covers the same ground in more depth for an agent that has both. Because it&apos;s bundled, the documentation tracks the release: what an agent reads is the documentation for the version it&apos;s running on.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Pane]&lt;/strong&gt; An &lt;a href=&quot;/docs/toolbars/interactions/agent.pane/&quot;&gt;agent pane&lt;/a&gt;&apos;s role and tool inventory are composed by Cerb at runtime. An agent sitting beside an editor is told what it is, where it sits, and what that editor can do, with nothing in the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; that drives it. The author&apos;s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system_prompt:&lt;/code&gt; is appended to that rather than replacing it, so adding a line about a custom tool is one line, and leaving it empty – the normal case – still produces a complete prompt. Composing at runtime rather than generating into each script is what lets an improved role reach an automation that was deployed before it: nothing is patched and nothing is regenerated. The tool inventory beneath each role is built from the live catalog, so it can&apos;t drift from the tools actually offered, and each agent-pane component names the skills its work needs and the documentation paths that cover it. Both pointers are emitted only when the volume behind them is really mounted – a chat can be authored with no filesystem at all, and sending an agent after files it can&apos;t read is worse than saying nothing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agents/Files]&lt;/strong&gt; Added bulk update for &lt;a href=&quot;/docs/records/types/agent_file/&quot;&gt;agent files&lt;/a&gt;. The agent files worklist has a bulk update button for moving files between &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;filesystems&lt;/a&gt;, editing their fields, and running automations over a batch. The popup also lists any &lt;a href=&quot;/docs/automations/triggers/record.bulkUpdate/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.bulkUpdate&lt;/code&gt;&lt;/a&gt; automations bound to agent files, so a batch can be handed to a script – generating embeddings for every file on a volume, for instance. Moving a batch to another filesystem skips any file whose path is already taken on the destination, since one filesystem can&apos;t hold two files at the same path; the rest of the batch still moves. Bulk updating agent files requires an administrator, matching the rest of agent file editing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents]&lt;/strong&gt; An &lt;a href=&quot;/docs/agents/&quot;&gt;AI worker&lt;/a&gt;&apos;s peek has an &lt;strong&gt;AI&lt;/strong&gt; tab for setting what the agent brings to a turn and where it runs – instructions, which models it may use, &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;filesystems&lt;/a&gt;, tools, and its &lt;a href=&quot;/docs/agents/#the-cerb-command-line&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb&lt;/code&gt; command line&lt;/a&gt;. A rail lists &lt;strong&gt;Everywhere&lt;/strong&gt; first and then each surface the agent can run on, with a green dot beside the ones it&apos;s turned on for. &apos;Everywhere&apos; is what the agent brings no matter where it&apos;s running, and a surface &lt;em&gt;adds&lt;/em&gt; to that rather than replacing it: filesystems, tools, and command-line namespaces are the union of the two, and only the model query and the chat it runs are swapped outright.&lt;/p&gt;

    &lt;p&gt;That&apos;s why the scope is called Everywhere rather than Defaults – there&apos;s nothing there to override. The command line is grants only. A surface can hand the agent a namespace it doesn&apos;t have everywhere and can never take one away, so the field is a picker of things to add rather than a row of checkboxes that would suggest unticking one could revoke it.&lt;/p&gt;

    &lt;p&gt;Each surface shows what it&apos;s adding &lt;em&gt;to&lt;/em&gt;, in the field itself: filesystems, tools, the chat, and the command line show what Everywhere contributes as faded tiles beside your own choices, while instructions and the model query show it as the placeholder, since there&apos;s nothing there to sit beside. All of it follows an edit to Everywhere immediately, without saving, so turning something on above takes it out of every surface below while you watch. Turning a surface off keeps everything configured for it – the switch says &quot;not running here&quot;, not &quot;start over&quot;. Configuration written by hand through the &lt;a href=&quot;/docs/api/&quot;&gt;API&lt;/a&gt; or an &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; survives a visit to this tab, including things the form draws no control for; anything it can&apos;t show as a chip is listed plainly with a button to remove it, so &quot;carried through untouched&quot; doesn&apos;t mean &quot;stuck there forever&quot;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents]&lt;/strong&gt; Cerb now ships the &lt;strong&gt;chat an agent runs by default&lt;/strong&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.ai.agent&lt;/code&gt; &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt; installs an &lt;a href=&quot;/docs/automations/triggers/interaction.worker.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction.worker.agent&lt;/code&gt;&lt;/a&gt; automation named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.ai.agent.chat&lt;/code&gt;, and an &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; that names no chat of its own runs that one – so creating an &lt;a href=&quot;/docs/agents/&quot;&gt;AI worker&lt;/a&gt; and turning it on for a surface is all it takes to have a working conversation there.&lt;/p&gt;

    &lt;p&gt;The chat adapts to wherever it opens: the surface contributes that editor&apos;s commands as tools and its orientation as a system prompt at runtime, so one script drives whichever screen it sits beside. It mounts Cerb&apos;s own documentation and reference skills read-only, and enables the &lt;a href=&quot;/docs/agents/#the-cerb-command-line&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb&lt;/code&gt; command line&lt;/a&gt; over this installation&apos;s record types, fields, and filters, so it looks a name up rather than recalling one that may not exist here.&lt;/p&gt;

    &lt;p&gt;It needs an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; under &lt;strong&gt;Search » Agent Models&lt;/strong&gt;; without one the chat opens and every turn reports an error, which is the honest failure for something that needs a model nobody has configured yet. The workflow is installed on new installations and once on upgrade; disable or delete it and it stays gone, since it&apos;s never re-enabled on a later update. To build your own, use &lt;strong&gt;Automations » Build » AI Agent Chat&lt;/strong&gt;, which generates a copy you own and point an agent&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;automation:&lt;/code&gt; at it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents]&lt;/strong&gt; Added &lt;strong&gt;&lt;a href=&quot;/docs/records/types/agent_tool/&quot;&gt;Agent Tool&lt;/a&gt;&lt;/strong&gt; records – a record type for the tools an AI agent can call. A tool is defined once and then added to any agent, rather than restated in each one. The record wraps an &lt;a href=&quot;/docs/automations/triggers/agent.tool/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent.tool&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; with everything the automation itself has nowhere to say: the name the model calls, the description it reads, and the icon and wording its transcript shows. The automation knows how to do the work; the record says what the model should call it and what the conversation shows while it runs.&lt;/p&gt;

    &lt;p&gt;What the tool &lt;em&gt;takes&lt;/em&gt; isn&apos;t restated on the record – the schema the model is shown is built from the answering automation&apos;s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs:&lt;/code&gt; block, which already carries a description, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;required&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowed_values&lt;/code&gt;, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; per input, and is what the script reads back. Declaring the arguments twice would mean two places to change and one of them silently wrong. The icon and the two labels are what a conversation shows – &quot;Searching the web…&quot; while the call runs, &quot;Searched the web&quot; once it returns – and either label can quote the call&apos;s own arguments, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Searched for {{query}}&lt;/code&gt; reads back what the agent actually asked for.&lt;/p&gt;

    &lt;p&gt;A tool is &lt;strong&gt;Available&lt;/strong&gt; (offered wherever tools are picked), &lt;strong&gt;Unlisted&lt;/strong&gt; (hidden from the pickers but still runs when an agent names it directly), or &lt;strong&gt;Disabled&lt;/strong&gt; (refused everywhere). Its name is the function name the model calls, so it must be unique, start with a lowercase letter, and contain only lowercase letters, numbers, and underscores; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_&lt;/code&gt; is reserved for Cerb&apos;s own built-in tools, so yours can never shadow one. Agent tools are searchable and work in worklists and workspaces like any other record. A tool record holds no credentials of its own – an API key for whatever the tool calls lives in the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; behind it, or in a &lt;a href=&quot;/docs/records/types/connected_account/&quot;&gt;connected account&lt;/a&gt; that automation reads.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-tool.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents]&lt;/strong&gt; Agents can now call the tools you define, referenced by name from an agent&apos;s own configuration or from a chat&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools:&lt;/code&gt; block. A reference is just the &lt;a href=&quot;/docs/records/types/agent_tool/&quot;&gt;agent tool&lt;/a&gt; record&apos;s name, and the entry under it may override the presentation the record supplies – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icon:&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;labels:&lt;/code&gt; – or switch the tool off for this agent with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;disabled@bool: yes&lt;/code&gt;. A conversation&apos;s tools are settled when it starts, because the tool set sits in the prompt prefix the provider caches: editing a tool reaches new conversations rather than rewriting one already under way, and switching a tool off refuses new calls to it rather than making it vanish mid-conversation. A tool that&apos;s disabled, or whose record is missing, when a conversation &lt;em&gt;starts&lt;/em&gt; is never offered at all, so the model is never shown something it would only be refused.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Agents]&lt;/strong&gt; Added an &lt;a href=&quot;/docs/automations/triggers/agent.tool/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent.tool&lt;/code&gt;&lt;/a&gt; trigger for the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; behind an &lt;a href=&quot;/docs/records/types/agent_tool/&quot;&gt;agent tool&lt;/a&gt; record. It&apos;s handed the environment of the call rather than only the model&apos;s arguments, so a tool can refuse work that doesn&apos;t belong where it was invoked. The arguments arrive as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs.*&lt;/code&gt;, declared in the automation&apos;s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs:&lt;/code&gt; block – that block &lt;em&gt;is&lt;/em&gt; the schema the model is shown, so a tool is self-documenting and there&apos;s exactly one place to change what it takes.&lt;/p&gt;

    &lt;p&gt;Alongside them a tool receives &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tool_*&lt;/code&gt;, the agent tool record that was called; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent_*&lt;/code&gt;, the AI worker running it; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transcript_user_*&lt;/code&gt;, the worker that agent is serving; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transcript_surface&lt;/code&gt;, where the conversation is happening; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transcript_trigger&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transcript_uuid&lt;/code&gt;, which kind of conversation this is and which one in particular. Because the record owns the schema, one automation can back several tools – branch on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tool_name&lt;/code&gt; to tell them apart.&lt;/p&gt;

    &lt;p&gt;An agent tool runs to completion inside a single tool call, so it returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content:&lt;/code&gt; string and can&apos;t &lt;a href=&quot;/docs/automations/commands/await/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await:&lt;/code&gt;&lt;/a&gt;; an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await:&lt;/code&gt; at any depth is refused when the automation is saved, with a message saying to return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content:&lt;/code&gt; instead. The &lt;strong&gt;AI Agent Tool&lt;/strong&gt; starter in the automation builder seeds a script on the new trigger, and an automation&apos;s Usage panel now resolves the agent tools that reference it by looking them up rather than by scanning every script for its name.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents/Transcripts]&lt;/strong&gt; An agent chat can now show who is speaking instead of a generic &quot;Agent&quot;. An &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/llmTranscript/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llmTranscript:&lt;/code&gt;&lt;/a&gt; element takes an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent:&lt;/code&gt; block, and every agent turn is attributed to it: the byline reads the agent&apos;s name and the avatar is the agent&apos;s rather than the vendor&apos;s. The model stays visible – its mark moves to a small badge on the lower right of the avatar, in the provider&apos;s brand color – so a reader can see who they&apos;re talking to and still see that it&apos;s an AI, which one glyph alone couldn&apos;t say.&lt;/p&gt;

    &lt;p&gt;Name an AI worker (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent: &apos;@cerb&apos;&lt;/code&gt;, a worker id, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb:worker:&amp;lt;id|handle&amp;gt;&lt;/code&gt;) and the name and avatar come from that record, or write the identity inline with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icon:&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;color:&lt;/code&gt; for a chat with no worker behind it. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;color:&lt;/code&gt; takes a Cerb UI hue – red, blue, green, gray, orange, or purple – which resolves to the theme&apos;s own color rather than the CSS keyword of the same name, so it matches every other pill and tag in the product; any CSS color works too, and left out, the color is hashed from the name.&lt;/p&gt;

    &lt;p&gt;This is display only: nothing is written to the conversation, so an agent renamed today relabels the chats it already had, and naming an AI worker on &lt;a href=&quot;/docs/automations/commands/llm.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt;&lt;/a&gt; remains what gives a chat a real identity – attribution, memory, and credentials.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; &lt;strong&gt;LLM Agent Transcripts&lt;/strong&gt; now identify the agent behind each session. A transcript is titled by its agent, an &lt;strong&gt;Agent&lt;/strong&gt; chip links to the record holding the instructions and tools the turns were composed from, and every agent turn carries that agent&apos;s picture and byline instead of a generic &quot;Agent&quot;. The session uuid stops being the headline: only its leading characters distinguish one session from another, so it&apos;s quoted like a git commit – eight characters in the eyebrow, the whole value on hover and on the &lt;strong&gt;Permalink&lt;/strong&gt; button. That leaves the list showing what you actually pick a transcript by – which agent ran it, for whom, how long ago, and how large it got.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents]&lt;/strong&gt; Agents appear in the command bar under their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@handle&lt;/code&gt;, over a line saying what picking one does. The bar mixes agents with every other shortcut in Cerb, so a row reads as the agent you&apos;d &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mention&lt;/code&gt; anywhere else rather than as the name of the script behind it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Agent/Terminal]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb platform version&lt;/code&gt; to the &lt;a href=&quot;/docs/agents/#the-cerb-command-line&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb&lt;/code&gt; command line&lt;/a&gt;. An agent can ask what version of Cerb it&apos;s working in, whether that install is self-hosted or on Cerb Cloud, and what PHP and database it runs on. It reports Cerb&apos;s version and build, the deployment, the Devblocks platform build, PHP with its SAPI, and the database server&apos;s own version string, which names the flavor too. This is what an agent should ask before assuming a feature exists: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt; is the exact string a &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt;&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_version: &apos;&amp;gt;=12.0&apos;&lt;/code&gt; gate or a &lt;a href=&quot;/docs/packages/&quot;&gt;package&lt;/a&gt;&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requires.cerb_version&lt;/code&gt; compares against, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; is a date serial that moves with every release and is what the updater compares – it isn&apos;t a version and doesn&apos;t sort against one. The deployment row reads &lt;strong&gt;Cerb Cloud&lt;/strong&gt; when Cerb hosts the install, naming its subdomain, and &lt;strong&gt;Self-Hosted&lt;/strong&gt; otherwise. Like the other sub-commands it takes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--format json&lt;/code&gt; and binds its rows for piping.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Workers]&lt;/strong&gt; On &lt;a href=&quot;/docs/records/types/worker/&quot;&gt;worker&lt;/a&gt; worklists, AI accounts now carry a visual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bot&lt;/code&gt; indicator, so an agent is recognizable at a glance in a roster of people.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents/Mail Routing]&lt;/strong&gt; An &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; can now sit beside both mail routing editors – the standalone &lt;strong&gt;Mail Routing Rule&lt;/strong&gt; record and a group&apos;s &lt;strong&gt;Mail: Incoming&lt;/strong&gt; tab – reading and writing the rules and testing them against a sample message. It&apos;s one surface rather than two, because the grammar, the schema, and the evaluator are shared; what differs is where in the pipeline the document runs, and the agent is told that when it reads: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scope&lt;/code&gt; comes back as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rule&lt;/code&gt; for a standalone rule that decides the &lt;strong&gt;group&lt;/strong&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group&lt;/code&gt; for a group&apos;s own rules that decide the &lt;strong&gt;bucket&lt;/strong&gt;.&lt;/p&gt;

    &lt;p&gt;Alongside the read, edit, grep, and diff tools every editor surface offers, this one adds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_test_routing&lt;/code&gt;, answered on the server rather than through the browser bridge: it runs a routing document against a sample message – subject, body, recipients, sender, spam score, headers – and reports which rule matched. That&apos;s the difference between an agent checking a rule and asserting that it works, and because the document is an argument rather than the editor&apos;s contents, a candidate rule can be tested &lt;em&gt;before&lt;/em&gt; it&apos;s written in.&lt;/p&gt;

    &lt;p&gt;Both editors also mark changed lines in the gutter against the last save, whichever of you made the change, and clicking a mark shows what changed; &lt;strong&gt;Save and continue&lt;/strong&gt; takes a fresh checkpoint, so the marks always answer what you&apos;ve touched in this sitting. The agent reads that same diff through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb_get_diff&lt;/code&gt;, so its account of an edit is checked against what it actually did rather than what it meant to do.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-mail-routing.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Workers]&lt;/strong&gt; An AI worker&apos;s whole &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; configuration can now be set through the &lt;a href=&quot;/docs/api/&quot;&gt;records API&lt;/a&gt; and &lt;a href=&quot;/docs/workflows/&quot;&gt;workflows&lt;/a&gt;, as an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent_config&lt;/code&gt; field on the &lt;a href=&quot;/docs/records/types/worker/&quot;&gt;worker&lt;/a&gt; record. Until now the &lt;strong&gt;AI&lt;/strong&gt; tab was the only way to author one, which left agents out of the text-based tooling every other record type already has – an agent couldn&apos;t be version-controlled, diffed, or synchronized between a development and a production install. Write it as a nested &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; object, so a workflow template can target a single leaf – a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models_query:&lt;/code&gt; drawn from workflow config, say – instead of interpolating into one opaque blob; a KATA string is accepted too for anyone writing it by hand. Either way it&apos;s validated against the same agent schema the AI tab uses, so a malformed configuration is refused rather than stored. It&apos;s only meaningful on a worker with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_ai&lt;/code&gt; set.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;automations&quot;&gt;Automations&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/66I3k8kftyY&quot; title=&quot;Building automation forms visually with the Cerb Form Builder&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations]&lt;/strong&gt; New &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt; open on a list of starter templates rather than an empty editor. Picking one seeds a working trigger, script, and policy; several ask a few questions first and generate the script from your answers. The five bundled templates cover AI agent chats and agent tools, worker interactions, reacting to ticket changes, and sending a Slack message. Plugins can contribute their own through a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.automation.template&lt;/code&gt; extension point, and the list gains a filter box once enough templates are installed to need one.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/automation-templates.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations]&lt;/strong&gt; Added a read-only control-flow graph for &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt;. It maps out a script&apos;s decisions, outcomes, and loops visually, which makes an unfamiliar or deeply nested automation far easier to follow. The graph appears in the editor&apos;s &apos;Visualization&apos; tab and is also available as an &apos;Automation: Graph&apos; card, profile, and workspace widget. Double-clicking a node or one of its properties jumps to that line in the code, so the graph works as a way to navigate a long script rather than only to read it.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/automation-graph.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations]&lt;/strong&gt; Added &quot;Simulate initial state&quot; for priming a test run from the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; editor. Test input is filled in as a form built from the trigger&apos;s inputs and the automation&apos;s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs:&lt;/code&gt;, rather than handwritten as state YAML. Triggers describe their simulatable scope, so a mail filter, webhook responder, or worker interaction each prompt for the fields that actually apply – and a trigger can replace that scope wholesale, as a mail filter does by asking for one example message and expanding it into sender, subject, headers, body, and recipients. Priming the form runs nothing, so it costs nothing even on an automation that calls a model.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/simulate-initial-state.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/simulate-initial-state-mail.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations]&lt;/strong&gt; Added a visual Form Builder for interaction &lt;a href=&quot;/docs/automations/triggers/interaction.worker/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await:form:&lt;/code&gt;&lt;/a&gt; blocks. Form elements are assembled by dragging components onto a canvas that renders as the finished form, with the &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; generated beneath it as you build. A field&apos;s options are edited in an inspector beside the canvas. This makes it much faster to build a worker or website interaction without memorizing every element&apos;s options.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/automation-form-builder.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Editor]&lt;/strong&gt; Added a &quot;What changed&quot; diff between a run&apos;s input and output in the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; editor&apos;s &apos;Run&apos; tab. Previously you compared two YAML documents side by side and spotted the differences yourself; now the editor shows what the automation actually changed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Editor]&lt;/strong&gt; Added least-privilege policy generation to the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; editor. It reads the script in front of it and writes the tightest policy that still allows it to run, which is a much better starting point than an overly broad policy that quietly permits more than intended. The generated policy takes the form of deny guards under an allow, scoping each command to the values the script actually uses.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/policy-generator.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Interactions]&lt;/strong&gt; Worker &lt;a href=&quot;/docs/interactions/&quot;&gt;interactions&lt;/a&gt; can now be listed, resumed, and disposed of. An interaction abandoned by navigating away or closing a popup is no longer lost – it can be picked back up where it left off.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added the interactions command bar. Every interaction you can run, plus the conversations still waiting on you, opens from one searchable panel instead of whichever toolbar happened to own it. Resumable interactions are listed first so they&apos;re easy to pick back up, and an entry carries its automation&apos;s description as a subtitle wherever one is set – which is a good reason to write them.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/command-bar.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automation/Scripting/Functions]&lt;/strong&gt; In &lt;a href=&quot;/docs/scripting/functions/&quot;&gt;automation scripting&lt;/a&gt;, added a &lt;a href=&quot;/docs/scripting/functions/#uuid&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uuid()&lt;/code&gt;&lt;/a&gt; function to generate a UUIDv1. This is useful for minting a stable identifier within a script – for instance, an LLM session id shared between an agent, a &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;composer&lt;/a&gt;, and a &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/llmTranscript/&quot;&gt;transcript&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; In automation scripting, a new &lt;a href=&quot;/docs/scripting/filters/#strip_pem_blocks&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|strip_pem_blocks()&lt;/code&gt;&lt;/a&gt; filter removes PEM blocks like PGP keys and SSL certificates. This is particularly useful when combined with the new &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; functionality, or when otherwise sanitizing blocks of text.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; In automation scripting, a new &lt;a href=&quot;/docs/scripting/filters/#strip_url_querystrings&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|strip_url_querystrings()&lt;/code&gt;&lt;/a&gt; filter removes the query string from URLs. This is particularly useful when combined with the new &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; functionality or when otherwise sanitizing blocks of text.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; In automation scripting, a new &lt;a href=&quot;/docs/scripting/filters/#strip_data_uris&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|strip_data_uris()&lt;/code&gt;&lt;/a&gt; filter removes base64-encoded content from data URIs. This is particularly useful when combined with the new &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; functionality or when otherwise sanitizing blocks of text.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Builder]&lt;/strong&gt; The &apos;AI Agent Chat&apos; starter template now generates a chat that drives the editor it sits beside. Before, the wizard made you hand-pick models and gave you a chat that could only talk: it had no way to see the thing you were looking at, no files to work with, and nothing to do about a conversation that outgrew its context window. The wizard now asks where the chat lives – the automation editor, the Data Query or Scripting testers, the &lt;a href=&quot;/docs/setup/developers/icon-builder/&quot;&gt;Icon Builder&lt;/a&gt;, a &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt; search bar, or a mail reply – and the generated automation ships the tools for that place, so the agent can act on what&apos;s on screen instead of asking you to paste it. Leave it blank and you get a standalone chat, same as before.&lt;/p&gt;

    &lt;p&gt;It also writes the system prompt, which is why the wizard no longer asks for one: an agent in the Icon Builder needs different orientation than one in the automation editor, and both need to be told what&apos;s mounted, so the prompt is composed from the answers you&apos;ve already given. &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;Filesystems&lt;/a&gt; are mounted through a chooser, one row per volume with a read-only or read-write switch, matching the Setup filesystem terminal; the agent gets a writable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; either way.&lt;/p&gt;

    &lt;p&gt;The model picker is gone – a generated chat falls through to your default model pool, so it runs on whatever models you already have configured, and pinning it is a matter of uncommenting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent:&lt;/code&gt; line and naming an AI worker, which stays portable between installations where naming a model does not. Long conversations get an exit too: &lt;a href=&quot;/docs/agents/#long-conversations&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/compact&lt;/code&gt;&lt;/a&gt; is offered to the agent and to you in the composer, alongside a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flatten&lt;/code&gt; example showing how to add your own. A generated chat isn&apos;t reachable from an editor until an &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; is pointed at it and enabled on a surface, so the generated script says so in its header.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Records]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/automations/commands/records.update/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;records.update:&lt;/code&gt;&lt;/a&gt; command for updating a batch of records in a single action. It takes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record_type&lt;/code&gt;, a list of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record_ids&lt;/code&gt;, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fields:&lt;/code&gt; to set, with an optional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;disable_events:&lt;/code&gt; toggle. Fields that must be unique – a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uri&lt;/code&gt;, an org or &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt;, an address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; – can&apos;t be bulk updated, since the same value can&apos;t be unique across many rows, and they&apos;re left out of autocomplete suggestions accordingly. A single-ID batch is treated as an ordinary single-record update. Workers must have the appropriate update permission for every target record.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Records]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/automations/triggers/record.bulkUpdate/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.bulkUpdate&lt;/code&gt;&lt;/a&gt; trigger for extending bulk update actions with your own. An &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; on this event runs once at the start for setup, once for each batch of target records (up to 100 IDs), and once at the end for tear-down. The event listener determines who can see or use these custom actions, and any automation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs:&lt;/code&gt; are displayed as prompts in the bulk update popup. Workers must still have the appropriate update permission for the target records.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; In automation scripting, a new &lt;a href=&quot;/docs/scripting/filters/#number_pretty&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|number_pretty&lt;/code&gt;&lt;/a&gt; filter formats large numbers in a human-friendly form – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{{12345678|number_pretty(1)}}&lt;/code&gt; reads as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;12.3M&lt;/code&gt;. Its one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;precision&lt;/code&gt; parameter sets the decimal places and defaults to none. It truncates rather than rounds, so a 32,768-token context window reads as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;32K&lt;/code&gt; the way everyone actually says it, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;999999&lt;/code&gt; can&apos;t round up into a nonsensical &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1000K&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; In automation scripting, new &lt;a href=&quot;/docs/scripting/filters/#bin2hex&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|bin2hex&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;/docs/scripting/filters/#hex2bin&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|hex2bin&lt;/code&gt;&lt;/a&gt; filters convert between a binary string and its hexadecimal representation. Decoded binary – the bytes of a message header, a hash digest, a packed identifier – is unprintable as a raw string and unsafe to slice by character, since a cut can land inside a multi-byte sequence. As hex it&apos;s two stable characters per byte, so it can be read, compared, and sliced at any even offset, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|hex2bin&lt;/code&gt; turns it back. Anything that isn&apos;t a string, and any hex value of odd length or with a non-hex character in it, returns nothing rather than raising an error.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[KATA/Automations]&lt;/strong&gt; Converting a dictionary to &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; with &lt;a href=&quot;/docs/scripting/filters/#kata_encode&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|kata_encode&lt;/code&gt;&lt;/a&gt; now annotates decimal numbers with &lt;a href=&quot;/docs/kata/#float&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@float&lt;/code&gt;&lt;/a&gt;, so they read back as numbers rather than text. The filter labels each value with the annotation for its type – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@int&lt;/code&gt; for a whole number, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@bool&lt;/code&gt; for a true or false – but decimals were written bare, so parsing the result returned the digits as a string. A script that encoded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.5&lt;/code&gt; and read it back got text it couldn&apos;t do arithmetic on without converting first. Whole numbers already survived this round trip and decimals did not.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;queues&quot;&gt;Queues&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/Hw5D1GlBtG4&quot; title=&quot;Process work faster with parallel queues&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs]&lt;/strong&gt; Introduced &lt;a href=&quot;/docs/queues/&quot;&gt;parallel queues&lt;/a&gt; with &lt;a href=&quot;/docs/queues/#consumer-extensions&quot;&gt;consumer extensions&lt;/a&gt;, FIFO ordering, and first-class &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue jobs&lt;/a&gt;. Added a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Extension_QueueConsumer&lt;/code&gt; extension point with built-in consumers (manual, internal, automation) for routing queue messages. Queue messages can be grouped under a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;job_id&lt;/code&gt; to track progress against a &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; record with singleton keys, worker ownership, record-level count caches, and arbitrary metadata.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/queue-job-parallel.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Automations]&lt;/strong&gt; Added &lt;a href=&quot;/docs/queues/#automation-backed-queues&quot;&gt;automation-backed queues&lt;/a&gt;. Previously, user-created queues were always manual and each one tediously required an automation timer and loop to drain. Automation-backed queues are automatically managed by the background queue. A batch size can be configured per queue (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; for expensive operations, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10-100+&lt;/code&gt; for batch operations). An automation is invoked with a batch of messages and inputs for the queue and optional &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt;. Any non-error response is considered successful delivery. Like event listeners, the most appropriate automation can be selected programmatically based on the event.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Queues]&lt;/strong&gt; Added the &lt;a href=&quot;/docs/automations/events/queue.consumer/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue.consumer&lt;/code&gt;&lt;/a&gt; automation event to process messages from &lt;a href=&quot;/docs/queues/#automation-backed-queues&quot;&gt;automation-backed queues&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Scheduler]&lt;/strong&gt; The &lt;a href=&quot;/docs/queues/#background-queue-scheduler&quot;&gt;&apos;Background Queue&apos;&lt;/a&gt; scheduled task randomly round-robins through batches of available queue messages and jobs. It continues until all work is drained or the allotted time is exhausted. This also catches worker-initiated &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue jobs&lt;/a&gt; that are no longer being actively monitored.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues]&lt;/strong&gt; Queue message progress reporting now efficiently buffers per-request and drains once at the end. This allows status reports to be simpler and incremental (loop iterations; per-error). &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;Queue job&lt;/a&gt; stats are automatically recached when their linked queue messages change, which allows O(1) lookups for the queue job monitor popup without database index aggregation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Performance]&lt;/strong&gt; A licensed installation now sizes its own &lt;a href=&quot;/docs/queues/#concurrency-slots&quot;&gt;concurrency pool&lt;/a&gt; from &lt;strong&gt;Setup » Configure » &lt;a href=&quot;/docs/setup/configure/queues/&quot;&gt;Queues&lt;/a&gt;&lt;/strong&gt; – a field in the interface, with no configuration file to edit and no restart. There&apos;s no ceiling on it: you&apos;re sizing Cerb to the machine it runs on, and you&apos;re the one paying for that machine. Every installation keeps a floor of &lt;strong&gt;three&lt;/strong&gt; slots; a Community installation stays there, and on &lt;a href=&quot;/pricing/&quot;&gt;Cerb Cloud&lt;/a&gt; the platform sets the count because it provisions the compute. Slots are reserved on the MySQL writer connection and released automatically when that connection closes, so an interrupted request can never permanently consume one.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Performance]&lt;/strong&gt; The &lt;a href=&quot;/docs/queues/#concurrency-slots&quot;&gt;concurrency pool&lt;/a&gt;&apos;s &lt;a href=&quot;/docs/queues/#lanes&quot;&gt;lane&lt;/a&gt; split is now configurable rather than derived from the slot count. Two fields on &lt;strong&gt;Setup » Configure » &lt;a href=&quot;/docs/setup/configure/queues/&quot;&gt;Queues&lt;/a&gt;&lt;/strong&gt; reserve slots for one kind of work – &lt;strong&gt;Batch only&lt;/strong&gt; and &lt;strong&gt;Agent turns only&lt;/strong&gt;, each at least one. &lt;strong&gt;Shared&lt;/strong&gt; is whatever the pool has left after those two, and serves either kind; the form labels it &lt;em&gt;What&apos;s left&lt;/em&gt;. That&apos;s why raising the slot count lands in &lt;strong&gt;Shared&lt;/strong&gt;: the new slots haven&apos;t been reserved for anything, so both kinds of work may take them. An &lt;strong&gt;Auto&lt;/strong&gt; button restores the default split, a quarter to each dedicated lane with the rest shared.&lt;/p&gt;

    &lt;p&gt;This is what stops batch work queuing behind a run of long agent turns: an installation that knows it&apos;s batch-heavy or agent-heavy can say so, rather than living with a quarter-of-the-pool formula that can&apos;t know. Lane configuration requires a subscription – a Community installation sees the same fields, filled in at three slots divided evenly and locked, with no Save and no &lt;strong&gt;Auto&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;Queue Jobs&lt;/a&gt; are first-class records with cards, profiles, and worklists. Jobs are initiated in the UI by a worker and group together related queue messages (search index, record import). Opening a queue job&apos;s card displays its current progress until complete. A &apos;singleton_key&apos; ensures certain jobs are only run once at a time (search re-indexing).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Cards]&lt;/strong&gt; Added a &apos;Queue Job Monitor&apos; card widget for &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; records.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Profiles]&lt;/strong&gt; Added a &apos;Queue Job Monitor&apos; profile widget for &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; records.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs/UX]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;Queue job&lt;/a&gt; monitor widgets display linked attachments directly. For instance, a worklist export&apos;s file appears on the job widget rather than only on the worklist marquee – workers can choose to view inline or download.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Queues/Performance]&lt;/strong&gt; Moved &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.changed&lt;/code&gt; event processing into the &lt;a href=&quot;/docs/queues/&quot;&gt;parallel background queue&lt;/a&gt;. This particularly improves performance on bulk updates and imports.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Import/Queues]&lt;/strong&gt; &lt;a href=&quot;/docs/worklists/&quot;&gt;Worklist&lt;/a&gt; file imports (CSV/JSONL) now run as a parallel background &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; instead of blocking the request. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1408&quot;&gt;#1408&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Performance]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/queues/#post-processing-chunks&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_job_chunk&lt;/code&gt;&lt;/a&gt; table for queue jobs that run in parallel but need post-processing on completion. For instance, exporting a worklist in parallel (CSV/JSONL/XML) but reassembling the chunks in sorted order at the end and writing a file attachment.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Export/Queues]&lt;/strong&gt; &lt;a href=&quot;/docs/worklists/&quot;&gt;Worklist&lt;/a&gt; file exports (CSV/JSONL/XML) now run as a parallel background &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; instead of blocking the request. On completion the chunks are sorted and saved as a file attachment linked to the job. The originating worker can close their browser and the export will continue in the background. They will receive a notification when the file is ready. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1837&quot;&gt;#1837&lt;/a&gt;]&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/worklist-export-job.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Bulk/Queues]&lt;/strong&gt; &lt;a href=&quot;/docs/worklists/&quot;&gt;Worklist&lt;/a&gt; bulk updates now use parallel background &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue jobs&lt;/a&gt; for improved performance and accountability. This fixes fragility with the older browser-based incremental updates that could abort after a timeout, navigation, or other error. When a bulk update starts, the queue job progress monitor popup opens. If a worker closes their browser or navigates away the update job will continue in the background. They will receive a notification when the job is complete.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs]&lt;/strong&gt; Added &lt;a href=&quot;/docs/records/types/queue_job/#progress-tracking&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cardinality&lt;/code&gt;&lt;/a&gt; to queue messages. This represents the work units per message. For instance, each message in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;records.bulk_update&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;records.export&lt;/code&gt; queues may represent 100 record IDs. The &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; monitor reports progress in work units rather than raw message counts.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs/Log]&lt;/strong&gt; Added a permanent &lt;a href=&quot;/docs/records/types/queue_job/#log&quot;&gt;log&lt;/a&gt; for &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; processing. When a queue message succeeds or fails, a summary message and metadata are stored. For instance, on a worklist bulk update, the metadata contains the affected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record_ids&lt;/code&gt; for an audit trail.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs]&lt;/strong&gt; The &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt; monitor now displays parallel consumer processes. Consumers ramp up to max concurrency as needed, but start with one to reduce contention and let small jobs finish with less network noise. Consumer processes report back on their progress so the monitor can scale them in and out.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;Queue jobs&lt;/a&gt; can now be canceled to immediately remove pending messages and end the job. Previously, jobs could only be paused or deleted.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Queues]&lt;/strong&gt; Added a new metric &lt;a href=&quot;/docs/metrics/cerb.queue.messages.open/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.queue.messages.open&lt;/code&gt;&lt;/a&gt; gauge to snapshot available and in-flight message counts per queue. This helps identify stalled queues and backpressure.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Queues]&lt;/strong&gt; Added a new metric &lt;a href=&quot;/docs/metrics/cerb.queue.messages.processed/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.queue.messages.processed&lt;/code&gt;&lt;/a&gt; counter for done and failed messages per queue and &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;job&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues]&lt;/strong&gt; &lt;a href=&quot;/docs/queues/&quot;&gt;Queues&lt;/a&gt; can now configure a retry policy – a maximum number of retries and a retry window – using exponential backoff so each successive failure waits longer. Setting max retries to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; disables retries for that queue and makes failures terminal. For instance, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.storage.migrations&lt;/code&gt; queue may hit a temporary network error while sending attachments to an S3 storage profile; it will now retry over the following day, while the content continues to be served from its current storage profile in the meantime.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Storage/Queues]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.storage.migrations&lt;/code&gt; &lt;a href=&quot;/docs/queues/&quot;&gt;queue&lt;/a&gt; covering the whole lifecycle of storage objects – migrations, archival, and deletions. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cron.storage&lt;/code&gt; scheduler job now enqueues storage operations for parallel processing instead of performing them inline and blocking.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Storage/Queues]&lt;/strong&gt; Storage schema deletions are now handled by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.storage.migrations&lt;/code&gt; background queue rather than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devblocks_storage_queue_delete&lt;/code&gt; table, and existing rows are migrated to the queue on upgrade. This wasn&apos;t used by the &apos;disk&apos; and &apos;database&apos; storage engines, but it is by &apos;s3&apos;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues]&lt;/strong&gt; &lt;a href=&quot;/docs/queues/&quot;&gt;Queues&lt;/a&gt; now have a configurable &apos;claim window&apos; – the amount of time a consumer is granted to process a message it has claimed. If a message stays in flight longer than that, the stalled claim is released and the message is either failed or retried, which handles a consumer that dies unexpectedly instead of leaving work stuck forever.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues]&lt;/strong&gt; Background work now runs in &lt;strong&gt;lanes&lt;/strong&gt;, so a queue of AI agent turns can no longer take every concurrency slot. Slots are split into a fast lane, a slow lane, and a commons that either may use. Work that holds a slot for as long as a model takes to answer – an agent turn, a &lt;a href=&quot;/docs/setup/configure/scheduler/&quot;&gt;scheduler&lt;/a&gt; job that runs in parallel – draws from the slow lane; work that yields every batch – a bulk update, an import, an export – draws from the fast one. Neither can take the other&apos;s dedicated slots, and half the pool stays shared, so an idle install still gives any single job everything it can use. The axis is how long a slot is &lt;em&gt;held&lt;/em&gt;, not how important the work is. A three-slot install gets one slot per lane and one shared; below three there&apos;s nothing to divide and every slot is shared. Nothing about this is configured – a job names a lane in code and gets back a slot or nothing, and the split follows the pool size.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Scheduler]&lt;/strong&gt; The per-job &lt;strong&gt;&apos;runs in parallel up to&apos;&lt;/strong&gt; setting is gone from &lt;strong&gt;Setup » Configure » &lt;a href=&quot;/docs/setup/configure/scheduler/&quot;&gt;Scheduler&lt;/a&gt;&lt;/strong&gt;. There&apos;s nothing left to tune: a parallel job takes a slot from the slow lane like any other long-running drain, and drains as fast as it can. A concurrent job&apos;s row now counts down on a real timer instead of showing a static &quot;continuous&quot; label – though it stays out of the page&apos;s &lt;strong&gt;next to fire&lt;/strong&gt; chip, since a job that drains as fast as it can has no cadence to be next on. &lt;strong&gt;Run now&lt;/strong&gt; on a parallel job takes a real slot – so it answers &quot;All concurrency slots are busy. Try again in a moment.&quot; rather than starting work that has nowhere to run.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/LLM]&lt;/strong&gt; A single background worker now runs several &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; turns at once, so a queue of waiting turns finishes in about the time of its slowest instead of the sum of all of them. An agent turn spends nearly all of its life waiting on the model provider, so a worker holding one turn sits idle for almost all of it. A worker now carries several turns together, taking the next queued turn as each one finishes, for as long as its admission window is open – and every turn admitted still gets its full time budget, since the window decides whether another turn &lt;em&gt;starts&lt;/em&gt;, never whether one finishes. One conversation still advances a single turn at a time across every worker on the install: resuming the same chat in two tabs, on two devices, or from an unattended agent can no longer interleave two replies into it, because a worker that finds a conversation already advancing puts its message back and runs it once the conversation is free, without counting that as a failed attempt. There&apos;s no configuration option; the count follows the license.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Queues]&lt;/strong&gt; Added a &lt;strong&gt;Setup » Configure » Queues&lt;/strong&gt; page: what the concurrency pool is divided into, and what&apos;s running in it right now. &lt;strong&gt;Setup » Subscription&lt;/strong&gt; answers how much capacity you have; this answers what it&apos;s doing. The split is drawn one block per slot on two rows, &lt;strong&gt;Batch jobs&lt;/strong&gt; and &lt;strong&gt;Agent turns&lt;/strong&gt;, so you can see which slots each kind of work holds and which ones both may use – and it&apos;s drawn from the same component the Subscription page uses, so the two can&apos;t come to disagree about the shape of the pool.&lt;/p&gt;

    &lt;p&gt;Beneath it, a live occupancy row marks the slots that are busy this second. The reading is polled, so the page carries its own countdown ring showing when the next one lands; the ring doubles as the interval picker, the way it does on a workspace &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt; tab, and a toggle beside it turns refreshing off entirely. The countdown holds while the tab is hidden rather than draining and firing a burst of catch-up polls when you come back.&lt;/p&gt;

    &lt;p&gt;A pool whose occupancy can&apos;t be read says so, rather than drawing an empty pool – an idle install and a failed read look identical in the numbers, and quietly showing zero would be the most reassuring possible way to be wrong. The page is also where a licensed installation sets the pool size and divides it between the lanes.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-queues.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;search-indexes&quot;&gt;Search indexes&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/a2IhZPPLWls&quot; title=&quot;Custom search indexes in Cerb 11.2&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Records]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;Search Index&lt;/a&gt; record type. Each index manages a linked custom &lt;a href=&quot;/docs/search/&quot;&gt;search filter&lt;/a&gt; on any record type. New search index extensions can be implemented with &lt;a href=&quot;/docs/plugins/&quot;&gt;plugins&lt;/a&gt; (e.g., TF-IDF, BM25, vector embeddings, Elasticsearch, Qdrant, Pinecone).&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/search-index-editor.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;

    &lt;p&gt;Previously, full-text search schemas required backend code and database changes (e.g., email content, comments).&lt;/p&gt;

    &lt;p&gt;A search index can be created on any combination of fields with a strategy specific to the use case; improving performance and efficiency.&lt;/p&gt;

    &lt;p&gt;For instance, a &quot;sparse&quot; message-based search index can only include outgoing worker replies from the past year. This has a dramatically smaller search space in large environments and provides near-instantaneous results.&lt;/p&gt;

    &lt;p&gt;Similarly, a search index can be created for a high-traffic custom field, or an arbitrary combination of fields (title + url + summary).&lt;/p&gt;

    &lt;p&gt;External resources (docs, KB, FAQ, websites) can be indexed using &lt;a href=&quot;/guides/records/custom-records/&quot;&gt;custom records&lt;/a&gt; and made available to &lt;a href=&quot;/docs/workers/&quot;&gt;workers&lt;/a&gt; and &lt;a href=&quot;/docs/interactions/&quot;&gt;AI agents&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; Implemented a local full-text &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; extension that is optimized for performance and intended to replace MySQL&apos;s hard-to-scale FULLTEXT indexes. For each index, a record type, filter query, and content template are configurable. This makes it simple to create custom search indexes on only the content you care about; for instance, a set of custom fields on the past 3 years of tickets. Cerb will automatically manage these constraints to keep the index updated. Each search index adds a new &lt;a href=&quot;/docs/search/#search-indexes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter:&lt;/code&gt;&lt;/a&gt; to worklists of that record type. When a search index has priority zero it overrides the default filter when a search query has no explicit filters.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text/Developers]&lt;/strong&gt; Technical notes. The new local full-text search index extension splits tokens on spaces and punctuation but allows dashes and dots within terms (e.g., hostnames, email addresses, IPs, ticket masks). This significantly improves search performance because these terms can be matched directly without a phrase search. Tokens are stored as xxHash 64-bit signed integers, so each is a fixed 8 bytes regardless of length. Token hashes are consistent across all Cerb environments. Lookups are O(1). Distinct tokens are linked to record IDs with a precached term frequency for quick TF-IDF/BM25 scoring. Queries sort &apos;AND&apos; terms by the lowest document frequency first and JOIN in that order to significantly reduce lookups. Since indexes are now managed by Cerb and not MySQL, indexes can be analyzed, pruned, merged, split, sharded, etc.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Records]&lt;/strong&gt; On all record types, the default search filter is now configurable when no explicit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter:&lt;/code&gt; is given by setting the priority of the &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; to zero. For instance, default queries can route to a custom search index for a specific set of custom fields rather than just the record name (e.g., part number lookup). With any other priority, custom search filters will be sorted to the top of query autocompletion suggestions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; Added &lt;a href=&quot;/docs/search/#search-indexes&quot;&gt;wildcard support&lt;/a&gt; to custom search indexes with asterisk (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;). This matches tokens in the vocabulary using OR for that term. For instance: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11.1* release*&lt;/code&gt; to match &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11.1.6 released&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11.1 release&lt;/code&gt;.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/search-wildcard.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; Added &lt;a href=&quot;/docs/search/#search-indexes&quot;&gt;stemming support&lt;/a&gt; to custom search indexes with a tilde suffix (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt;). This fuzzy matches tokens in the vocabulary using OR. For instance: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;automate~&lt;/code&gt; expands to: automate, automates, automation, automating, automated.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; Added support for &lt;a href=&quot;/docs/search/#search-indexes&quot;&gt;excluded terms&lt;/a&gt; in custom search index queries by prefixing a term with a dash (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;). At least one included term is still required. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;workflow -automation&lt;/code&gt; matches documents that contain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;workflow&lt;/code&gt; while excluding any that also contain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;automation&lt;/code&gt;.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/search-excluded-terms.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;Search index&lt;/a&gt; filters send additional parameters through to extensions. For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;top:10&lt;/code&gt; for ranked results.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; Added support for &lt;a href=&quot;/docs/search/#search-indexes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;top:&lt;/code&gt;&lt;/a&gt; parameter to limit and rank results by score in full-text search queries.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Full-Text]&lt;/strong&gt; Added support for boosting TF-IDF scores using custom templates in full-text &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search indexes&lt;/a&gt;. This gives more relevancy to document titles, etc.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Scheduler]&lt;/strong&gt; Updated the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt; scheduler job to handle custom &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search indexes&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Queues]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;Search index&lt;/a&gt; cards now display indexing progress and have a re-index option to launch a background &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue job&lt;/a&gt;.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/search-index-card.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search]&lt;/strong&gt; Added &lt;strong&gt;search facets&lt;/strong&gt; – named subsets of a record type. Some useful views are a filtered slice of an existing record type rather than a type of their own; &lt;a href=&quot;/docs/workers/&quot;&gt;AI workers&lt;/a&gt; are the obvious case, since they&apos;re workers but &quot;Workers&quot; isn&apos;t where you&apos;d look for them. A facet gives that slice its own name, icon, and Search menu entry with its filter always applied, and sits beside the real record types rather than nested in a submenu. Each facet keeps its own columns and sort, so customizing it doesn&apos;t disturb the parent type&apos;s search.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/search-facets.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Search]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/metrics/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.search.index.records&lt;/code&gt;&lt;/a&gt; gauge metric for counting records over time per &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; and engine.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Search]&lt;/strong&gt; Added on-demand search re-indexing for specific records. A record can be made searchable immediately after it&apos;s written rather than waiting for the next scheduler sweep, so a newly created record is findable right away. Bulk writers – ZIP imports, re-indexes, and bundled filesystem syncs – index in batches instead, so a thousand-file import doesn&apos;t reindex a thousand times.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;cerb-ui&quot;&gt;Cerb UI&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/ArVRK6cwsBM&quot; title=&quot;Goodbye jQuery UI: Cerb 11.2 ships its own component library&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a modern, reusable &lt;strong&gt;&lt;a href=&quot;/docs/developers/cerb-ui/&quot;&gt;Cerb UI&lt;/a&gt;&lt;/strong&gt; component library. This gives Cerb full control of its own interface and makes it much easier for widgets and plugins to add visual elements with consistent styling, light and dark mode support, and interactivity. It also fully replaces jQuery UI, which has been in maintenance-only mode for several years and is removed entirely in this release. Components are plain JavaScript with no bundler and no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;: when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEVELOPMENT_MODE&lt;/code&gt; is enabled the individual scripts load from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerberusweb.core/resources/js/cerb-ui/&lt;/code&gt; for real-time editing, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer build-js&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer dist&lt;/code&gt;) concatenates and minifies them into a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-ui.js&lt;/code&gt; for production. The first dozen components totaled around 35KB, compared to jQuery UI&apos;s 230KB+.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[UI/Icons]&lt;/strong&gt; Replaced Glyphicons with a modern, custom Cerb SVG &lt;a href=&quot;/docs/developers/icons/&quot;&gt;icon set&lt;/a&gt;. The icons are monochromatic line icons that inherit the current text color and render cleanly at any size in light or dark mode, and new icons can easily be generated in the same style for any use case. All &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glyphicons glyphicons-*&lt;/code&gt; CSS classes were replaced with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-icons cerb-icon-*&lt;/code&gt; versions. The reference set was pared down to the icons actually used, with modern additions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bot&lt;/code&gt;. If a &lt;a href=&quot;/docs/sheets/&quot;&gt;sheet&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icon&lt;/code&gt; column specifies an unknown icon name, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zap&lt;/code&gt; is now used as the default. If you&apos;ve customized toolbar sections, update them to reference the new icon names.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-icon-set.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Redesigned the ticket conversation view. Messages, drafts, comments, and notes now read as distinct entries with badged author avatars, aligned headers, and hover toolbars.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/ticket-conversation.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Dialog&lt;/code&gt; component for draggable, resizable, and minimizable floating dialogs. It wraps an existing element and restores it to its original place when destroyed, and its colors are theme tokens so dark mode is automatic. This replaces jQuery UI Dialog.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Dialog]&lt;/strong&gt; Minimized popup windows now group into a single tray icon in the top right, which stays fixed as the page scrolls. Clicking the tray opens a menu of popup names to restore from, and &apos;Restore all&apos; fans them out rather than stacking them on top of each other. Previously, minimized popups piled up at the top of the page and had to be shuffled through to find the right one.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/dialog-tray.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Dialog]&lt;/strong&gt; When two or more popups are minimized to the tray, its menu offers a &apos;Close all&apos; shortcut.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Dialog]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Shift+Esc&lt;/code&gt; to minimize the topmost dialog popup to the tray.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Dialog]&lt;/strong&gt; In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Dialog&lt;/code&gt;, added an opt-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;closeWarnOnUnsavedChanges&lt;/code&gt; guard that tracks whether form controls were actually modified. Previously the warning fired on close if a popup contained any form controls at all, changed or not. The same guard also catches navigating away from the page entirely, so unsaved work isn&apos;t lost to a stray click. Elements or whole subtrees can be excluded with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-cerb-ui-dialog-no-dirty&lt;/code&gt; attribute.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Confirm]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Confirm&lt;/code&gt; as the modern replacement for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;confirmPopup()&lt;/code&gt;, with a locked-down modal design and customizable title, body, buttons, and callbacks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Menu&lt;/code&gt; component for lightweight cascading menus, replacing jQuery UI for large and deep trees. It parses a nested list once into a data model, renders only the open path into the DOM, and virtualizes any panel past a threshold – a 100,000-item menu stays at roughly 25 DOM nodes. Optional type-to-filter searches every leaf and shows matches with breadcrumb context.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Tooltip&lt;/code&gt; component for floating, auto-positioning tooltips with DOM-aware auto-hide and screen boundary handling.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Tooltip&lt;/code&gt; supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;point&lt;/code&gt; mode for charts and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anchored&lt;/code&gt; mode for tutorials and callouts. Anchored mode accepts jQuery-style &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;at&lt;/code&gt; relative position strings, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;center top&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Tabs&lt;/code&gt; component for lightweight, accessible tab interfaces. Tabs can toggle content already on the page or fetch it on first activation, with a loading spinner, caching, and keyboard navigation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Accordion&lt;/code&gt; component for expandable and collapsible sections with keyboard navigation, callbacks, and scrollable panels. This replaces jQuery UI accordions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Sidebar&lt;/code&gt; component for collapsible vertical navigation rails with sections, icons, and badges. Sidebar options can open internal or external links, fetch content dynamically like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Tabs&lt;/code&gt;, or run arbitrary callbacks. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;palette&lt;/code&gt; mode variant turns the rail into a library of item templates that can be dragged onto another element or canvas.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Toolbar&lt;/code&gt; component for configurable toolbar strips with buttons, menus, badges, and interaction support. It&apos;s the standalone successor to the jQuery &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerbToolbar()&lt;/code&gt; plugin, and existing worker interactions keep working unchanged.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SplitPane&lt;/code&gt; component: two panes separated by a draggable divider, horizontal or vertical. Sizing is percentage-based, so a split pane built while hidden still renders correctly once revealed and tracks container resizes automatically.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Sortable&lt;/code&gt; component for drag-and-drop reordering. During a drag it shows both the item&apos;s original slot and the current insertion point, so where it will land is unambiguous.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Draggable&lt;/code&gt; component for lifting and dragging elements into designated drop zones.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Droppable&lt;/code&gt; component for defining drop zones that accept draggable elements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.KataEditor&lt;/code&gt; component to replace the Ace.js in-browser code editor for &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt;. It provides KATA-aware syntax highlighting, contextual autocompletion, line numbering, gutter markers, code folding with fold-to-depth controls, indentation guides, find and replace on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mod+F&lt;/code&gt;, comment toggling on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mod+/&lt;/code&gt;, and clickable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb:&lt;/code&gt; URI markers in the gutter that open the referenced record. Large documents render through viewport virtualization. It also implements the primary Ace API for driving an editor programmatically, which allows much tighter integration with KATA and &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt;.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-kata-editor.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Editors]&lt;/strong&gt; Introduced &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diffGutter&lt;/code&gt; across the Markdown, KATA, and Scripting editors for real-time change tracking against a save checkpoint, with added, modified, and deleted markers, a reset action, and interactive diff popovers. You can see exactly what changed since the last save without leaving the editor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.JsonEditor&lt;/code&gt; component with syntax highlighting and bracket-based code folding for JSON documents, replacing the Ace editor. It also validates JSON as you type and marks errors in the gutter.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/ScriptingEditor]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ScriptingEditor&lt;/code&gt; component for Cerb&apos;s Twig and KataScript template documents – email signatures, HTML and widget templates, and bot scripting – replacing the Ace Twig editors. It highlights embedded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{{ }}&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{% %}&lt;/code&gt; tags, autocompletes scripting commands, functions, and filters, and offers a line-number gutter with markers, find and replace, line move and delete, autosizing, and read-only and single-line modes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/MarkdownEditor]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.MarkdownEditor&lt;/code&gt; component – a lightweight Markdown prose editor that retires the legacy jQuery UI text editor, toolbar, autocomplete, and inline-image-paste stack used by the mail reply and comment composers. It adds subtle color-only Markdown syntax highlighting, a formatting toolbar, a Markdown/plaintext switcher, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mention&lt;/code&gt; autocompletion with rich avatar rows, inline image paste and upload, and find and replace.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SearchQuery&lt;/code&gt; component for building search queries with syntax highlighting and autocompletion, replacing the Ace editor. It understands Cerb&apos;s quick search grammar – plain full text, booleans, filters, quoted literals, lists, and nested searches – and autocompletes against the filter path at the caret, so suggestions stay relevant several levels deep.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Search]&lt;/strong&gt; Replaced Ace.js in the &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt; quick search editor with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SearchQuery&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SearchQuery&lt;/code&gt;, added colored field-type icons to the autocomplete suggestions menu, so the kind of field being suggested is obvious at a glance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/DataQuery]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.DataQuery&lt;/code&gt; multi-line editor component for &lt;a href=&quot;/docs/data-queries/&quot;&gt;data queries&lt;/a&gt;, with syntax highlighting for both the query syntax and embedded scripting tags, toolbars, and autocompletion.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/DiffViewer]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.DiffViewer&lt;/code&gt; component – a side-by-side &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; diff that replaces the ace-diff viewer. Two editor panes show per-line add and remove tints joined by curved connectors, with synchronized scrolling. Long runs of identical lines collapse behind expandable dividers to keep large diffs readable, and the right pane can optionally be made editable so the diff recomputes live as you type. The comparison is computed in the browser, with no server round-trip and no external library.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Change History]&lt;/strong&gt; Revamped the &apos;Change History&apos; popup in the automation, event listener, and widget editors to use the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.DiffViewer&lt;/code&gt; rather than ace-diff. Any two revisions can now be compared, not just a revision against the current version, and a &apos;Restore this version&apos; action copies the historical document back into the editor.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-diffviewer.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SyntaxHighlight&lt;/code&gt; for lightweight, read-only code highlighting with reusable KATA and JSON tokenizers. The server emits raw code carrying a language marker, so the output stays portable for API consumers and non-Cerb UI portals while the browser adds the color.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.RecordChooser&lt;/code&gt; component for server-backed single and multiple record selection, with ACL-filtered autocompletion, lazy-loaded avatars, an inline create button for adding a missing record without leaving the form, and integration with the existing chooser popups. Selections render as chips that open the record&apos;s card on click.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ContextChooser&lt;/code&gt; component for multi-record-type selection. A chip head at the front switches the record type on the fly and autocompletes within it, and selections can span types – an &apos;Owner&apos; chooser can move between global, role, group, and worker without a separate control for each.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/TextChooser]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.TextChooser&lt;/code&gt; component – a plain text input with optional endpoint-backed suggestions. It&apos;s the freeform sibling of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RecordChooser&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ContextChooser&lt;/code&gt;: accepting a suggestion just writes text, and any typed value is always allowed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/ValuePicker]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ValuePicker&lt;/code&gt; component for small, local option sets, replacing tall page-scrolling &apos;Multiple Checkbox&apos; lists. Selections show as tags in the options&apos; defined order, and a filterable dropdown lists every option with the picked ones dimmed and checked. Values post under the original field names, so existing save handlers are unchanged.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/TagInput]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.TagInput&lt;/code&gt; component – a freeform tag field that replaces tall &apos;List&apos; fields of repeating text inputs. Type and press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enter&lt;/code&gt; (or comma) to turn text into a removable chip, paste to add several at once by splitting on newlines, tabs, or commas, press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Backspace&lt;/code&gt; on an empty input to remove the last tag, and double-click a chip to rename it in place.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SelectMenu&lt;/code&gt; component that enhances native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;select&amp;gt;&lt;/code&gt; elements with searchable, styled dropdowns.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Datepicker&lt;/code&gt; component for populating date inputs from a calendar. It also provides a free-text field that accepts natural language, parsed on the server – so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next tuesday&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+3 days&lt;/code&gt; works as well as a date.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.DatePicker&lt;/code&gt; can display indicator pips on the calendar for arbitrary datasets, so days that already have activity stand out before you pick one.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ColorPicker&lt;/code&gt; component for Photoshop-style color selection with palette presets, hue, saturation, and opacity. This replaces the miniColors jQuery plugin.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/IconPicker]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.IconPicker&lt;/code&gt; component – a zero-dependency icon picker that turns a text input into a &quot;well&quot; button opening a floating, filterable grid of every Cerb icon, with full keyboard navigation and type-to-filter.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/ImageEditor]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ImageEditor&lt;/code&gt; component – an editable image &quot;well&quot; that opens a canvas editor in a dialog. Pan and zoom an image under a fixed-aspect crop frame (rectangular or circular), fill a background color, tint, erase, or pick a Cerb icon, and pull image bytes from the configured profile image toolbar as text or a monogram, an upload, a remote URL, or an icon. Edits are non-destructive – pan, zoom, and crop only rasterize on save.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Replaced the avatar chooser popup with the inline image editor. Profile pictures are now cropped and positioned in place instead of in a separate dialog.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/FileUpload]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.FileUpload&lt;/code&gt; component for inline drag-and-drop and click-to-browse file uploads with no popup. Files upload as you add them and show per-file progress, with validation for accepted types, maximum size, and file count.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Slider]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Slider&lt;/code&gt; component, succeeding the legacy jQuery UI slider. It supports minimum, maximum, and step bounds, optional midpoint delta coloring, keyboard control, and a value tooltip on hover, focus, and drag. Positioning is percentage-based, so it renders correctly even when initialized while hidden – in a bulk update popup or a custom field row, for instance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.PriorityPicker&lt;/code&gt; component for multi-selecting items and ordering them by priority with drag-and-drop. Selection and ordering are independent, so an overall priority can be set once and individual items toggled on and off without losing the order.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Avatar&lt;/code&gt; component for monogram avatars and avatar stacks, generated in the browser with hash-locked colors so the same record always gets the same color. It supports image placeholders, configurable sizes, status badges, and non-square aspect ratios.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.NodeEditor&lt;/code&gt; component – a visual node-based canvas with extensible block types, inlets and outlets, hierarchical data types, draggable edge connections, blackboard variables, a scripting expression builder, a drag-to-add palette, zoom and pan, a minimap, JSON import and export, and a read-only mode. Dragging from an outlet onto empty canvas opens a picker that creates and connects a new node in one step.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-node-editor.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Introduced &lt;a href=&quot;/docs/developers/cerb-ui/#ai-agents&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.AgentPrompt&lt;/code&gt;&lt;/a&gt; for composing an agent turn, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mention&lt;/code&gt; autocompletion, image paste, and a model picker. It backs the &lt;a href=&quot;/docs/automations/triggers/interaction.worker/elements/agentPrompt/&quot;&gt;agentPrompt&lt;/a&gt; form element in &lt;a href=&quot;/docs/interactions/&quot;&gt;worker interactions&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Agent Transcript]&lt;/strong&gt; Introduced &lt;a href=&quot;/docs/developers/cerb-ui/#ai-agents&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.AgentTranscript&lt;/code&gt;&lt;/a&gt; for reading agent sessions. Turns read like ticket messages: a large author avatar, a sender and meta header, token chips, a hover-revealed action toolbar, and an indented sub-thread of thinking and tool-call bubbles.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Introduced &lt;a href=&quot;/docs/developers/cerb-ui/#ai-agents&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.AgentPane&lt;/code&gt;&lt;/a&gt;, a collapsible agent chat that sits beside an editor. It&apos;s available in the automation editor, the Bot Scripting tester, the Data Query tester, the Icon Builder, and mail Reply.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-pane.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Switcher&lt;/code&gt; component for segmented toggles, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localStorage&lt;/code&gt; persistence so a chosen segment survives a page reload, and programmatic selection.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Toggle&lt;/code&gt; component for styled on/off switches with programmatic control and event callbacks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.TimeRing&lt;/code&gt; component for rendering SVG countdown and progress rings with customizable labels and dynamic updates.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Spinner&lt;/code&gt; component for reusable, pure-CSS animated SVG spinners, and integrated it into the header.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Spinner&lt;/code&gt; variants: arc, dots, and spark.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.date&lt;/code&gt; module of date and time formatters: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remain()&lt;/code&gt; for countdowns (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;45s&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2:05&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;20h&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1d&lt;/code&gt;), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ago()&lt;/code&gt; for elapsed time (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;just now&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3m ago&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2h ago&lt;/code&gt;), and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strftime()&lt;/code&gt; for lightweight formatting with GNU-style patterns.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.num&lt;/code&gt; module for number formatting in chips, legends, and stat values – compact counts (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1500&lt;/code&gt; renders as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.5k&lt;/code&gt;), digit grouping, percentages, and humanized durations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Async]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.utils.apply&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.utils.series&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.utils.parallelLimit&lt;/code&gt; for client-side async flow control – building task lists, running them strictly one at a time, or running them with a cap on how many are in flight at once.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Effects]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.effects&lt;/code&gt; – small one-shot animation helpers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flash&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transfer&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pulse&lt;/code&gt;) that replace the cosmetic jQuery UI &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.effect(&apos;highlight&apos;|&apos;transfer&apos;|&apos;pulsate&apos;)&lt;/code&gt; API with CSS animations. Each is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefers-reduced-motion&lt;/code&gt; aware: it skips the animation and runs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onEnd&lt;/code&gt; callback synchronously, and arms a timeout fallback so a dropped animation event never strands the callback.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-ui-form&lt;/code&gt; styles for consistent form layouts with minimal markup.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-ui-kbd&lt;/code&gt; styles for rendering keyboard key caps.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Separator]&lt;/strong&gt; In Cerb UI separators, added optional arrows on the start and end lines, plus a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--thick&lt;/code&gt; variant.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Icons]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-u-anim-*&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-u-anim-*-hover&lt;/code&gt; icon animation utilities, so an icon can animate continuously or only on hover.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Icons]&lt;/strong&gt; Added animated &quot;magic gradient&quot; styles for icons, including sweep, aurora, and cycle effects.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[CerbUI/Icons]&lt;/strong&gt; Updated several editor toolbars for consistency, replacing the &apos;tags&apos; icon with &apos;placeholders&apos;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Agents]&lt;/strong&gt; &lt;a href=&quot;/docs/developers/cerb-ui/#ai-agents&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.AgentPane&lt;/code&gt;&lt;/a&gt; can float its chat in a dialog instead of splitting its host. A pane assumed its host was a big rectangle worth splitting down the middle, which rules out anything one line tall and anything already as wide as it wants to be – whole classes of host could never have an agent no matter how much they&apos;d benefit from one. Float mode leaves the host completely untouched and puts the chat in a non-modal, draggable, resizable, minimizable dialog. Non-modal is the point: you keep working underneath it rather than dismissing the chat to do anything. Minimizable is the other half, since it docks into the shared dialog tray and a long conversation survives being set aside. Split mode is unchanged and remains the default.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-pane-float.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Search]&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.SearchQuery&lt;/code&gt; can mount an agent pane on any search field, with a built-in command bridge covering the three things an agent needs from one: read the current query, write a replacement, and run it. A host can override any of the three and extend the vocabulary without restating the rest. To make room on the right, the manual-suggestions trigger moves to the left magnifier – the affordance nearest the thing it acts on – across every search field, including record choosers and query prompts. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl/Cmd+Space&lt;/code&gt; is unchanged.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Icons]&lt;/strong&gt; Added brand &lt;a href=&quot;/docs/developers/icons/&quot;&gt;icons&lt;/a&gt; for more LLM providers: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logo-azure&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logo-deepseek&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logo-meta&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logo-mistral&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logo-moonshot&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logo-xai&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Rating]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Rating&lt;/code&gt; component for ordinal ratings, drawn as a row of repeated glyphs filled from the left up to the selected value. It&apos;s documented with a live example under &lt;strong&gt;Setup » Developers » UI Reference » Rating&lt;/strong&gt;. The host owns the glyph and the scale and the component only paints state and reports the value, so any &lt;a href=&quot;/docs/developers/icons/&quot;&gt;icon&lt;/a&gt; works and the same control reads as stars, brains, locks, or coins depending on what&apos;s being rated. Hovering previews the value you would set – repainting the glyphs and live-updating the tier label beside them – and moving off the control restores both to what&apos;s stored. Clicking the glyph &lt;em&gt;at&lt;/em&gt; the current value clears back to unrated, which is what keeps a mis-click fixable without the host adding a separate Clear affordance; clicking a lower filled glyph sets that lower value instead. A text label beside the row always names the current tier, reading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unrated&lt;/code&gt; at zero, so a reader tells &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no-training&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zdr&lt;/code&gt; without counting glyphs. Values are compared, never counted: a scale can be a plain 1-5 or sparse (10/20/30/40) so a tier can be inserted later without rewriting stored rows, and the component behaves identically either way.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Meter]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-ui-meter&lt;/code&gt; component that reports an ordinal level as a row of small filled blocks, with an entry under &lt;strong&gt;Setup » Developers » UI Reference » Meter&lt;/strong&gt;. It&apos;s markup and CSS with no JavaScript to construct, which is what lets a worklist template, the agent prompt&apos;s model picker, and a record card all draw one without instantiating anything. A meter is the read-only twin of the rating control – the same 1-of-N read, sized for a worklist cell, a menu row, or a property grid. Its two neighbors cover the other cases: a rating when the value should be editable, and a distribution bar when the segments are proportions of a whole at continuous widths. Profile and card property grids can draw a field as a meter through a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;meter&lt;/code&gt; field type. An unrated meter keeps all of its blocks and fills none rather than rendering nothing, because a missing meter leaves a hole and breaks the comparison down a column, where a row of gray reads as &quot;not rated&quot;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/RecordChooser/ValuePicker]&lt;/strong&gt; A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.RecordChooser&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ValuePicker&lt;/code&gt; can now show values it doesn&apos;t own – an inherited set, a grant that comes from somewhere else – as faded &quot;ghost&quot; tiles sitting alongside your own selections. A ghost is the same tile as the ones beside it, just faded and without a remove button: it isn&apos;t yours to remove, and it posts nothing, so the field still submits only what you picked. What it answers is &quot;what do I already have here?&quot;, in the one place you&apos;re looking while you decide what to add. That question used to be answered by a placeholder, which only works while a field is &lt;em&gt;empty&lt;/em&gt; – it disappears the moment you add anything, which is exactly when you most need to see what you&apos;re adding to. A ghosted value is also dropped from the field&apos;s own menu, so you can&apos;t add the same thing twice. Ghosts are managed by the page rather than by the field, because what they stand for lives somewhere else on the form, so a field can follow an edit made elsewhere without being rebuilt. Both components are documented in &lt;strong&gt;Setup » Developers » UI Reference&lt;/strong&gt; with a live example each: two fields side by side where the left one grants and the right one adds to it.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;charts-and-dashboards&quot;&gt;Charts and dashboards&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Charts]&lt;/strong&gt; Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Chart&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.CartesianChart&lt;/code&gt; components for shared-axis charts, with series plotted as bars, lines, splines, and areas. Series can be stacked into arbitrary groupings, the x-axis supports either categories or a continuous time or linear range and can be rotated to horizontal, and a second y-axis is supported. Legends, tooltips, ticks, axis labels, scaling, and events are all managed automatically. Clicking a mark drills through to a Cerb search, and every chart in the family shares that behavior.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-charts.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Charts]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.PieChart&lt;/code&gt; component for pie and donut visualizations. Slices and legend rows share one color scale keyed by label, so the two always match, and hovering shows the value with its percentage share.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Charts]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ScatterChart&lt;/code&gt; component for XY scatterplots with independent series on two continuous axes, including legend support, hover tooltips, and customizable interaction handlers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Charts]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Gauge&lt;/code&gt; component for single-value radial gauges with customizable thresholds that recolor the fill, plus a formatted center value and label.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Charts]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Timeblocks&lt;/code&gt; component for GitHub-style activity heatmaps, with rows as calendar days and columns as hours, hover tooltips, click events, and customizable color scaling.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-timeblocks.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Map]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Map&lt;/code&gt; component for interactive SVG region and point &lt;a href=&quot;/docs/maps/&quot;&gt;maps&lt;/a&gt; with customizable projections, choropleth coloring, points of interest, and pan and zoom. It reads GeoJSON and TopoJSON and does its own decoding, projection, and rendering with no external library – the Web Mercator and AlbersUsa projection math is validated against D3&apos;s equivalents. Projections also pick a sensible default scale now, so choosing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;albersUsa&lt;/code&gt; no longer renders the map too small to read until you find a workable scale by trial and error.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-map.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Sparkchart&lt;/code&gt; component for compact, multi-series categorical charts of bars and lines, with independent scaling per series, tooltips, and event publishing. Bars sharing a stack key stack cumulatively, and lines sharing a scale group share one range, so a min/avg/max band nests instead of each line filling the full height on its own scale.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added stacked bar charts to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Sparkchart&lt;/code&gt; – for instance, counting successes in green and failures in red as proportions of the same bar.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Distbar&lt;/code&gt; component for horizontal stacked bars with segment-based legends and palette support. Zero-valued segments are hidden from the bar rather than rendering as a sliver, and can optionally be omitted from the legend as well.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Legend&lt;/code&gt; component for color-matched keys with dynamic data binding, palette support, and integration with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Distbar&lt;/code&gt;. Swatches render as bars or lines in horizontal or vertical layouts.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI]&lt;/strong&gt; Added shared color palettes and an ordinal color scale to Cerb UI. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ColorScale&lt;/code&gt; assigns colors by hash, so separate components – a sparkchart, a distbar, and a legend – synchronize on the same color for the same series without being wired together.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/QR Code]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.QrCode&lt;/code&gt; component for generating and rendering self-contained, scalable QR codes as SVGs with no external dependencies.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Calendar]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Calendar&lt;/code&gt; component for interactive, multi-view calendars with support for event sources and custom interactions. A switcher toggles between daily, weekly, monthly, and yearly views, multi-day events render as a spanning strip, and clicking a day creates a new event.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cards/Widgets/Calendar]&lt;/strong&gt; Added a configurable &lt;a href=&quot;/docs/dashboards/widgets/calendar/&quot;&gt;&apos;Calendar&apos; card widget&lt;/a&gt; with multi-view displays and linked calendars.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cards/Widgets/Charts]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/dashboards/widgets/chart-kata/&quot;&gt;&apos;Chart: KATA&apos; card widget&lt;/a&gt; type, bringing the full Chart &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt; visualizations to record cards. This was previously only available on workspace widgets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles/Widgets/Charts]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/dashboards/widgets/chart-kata/&quot;&gt;&apos;Chart: KATA&apos; profile widget&lt;/a&gt; type, bringing the full Chart KATA visualizations to record profile tabs. The widget resolves &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record_&lt;/code&gt; placeholders against the profile&apos;s record, renders in light or dark mode per the viewer&apos;s preference, and offers the same dataset and chart KATA autocompletion and live preview testers in its config as the other Chart KATA widgets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Cards]&lt;/strong&gt; Added a &apos;Chart: Metrics Explorer&apos; card widget – an interactive, client-side &lt;a href=&quot;/docs/metrics/&quot;&gt;metric&lt;/a&gt; chart builder for metric and other record cards. Build and live-edit multiple series (metric, aggregate function, dimension filters with is and not, per-series line, bar, or area type, left or right axis, stacking, color, and visibility) over an adjustable range and period, then export the result as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metrics.timeseries&lt;/code&gt; &lt;a href=&quot;/docs/data-queries/&quot;&gt;data query&lt;/a&gt;, an importable &apos;Chart: KATA&apos; widget, or an explorer config.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/metrics-explorer.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Charts]&lt;/strong&gt; Added &lt;a href=&quot;/docs/developers/cerb-ui/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Gantt&lt;/code&gt;&lt;/a&gt;, a chart of named rows of spans across a shared numeric or time axis. A row is a label plus any number of spans, and rows covering the same range overlap on screen. That overlap is the point: a region two rows share is drawn as the place they meet, rather than invented as a third series – which would imply a third kind of thing where there are only two.&lt;/p&gt;

    &lt;p&gt;Spans are half-open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[start, end)&lt;/code&gt;, so a job running 09:00 to 10:00 doesn&apos;t overlap one starting at 10:00. Setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;step&lt;/code&gt; makes the axis discrete units of that size and the span end inclusive, so slots &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1,6]&lt;/code&gt; cover six cells rather than five; it also governs the tick placement, which otherwise falls between units and labels a position that doesn&apos;t exist – on a three-slot pool the generic tick generator offers a slot 1.5. A time axis picks its own tick step, from one second to one week, and aligns from local midnight rather than from the epoch, which lands on the hour only in whole-hour zones and would label every tick at :30 for anyone on a half-hour offset.&lt;/p&gt;

    &lt;p&gt;It&apos;s documented under &lt;strong&gt;Setup » Developers » UI Reference » Gantt&lt;/strong&gt; with three live examples – a discrete stepped axis, a segmented one, and a time axis – and it&apos;s what the new &lt;strong&gt;Setup » Configure » Queues&lt;/strong&gt; page draws the concurrency pool with.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-gantt.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tasks-and-projects&quot;&gt;Tasks and projects&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Daily Task Boards]&lt;/strong&gt; Added a &lt;strong&gt;Daily Task Board&lt;/strong&gt; workspace tab – a personal, day-oriented planning board built on real &lt;a href=&quot;/docs/records/types/task/&quot;&gt;task&lt;/a&gt; records and task projects. Unlike &lt;a href=&quot;/docs/project-boards/&quot;&gt;project boards&lt;/a&gt;, nothing board-specific is stored: every column and day placement is derived from a task&apos;s status, active flag, importance, and completion or wake dates, so the board and the underlying tasks can never disagree.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/daily-task-board.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;

    &lt;p&gt;The board is a horizontal timeline of days, newest first. Today is fully interactive with TODO, In Progress, and Done columns, while the previous six days are a read-only completion log. A board-spanning Stash holds waiting tasks grouped by wake date, and the scheduler revives a stashed task into today&apos;s TODO once its &quot;stashed until&quot; date passes.&lt;/p&gt;

    &lt;p&gt;Cards support inline title editing, drag-and-drop between columns and days, manual ranking in the TODO lane by importance, quick-add, delete, and moving a task to another project. A multi-select column action bulk-moves tasks between columns or projects, and a card&apos;s meta strip shows the assignee avatar with an &quot;assign to me&quot; claim. &apos;Jump to Date&apos; renders any off-window day on demand, with month pips marking which days carry completed or waiting tasks.&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;Quick Triage&lt;/strong&gt; deals a lane out as a stack of cards and sorts it one keystroke at a time: raise or lower a task&apos;s importance by one – or by five holding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Shift&lt;/code&gt; – move it to another column, stash it, schedule it for a date typed in plain language, skip it, or delete it. A progress meter tracks what&apos;s left, and a shuffle re-deals the remainder. It&apos;s offered on the TODO column and the Stash, the two places where a pile actually needs sorting.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/quick-triage.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;

    &lt;p&gt;Each board has a shared configuration – which task projects appear, their accent colors, and their order – stored on the tab, while every worker overlays a personal selection, order, and &quot;focus my tasks&quot; preference. A task&apos;s permissions derive from its project, and archived or unreadable projects are dropped from the board gracefully.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Tasks/Projects]&lt;/strong&gt; Added a &apos;Task Project&apos; record type for grouping related tasks together and sharing ownership. Tasks gain a project and an active flag, and a project&apos;s permissions carry through to the tasks inside it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Tasks/Projects]&lt;/strong&gt; In task project worklists, added a &apos;Tasks&apos; distribution bar column showing how a project&apos;s tasks are split between done, stashed, todo, and in-progress – so a project that has quietly stalled is visible without opening it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Tasks/Projects]&lt;/strong&gt; In task project worklists, added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tasks:&lt;/code&gt; deep search filter. This matches any filter on the tasks within a project, so a project can be found by the properties of its tasks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Tasks]&lt;/strong&gt; The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt; field on &lt;a href=&quot;/docs/records/types/task/&quot;&gt;task&lt;/a&gt; records may now contain 4-byte emoji characters.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspaces/Packages]&lt;/strong&gt; Added a &quot;Daily Task Board&quot; package to the workspace tab library. It sits alongside Dashboard and World Clocks when you add a tab to a &lt;a href=&quot;/docs/workspaces/&quot;&gt;workspace&lt;/a&gt; page. The package prompts for a tab name and, optionally, the &lt;a href=&quot;/docs/records/types/task_project/&quot;&gt;task projects&lt;/a&gt; to show – pick them there and the board comes up ready to use, with an accent color assigned to each. Skip the prompt and the board opens to its setup note pointing at the Projects picker, which is also where you change the selection, the order, and the colors later.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;setup-and-developers&quot;&gt;Setup and developers&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/oXRxQNJAu6Y&quot; title=&quot;A tour of the redesigned Setup pages in Cerb 12.0&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Records]&lt;/strong&gt; In &lt;a href=&quot;/docs/setup/&quot;&gt;Setup » Records&lt;/a&gt; there is now a full reference for every record type and field, including their API keys and search filters. Customization through custom records and custom fields is surfaced here rather than buried in the global &apos;Search&apos; menu. The old &apos;Custom Fields&apos; and &apos;Snippets&apos; items were removed from the &apos;Records&apos; menu since both are better reached elsewhere.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-records-reference.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Records]&lt;/strong&gt; A custom &quot;Record Link&quot; field now names the record type it points at, and a &quot;Picklist&quot; lists its valid values. The schema reported a custom field&apos;s label and type, and for those two types that isn&apos;t enough to use the field: &quot;Record Link&quot; tells you the shape but not what it points at, and &quot;Picklist&quot; tells you there&apos;s a fixed set of values without saying what they are – so anyone reading the schema to write a search query or set a field, a person or an agent, had to go dig through the field&apos;s own settings, or guess. A Record Link now reads &quot;Links to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ticket&lt;/code&gt; records&quot;, naming the target by its alias, which is the same name a search query or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.create&lt;/code&gt; would use, and a Picklist reads &quot;One of:&quot; followed by its values, capped with a count of what was left off when the list is very long. Both show in &lt;strong&gt;Setup » Records&lt;/strong&gt; and in an agent&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb records&lt;/code&gt; output.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Automations]&lt;/strong&gt; A new &lt;strong&gt;Setup » Developers » Automation Events&lt;/strong&gt; overview shows the sequence of every event flow – &quot;On new inbound mail&quot;, for instance – as a node graph of each &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; event and legacy behavior event triggered along the way. Double-clicking an event, listener, automation, or bot behavior opens it for editing. This makes it far easier to answer &quot;what actually runs when mail arrives, and in what order?&quot;&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-automation-events.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Toolbars]&lt;/strong&gt; Added an overview of every customizable &lt;a href=&quot;/docs/toolbars/&quot;&gt;toolbar&lt;/a&gt; in &lt;strong&gt;Setup » Developers » Toolbars&lt;/strong&gt;, listing sections by toolbar and by managing &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt;. Clicking a toolbar item opens its associated automation or behavior editor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI/Developers]&lt;/strong&gt; Added a &apos;UI Reference&apos; section to &lt;strong&gt;Setup » Developers&lt;/strong&gt; showcasing the full &lt;a href=&quot;/docs/developers/cerb-ui/&quot;&gt;Cerb UI&lt;/a&gt; component library with interactive examples, variants, code snippets, and documentation, navigable from a sidebar.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/cerb-ui-reference.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; Added an &lt;a href=&quot;/docs/setup/developers/icon-builder/&quot;&gt;Icon Builder&lt;/a&gt; for authoring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb-icons&lt;/code&gt; glyphs. Draw the SVG geometry and see the glyph rendered everywhere it appears in the interface, so a new icon can be checked in context before it ships. It has an agent pane too, so an agent can look up how a comparable icon is drawn and hand back a new one.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/icon-builder.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; Added a visual &lt;a href=&quot;/docs/setup/developers/sheet-builder/&quot;&gt;Sheet Builder&lt;/a&gt;. &lt;a href=&quot;/docs/sheets/&quot;&gt;Sheet&lt;/a&gt; layouts and columns are built against a sample dataset with a live preview, instead of writing the KATA blind and reloading to see the result. It&apos;s also available from the Form Builder&apos;s sheet element, where it loads the existing sheet and writes your changes back.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/sheet-builder.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; Added an &lt;a href=&quot;/docs/setup/developers/agent-filesystem-terminal/&quot;&gt;Agent Filesystem Terminal&lt;/a&gt; for browsing and editing agent volumes with the same commands an agent uses, so what a worker sees and what an agent sees can&apos;t drift apart.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; Added a Schema KATA export to the Database Schema page. Previously the page could tell you the database had drifted, but only as a table of columns to read by eye – getting the schema back out meant transcribing it. The export opens the live schema as copyable text, showing the differences alone: tables the reference doesn&apos;t have appear whole, and tables that merely drifted are narrowed to just the changed columns, so what you paste is the delta. Toggling it off gives every table.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; Reworked the LLM Agent Transcripts browser. Transcripts are listed in a sidebar with Active and Archived filtering and per-transcript actions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; An LLM transcript can be forked onto another provider, or switched to one mid-conversation, so the same conversation can be replayed on a different model for comparison.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers]&lt;/strong&gt; An LLM agent transcript now shows the &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;filesystem volumes&lt;/a&gt; its session mounted. Until now a transcript told you the agent had a filesystem tool but never which volumes it reached – the Tools panel listed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agent_terminal&lt;/code&gt; and that was the whole story, so two sessions with completely different volumes read identically. A Filesystem Mounts panel now sits directly below Tools, naming each mountpoint, the volume behind it with a link to the record, that volume&apos;s file count and size, and whether the agent had read-only or read-write access. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; is listed too, since an agent reads and writes it like any other mount – as per-run scratch rather than a stored volume, it&apos;s the one row with no record to link and no file count. A mount whose volume has since been deleted or disabled is called out as Missing or Disabled rather than left off the list: those silently don&apos;t mount at run time, so a session can have had fewer volumes than its automation asked for, and this panel is the only place that says so.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/agent-transcript-mounts.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Developers/Icons]&lt;/strong&gt; In the &apos;Icon&apos; component of &lt;strong&gt;Setup » Developers » UI Reference&lt;/strong&gt;, icons can be filtered by name, a &apos;Show labels&apos; toggle switches between a compact grid and named icons, and clicking an icon copies its HTML fragment to the clipboard.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Scheduler/Setup]&lt;/strong&gt; Completely redesigned the &lt;a href=&quot;/docs/setup/configure/scheduler/&quot;&gt;Setup » Configure » Scheduler&lt;/a&gt; page with Cerb UI components. Deployment options are separated into &apos;Development&apos; and &apos;Production&apos;: the Development section has an &apos;Auto-Run&apos; option that runs jobs entirely in the browser, with a countdown ring showing the next interval, and the Production section carries an example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/cron&lt;/code&gt; request using &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;service tokens&lt;/a&gt;. Per-job metrics for runs and duration are displayed with a range toggle, and the &apos;edit&apos; and &apos;run now&apos; actions open in a popup.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-scheduler.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Storage]&lt;/strong&gt; Redesigned &lt;strong&gt;Setup » Storage&lt;/strong&gt; to better visualize storage lifecycles and usage. The active and archive storage profile for each storage schema are clearly marked, and a distribution bar makes it easy to compare the number or size of objects stored.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-storage.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Storage]&lt;/strong&gt; In &lt;strong&gt;Setup » Storage&lt;/strong&gt;, a new button starts a migration of objects between storage profiles. Previously objects only moved from the active to the archive profile via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cron.storage&lt;/code&gt; scheduler job, with no way to consolidate fragmented storage or to move long-term storage such as S3 back to local. Migrations run as parallel background &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue jobs&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Avatars]&lt;/strong&gt; Removed the avatar configuration page in Setup. It previously toggled between default monograms and silhouettes for contact and worker records; monograms with locked colors are now always used, since they can be generated in the browser.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Storage]&lt;/strong&gt; In &lt;strong&gt;Setup » Storage&lt;/strong&gt;, removed the &apos;Objects&apos; page. It was exactly the same as &lt;strong&gt;Search » Attachments&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Records]&lt;/strong&gt; In &lt;strong&gt;Setup » Records&lt;/strong&gt;, removed the &apos;Snippets&apos; page. It was exactly the same as &lt;strong&gt;Search » Snippets&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/AI]&lt;/strong&gt; Setup has a new &lt;strong&gt;AI&lt;/strong&gt; menu gathering the records an installation&apos;s AI is built from: &lt;strong&gt;Agents&lt;/strong&gt;, &lt;strong&gt;Models&lt;/strong&gt;, &lt;strong&gt;Files&lt;/strong&gt;, &lt;strong&gt;Filesystems&lt;/strong&gt;, &lt;strong&gt;Tools&lt;/strong&gt;, &lt;strong&gt;Surfaces&lt;/strong&gt;, and &lt;strong&gt;Transcripts&lt;/strong&gt;. The first six open as tabs on a single page, so moving between the &lt;a href=&quot;/docs/agents/&quot;&gt;agents&lt;/a&gt; you&apos;ve defined and the &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;models&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/agent_file/&quot;&gt;files&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;filesystems&lt;/a&gt;, and &lt;a href=&quot;/docs/records/types/agent_tool/&quot;&gt;tools&lt;/a&gt; they&apos;re composed from doesn&apos;t mean leaving the page. &lt;strong&gt;Transcripts&lt;/strong&gt; is the seventh menu entry but its own page, not a tab.&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;Agents&lt;/strong&gt; is a &lt;a href=&quot;/docs/records/types/worker/&quot;&gt;worker&lt;/a&gt; worklist locked to AI accounts, reading its filter from the same manifest the global search menu&apos;s &lt;strong&gt;Agents&lt;/strong&gt; entry uses, so the two can&apos;t drift into meaning different subsets.&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;Surfaces&lt;/strong&gt; is a reference rather than a worklist – one card per place an agent can run, listing what that surface hands an agent: the tools it contributes and their parameters, any values pinned on a tool that the model never sees and can&apos;t override, the reading it points the agent at – and only when the volume holding it is actually mounted – and the orientation prompt it supplies. It reads from the surface catalog itself, so it&apos;s never a second, hand-written description of the same facts.&lt;/p&gt;

    &lt;p&gt;The tab set remembers where you left it, so it reopens on the tab you were last using rather than back at &lt;strong&gt;Agents&lt;/strong&gt; – which is the first tab, not a home the page returns to. The page is a tab set rather than a row of menu entries because AI settings will get a &lt;strong&gt;Configure&lt;/strong&gt; tab in front of these when there are any.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-ai.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;worklists&quot;&gt;Worklists&lt;/h3&gt;

&lt;p class=&quot;youtube-video-container&quot;&gt;&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/cWF2lkmnAYU&quot; title=&quot;Adding sparkline trend columns to Cerb worklists&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/UX]&lt;/strong&gt; When customizing a &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt;, configuring which columns are visible has been drastically improved. A searchable menu of available fields is displayed, segmented by custom fieldset, and selecting a field dims it in the menu but leaves it in place so you keep your bearings. Icon type hints give a visual cue for each field&apos;s data type, and the selected fields sort in a single column. Previously every available field was displayed in one giant grid and reordering was unintuitive.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/worklist-columns-config.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Sparklines]&lt;/strong&gt; Added generic &apos;Sparklines&apos; and &apos;Distbar&apos; columns to worklists, along with parameterized &lt;a href=&quot;/docs/metrics/&quot;&gt;metrics&lt;/a&gt; filters. Sparkline columns show a mini-chart of recent activity per row with a 2h/1d/30d range toggle in the column header, and load asynchronously per page only when the column is visible, so they cost nothing on worklists where they aren&apos;t shown. Because the underlying metrics are queryable, each one also brings a matching quick search filter that accepts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;since:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;until:&lt;/code&gt; – the sections below list what each record type exposes.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/worklist-sparklines.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Automations]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column to &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; worklists showing runs, errors, and duration, plus a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter backed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.automation.invocations&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.automation.duration&lt;/code&gt; metrics. For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:(runs:&amp;gt;0 since:today)&lt;/code&gt; returns automations that ran at least once today, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:(runs:&amp;gt;1000)&lt;/code&gt; returns those that have run more than a thousand times.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Automations/Events]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to automation event worklists, using the same runs, errors, and duration series – which makes it easy to spot an event that started failing or slowed down.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Bots/Behaviors]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to bot behavior worklists, showing runs and duration from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.behavior.invocations&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.behavior.duration&lt;/code&gt; metrics.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Mailboxes]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to mailbox worklists, showing messages received and protocol errors. For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:(errors:&amp;gt;0)&lt;/code&gt; returns mailboxes that have ever had an error, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:(received:&amp;gt;0 since:today)&lt;/code&gt; returns those that pulled mail today.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Mail Routing Rules]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to mail routing rule worklists, which makes it obvious at a glance which rules are actually matching mail and which have gone stale.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Mail Transports]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to mail transport worklists, showing deliveries and failures.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Queues]&lt;/strong&gt; Added an &apos;Activity&apos; sparklines column and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;activity:&lt;/code&gt; quick search filter to &lt;a href=&quot;/docs/queues/&quot;&gt;queue&lt;/a&gt; worklists, showing done, failed, and open message counts so a backing-up queue is visible without opening it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Search Index]&lt;/strong&gt; Added a &apos;Records&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;records:&lt;/code&gt; quick search filter to &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; worklists, tracking indexed record counts over time.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Service Tokens]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;service token&lt;/a&gt; worklists, tracking authentications – which surfaces both unused tokens and unexpected spikes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Snippets]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to &lt;a href=&quot;/docs/records/types/snippet/&quot;&gt;snippet&lt;/a&gt; worklists, tracking how often each snippet is used.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Webhooks]&lt;/strong&gt; Added a &apos;Usage&apos; sparklines column and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usage:&lt;/code&gt; quick search filter to &lt;a href=&quot;/docs/records/types/webhook_listener/&quot;&gt;webhook listener&lt;/a&gt; worklists, tracking invocations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[Worklists/Metrics]&lt;/strong&gt; Added a &apos;Dataset&apos; sparklines column to &lt;a href=&quot;/docs/records/types/metric/&quot;&gt;metric&lt;/a&gt; worklists displaying min, max, average, sum, and count. It adapts automatically to counters versus gauges, so each metric is charted the way it&apos;s meant to be read.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Import]&lt;/strong&gt; Records can be imported into worklists using JSONL files. Previously this only supported CSV.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Import/UX]&lt;/strong&gt; When importing CSV/JSONL files into &lt;a href=&quot;/docs/worklists/&quot;&gt;worklists&lt;/a&gt;, the import field mapping is now saved as a per-worker preference for that record type, file format, and column schema. This saves a lot of tedious remapping for routine file imports.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Search]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;comments:&lt;/code&gt; worklist filter for every record type that supports comments. Previously this was only available on about a dozen of the nearly 80 record types. The filter is now backed by the new &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; record type.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Sessions/Subtotals]&lt;/strong&gt; Added subtotals to the user sessions worklist: worker, ip address, and user agent.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Bulk/Comments]&lt;/strong&gt; Added bulk commenting to the worklist &apos;Bulk Update&apos; popup for every record type that supports comments (tickets, tasks, organizations, opportunities, time tracking, domains, servers, calls). [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1602&quot;&gt;#1602&lt;/a&gt;]&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/bulk-comment.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[Worklists/Comments]&lt;/strong&gt; Added bulk delete to comment worklists. Admins can delete any comment; non-admins are limited to their own via per-record ACL. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/857&quot;&gt;#857&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;metrics&quot;&gt;Metrics&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics]&lt;/strong&gt; A &lt;a href=&quot;/docs/metrics/#retention&quot;&gt;retention policy&lt;/a&gt; can now be configured per metric. This applies to the 1-day sample aggregations, which are retained forever by default. The 5-min samples are still retained for 24 hours, and 1-hour samples for 2 weeks. This is particularly useful for metrics with high dimensionality and low long-term value, like rate-limiters. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1554&quot;&gt;#1554&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data Queries/Metrics]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metrics.subtotals&lt;/code&gt; &lt;a href=&quot;/docs/data-queries/&quot;&gt;data query&lt;/a&gt; type for flat metric subtotals read directly from samples. This is the inverse projection of &lt;a href=&quot;/docs/data-queries/metrics/timeseries/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metrics.timeseries&lt;/code&gt;&lt;/a&gt; – instead of values over time it returns the raw dimension values, which can then be composed into other queries such as subquery worklist filters.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data Queries/Metrics]&lt;/strong&gt; In &lt;a href=&quot;/docs/data-queries/metrics/timeseries/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metrics.timeseries&lt;/code&gt;&lt;/a&gt; data queries, added support for negating dimension filters – for instance, on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.tickets.open&lt;/code&gt; metric, every ticket sample where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group_id != 1&lt;/code&gt;. This makes proportional stacked bar charts straightforward: one dimension versus all the others.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data Queries/Tickets]&lt;/strong&gt; In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worklist.subtotals&lt;/code&gt; data queries, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;of:ticket&lt;/code&gt; now supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;by:sender.first&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;by:sender.last&lt;/code&gt;. Autocompletion had been suggesting these keys, but using one returned an &quot;Unknown by: field&quot; error.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Mailboxes]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.mail.mailbox.received&lt;/code&gt; counter metric tracking downloaded messages per &lt;a href=&quot;/docs/records/types/mailbox/&quot;&gt;mailbox&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Mailboxes]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.mail.mailbox.errors&lt;/code&gt; counter metric tracking protocol errors per &lt;a href=&quot;/docs/records/types/mailbox/&quot;&gt;mailbox&lt;/a&gt;, with a status dimension that breaks errors down by status code – invalid authentication, for instance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[AI/Agents/Metrics]&lt;/strong&gt; Every &lt;a href=&quot;/docs/agents/&quot;&gt;agent&lt;/a&gt; turn is now recorded as &lt;a href=&quot;/docs/metrics/&quot;&gt;metrics&lt;/a&gt;, so token spend, latency, and provider failures can be charted from a &lt;a href=&quot;/docs/dashboards/&quot;&gt;dashboard widget&lt;/a&gt; or filtered on in a &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt; like any other metric.&lt;/p&gt;

    &lt;p&gt;Six counters are written. Four count tokens – &lt;a href=&quot;/docs/metrics/cerb.agent.model.tokens.input/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.agent.model.tokens.input&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;/docs/metrics/cerb.agent.model.tokens.output/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.output&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;/docs/metrics/cerb.agent.model.tokens.cache_read/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cache_read&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;/docs/metrics/cerb.agent.model.tokens.cache_write/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cache_write&lt;/code&gt;&lt;/a&gt; – dimensioned by the &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; that ran the turn, the AI worker it ran as, and the worker it ran for, which is what answers how much each model costs, per model, per agent, or per person. The other two, &lt;a href=&quot;/docs/metrics/cerb.agent.model.turns/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.agent.model.turns&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;/docs/metrics/cerb.agent.model.turns.duration/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.agent.model.turns.duration&lt;/code&gt;&lt;/a&gt;, count turns and accumulate their duration in milliseconds, dimensioned by model, agent, and the provider&apos;s &lt;strong&gt;response status&lt;/strong&gt; – so rate limits (429), overloaded providers (529), and endpoints that never answered at all (recorded as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; – a DNS failure, a refused connection, a timeout) form their own series beside the successful turns, and dividing duration by turns gives an average response time per model.&lt;/p&gt;

    &lt;p&gt;Duration measures the provider request itself and not time spent waiting in the &lt;a href=&quot;/docs/queues/&quot;&gt;queue&lt;/a&gt;, so a busy queue never reads as a slow model. Interactive and background turns are both counted, as is the compaction pass that summarizes a long conversation, so the totals reconcile with a transcript&apos;s own token accounting. Reasoning tokens aren&apos;t counted separately, because providers report them as part of the output total and a second series would double-count any bare sum.&lt;/p&gt;

    &lt;p&gt;Two things go uncounted on purpose: a turn that failed still records its status and latency but not its tokens, since a failed request&apos;s usage never comes back; and &lt;a href=&quot;/docs/automations/commands/llm.chat/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.chat:&lt;/code&gt;&lt;/a&gt; and the model connection test have no agent behind them, so they&apos;d have nothing to dimension by. Samples are kept indefinitely unless you set a &lt;a href=&quot;/docs/metrics/#retention&quot;&gt;retention period&lt;/a&gt; on the metric.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;workspaces&quot;&gt;Workspaces&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspaces]&lt;/strong&gt; Added auto-refresh to worklist and widget tabs. A &lt;a href=&quot;/docs/dashboards/&quot;&gt;dashboard&lt;/a&gt; left open previously showed data from whenever it was last loaded, with nothing indicating how stale it had become. Switch auto-refresh on for a tab and a countdown ring appears showing when the next refresh is due; click the ring to choose an interval of one, five, or fifteen minutes. Worklist and widget tabs offer it; other tab types don&apos;t. It stays on for as long as you&apos;re on the tab rather than being remembered as a preference, so a tab always opens with it off.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/tab-auto-refresh.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;

    &lt;p&gt;An auto-refreshing page that reloads while you&apos;re reading it is worse than a stale one, so the countdown holds rather than drains whenever a refresh would interrupt: while the browser tab is in the background, while a popup is open in front of you, and while the countdown ring itself is scrolled out of view. That last case matters most – it means a refresh only ever lands at the top-of-tab glance view, and never yanks you upward mid-read further down the page. A minimized or docked popup doesn&apos;t count as interrupting, so a parked peek won&apos;t freeze the timer indefinitely. When the countdown resumes it picks up where it held plus a short grace period, so dismissing a dialog or returning to the tab never triggers a refresh the same instant.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Widgets/Worklists]&lt;/strong&gt; On profiles and &lt;a href=&quot;/docs/workspaces/&quot;&gt;workspaces&lt;/a&gt;, &apos;Worklist&apos; widget configuration simplifies selecting columns from custom fieldsets. Fieldset fields are split into their own sections with an all/none toggle, instead of one long undifferentiated list.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspaces/Worklists]&lt;/strong&gt; When a workspace widget&apos;s configuration changes, its worker-level cache is now cleared. This keeps &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt;-managed worklists from diverging – previously a worker could keep seeing the old columns or query after the managing workflow had updated the widget.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workflows]&lt;/strong&gt; When a &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt; manages a record, editing that record from the interface now warns you first. This applies to automations, automation event listeners, custom fields, custom fieldsets, custom records, mail routing rules, and toolbar sections – the record types most likely to be silently overwritten the next time the workflow synchronizes.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/workflow-managed-record.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workflows/UX]&lt;/strong&gt; Revamped the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.quickstart&lt;/code&gt; onboarding &lt;a href=&quot;/docs/workflows/&quot;&gt;workflow&lt;/a&gt; for 12.0, replacing the checklist approach with a guided setup tour, streamlining step navigation, and improving contextual guidance. The &apos;Guided Setup&apos; interaction is now reachable from the global menu.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workflows/Tutorial/UX]&lt;/strong&gt; Updated the built-in tutorial workflow to cover new 12.0 features. Each section gained an icon as a visual cue, the heavy SVG illustrations were removed from a few sections, and the worklist header switched to a neutral color that reads well in both light and dark mode.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workflows/Config]&lt;/strong&gt; &lt;a href=&quot;/docs/workflows/&quot;&gt;Workflow&lt;/a&gt; templates can now prompt for a search query in their configuration, with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query/&amp;lt;name&amp;gt;:&lt;/code&gt; field that takes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record_type:&lt;/code&gt; and autocompletes that record type&apos;s query filter syntax as you fill it in. A value an admin supplies is then written in Cerb&apos;s own search vocabulary rather than as free text, which is how a workflow sets a boundary – scoping which &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent models&lt;/a&gt; an agent workflow may use, for instance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workflows/Tutorial]&lt;/strong&gt; Added an &apos;AI &amp;amp; Agents&apos; tab to the built-in tutorial &lt;a href=&quot;/docs/workspaces/&quot;&gt;workspace&lt;/a&gt;. The tutorial workspace ships with every installation as a guided tour of what Cerb does, and AI agents are the largest addition in 12.0, so they get a section of their own rather than a paragraph inside Automations. It sits second, right after the welcome page, and starts from the decision everything else follows from: an AI agent is an ordinary &lt;a href=&quot;/docs/workers/&quot;&gt;worker&lt;/a&gt; record with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_ai&lt;/code&gt; flag, so it owns tickets, is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mentioned&lt;/code&gt;, and joins groups like anyone else.&lt;/p&gt;

    &lt;p&gt;From there it walks the pieces behind one – &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; records and where their credentials come from, the capabilities and ratings that let an &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; describe the model it needs instead of naming one, the model pools that resolve a search rather than a hand-maintained list, the &lt;a href=&quot;/docs/automations/commands/llm.chat/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.chat:&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;/docs/automations/commands/llm.agent/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;/docs/automations/commands/llm.router/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.router:&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;/docs/automations/commands/llm.embed/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.embed:&lt;/code&gt;&lt;/a&gt; commands, &lt;a href=&quot;/docs/records/types/agent_filesystem/&quot;&gt;agent filesystems&lt;/a&gt; and how an automation mounts them, the file commands an agent and a worker both use, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb&lt;/code&gt; command line an agent asks Cerb about itself with, the volumes that ship with Cerb, where an agent chat can open, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agentPrompt&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llmTranscript&lt;/code&gt; form elements that make one visible, and what happens to a conversation that outgrows its context window. Worklists of your own agent models, filesystems, and AI workers sit alongside the prose, so the tab reads against a real installation rather than an example.&lt;/p&gt;

    &lt;p&gt;The rest of the workspace is brought up to date for 12.0 as well: Search covers facets, Worklists the redesigned column picker and remembered import mappings, Workspaces the dashboard auto-refresh, Automations the starter templates, simulated initial state, generated policies, form builder, and batch record updates, and Queues the retry policy and claim window. The welcome page gains a &apos;Developer Tools&apos; widget listing what lives under &lt;strong&gt;Setup » Configure » Developers&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;service-tokens&quot;&gt;Service tokens&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Service Tokens]&lt;/strong&gt; Added &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;&apos;service tokens&apos;&lt;/a&gt; for anonymous privileged endpoint access (/cron, /debug, /update). This deprecates IP-based allowlists. A service token can be included in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization: Bearer&lt;/code&gt; HTTP header or an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_authorization&lt;/code&gt; HTTP POST parameter; for instance, from a cronjob or monitoring tool. Tokens can be restricted with scopes to specific endpoints. When viewing a protected endpoint in the browser, a token can be entered to continue. A master service token can be added to the config file using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_SERVICE_TOKEN&lt;/code&gt;; which is particularly useful for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/update&lt;/code&gt; since logins would be blocked until the update has finished. Service tokens are managed from &lt;a href=&quot;/docs/setup/configure/security/&quot;&gt;Setup » Configure » Security&lt;/a&gt;.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/service-tokens.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Service Tokens/Metrics]&lt;/strong&gt; Added a &lt;a href=&quot;/docs/metrics/cerb.service.token.uses/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.service.token.uses&lt;/code&gt;&lt;/a&gt; metric counter for tracking service token authentications.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Service Tokens]&lt;/strong&gt; When the &lt;a href=&quot;/docs/config-file/#common-settings&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_SECURITY_ALLOW_ADMIN_SESSION_TOKEN&lt;/code&gt;&lt;/a&gt; config option is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; (default), existing admin sessions can be used to authenticate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/update&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/cron&lt;/code&gt;. Disabling the option always requires a &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;service token&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;scheduler&quot;&gt;Scheduler&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Scheduler/Background]&lt;/strong&gt; Added a new &lt;a href=&quot;/docs/queues/#background-queue-scheduler&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Background Queue&lt;/code&gt;&lt;/a&gt; scheduler job to process events asynchronously.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Scheduler/Parallel]&lt;/strong&gt; &lt;a href=&quot;/docs/setup/configure/scheduler/&quot;&gt;Scheduler&lt;/a&gt; jobs can now be flagged as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parallel&lt;/code&gt; in their extension manifest (e.g. the &lt;a href=&quot;/docs/queues/#background-queue-scheduler&quot;&gt;Background Queue&lt;/a&gt;). These jobs limit by concurrency rather than locking during operation, which enables more real-time background functionality compared to traditional cron jobs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Scheduler]&lt;/strong&gt; Added a new metric &lt;a href=&quot;/docs/metrics/cerb.scheduler.invocations/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.scheduler.invocations&lt;/code&gt;&lt;/a&gt; to count &lt;a href=&quot;/docs/setup/configure/scheduler/&quot;&gt;scheduler&lt;/a&gt; runs by job.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Metrics/Scheduler]&lt;/strong&gt; Added a new metric &lt;a href=&quot;/docs/metrics/cerb.scheduler.duration/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.scheduler.duration&lt;/code&gt;&lt;/a&gt; to track &lt;a href=&quot;/docs/setup/configure/scheduler/&quot;&gt;scheduler&lt;/a&gt; execution duration by job.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;security&quot;&gt;Security&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Workers/MFA]&lt;/strong&gt; Added backup codes to worker accounts when multifactor authentication (MFA) is enabled.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/mfa-backup-codes.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;plugins&quot;&gt;Plugins&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Plugins/UX]&lt;/strong&gt; Revamped plugin configuration in &lt;a href=&quot;/docs/plugins/&quot;&gt;Setup » Configure » Plugins&lt;/a&gt;. Plugins can now be enabled or disabled in a single click directly from the worklist. Separate worklists are provided for modern features, legacy features, and third-party plugins, and the row icons visually distinguish each category (disabled plugins render in grayscale via CSS rather than the previous dated bitmap decoration, which also applies to disabled worker profile images). The &apos;Link&apos; column is shown by default for quick access to per-plugin documentation, plugins are sorted alphabetically, and plugin names are rendered at a larger font size. A tip points to &lt;a href=&quot;/docs/workflows/&quot;&gt;workflows&lt;/a&gt; as the preferred path for most user-level extensibility.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/setup-plugins.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;miscellaneous&quot;&gt;Miscellaneous&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Storage/Profiles/S3]&lt;/strong&gt; The &apos;S3&apos; storage profile now accepts a host with an optional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://&lt;/code&gt; protocol and a non-standard port. This makes it possible to use S3-compatible object storage like &lt;a href=&quot;https://min.io/&quot;&gt;MinIO&lt;/a&gt; (in self-hosted, local network, or development environments), Google Cloud Storage, and others rather than requiring Amazon S3.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/s3-compatible-storage.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Connected Accounts/AWS]&lt;/strong&gt; In &apos;Amazon Web Services&apos; connected accounts, added an &quot;Allow requests to non-AWS endpoints&quot; option. This permits the credentials to be used with AWS/S3-compatible services like Google Cloud Storage or MinIO. By default, credentials are restricted to AWS services.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Notifications/UX]&lt;/strong&gt; The unread notifications bell in the top right now occasionally plays a silent &apos;ring&apos; animation to draw attention to waiting notifications.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Workers]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;created_at&lt;/code&gt; field to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worker&lt;/code&gt; records.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Groups/Activity Log]&lt;/strong&gt; The activity log now records when group members are added or removed. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/246&quot;&gt;#246&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workers/Activity Log]&lt;/strong&gt; The activity log now records when workers are activated or deactivated. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/824&quot;&gt;#824&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Sheets/Code/KATA]&lt;/strong&gt; Added syntax highlighting for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kata&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code&lt;/code&gt; columns of &lt;a href=&quot;/docs/sheets/&quot;&gt;sheets&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Installer/UX]&lt;/strong&gt; Added default card and profile widgets to several record types that previously lacked them: &lt;a href=&quot;/docs/records/types/automation/&quot;&gt;automation&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/automation_event/&quot;&gt;automation event&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/automation_event_listener/&quot;&gt;automation event listener&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/automation_timer/&quot;&gt;automation timer&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/gpg_private_key/&quot;&gt;gpg_private_key&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/gpg_public_key/&quot;&gt;gpg_public_key&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/queue/&quot;&gt;queue&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/resource/&quot;&gt;resource&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;service token&lt;/a&gt;, &lt;a href=&quot;/docs/records/types/toolbar/&quot;&gt;toolbar&lt;/a&gt;, and &lt;a href=&quot;/docs/records/types/toolbar_section/&quot;&gt;toolbar section&lt;/a&gt; records.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Icons]&lt;/strong&gt; Added a default icon to every record type, displayed on card popups and profile pages so a record&apos;s type is identifiable at a glance even when it has no profile image.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Widgets/Icons]&lt;/strong&gt; Added default icons to all card, profile, and workspace widget types. This gives a visual cue in configuration menus and on &lt;a href=&quot;/docs/dashboards/&quot;&gt;dashboards&lt;/a&gt;, and the icon can be overridden per widget.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Added icons to package library records. Packages now show a glyph in the library and in choosers instead of a generic placeholder.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Autocomplete]&lt;/strong&gt; Implemented autocompletion when searching many more record types: connected accounts, custom fieldsets, email signatures, groups, mail templates, mail transports, metrics, organizations, PGP private keys, project boards, queues, roles, task projects, time tracking activities, and workspace pages. Previously most of these required typing an exact match or opening a chooser popup.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Comments/Notifications]&lt;/strong&gt; When replying to a comment, the original author&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@mention&lt;/code&gt; is prefilled automatically, so a reply notifies the person you&apos;re replying to without having to remember to tag them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Bots/Behaviors]&lt;/strong&gt; Legacy bot behaviors now track a change history the way &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt; do. From a behavior tree, click the event and choose &apos;Edit History&apos; to compare any two revisions in the diff viewer.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data/Records]&lt;/strong&gt; Added an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;only_custom&lt;/code&gt; filter to complement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exclude_custom&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.types&lt;/code&gt; &lt;a href=&quot;/docs/data-queries/&quot;&gt;data queries&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Connected Services/UI]&lt;/strong&gt; Added profile images to &lt;a href=&quot;/docs/records/types/connected_service/&quot;&gt;connected service&lt;/a&gt; records. The image is displayed on the login form&apos;s SSO buttons and in the connected service profile and worklists.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/sso-profile-images.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Connected Services/Packages]&lt;/strong&gt; Added a &quot;Microsoft Entra ID&quot; package that sets up the OAuth2 &lt;a href=&quot;/docs/records/types/connected_service/&quot;&gt;connected service&lt;/a&gt; Microsoft 365 mailboxes need for SMTP, POP3, and IMAP. Microsoft has been retiring legacy passwords for Office 365 mail, and building that service by hand meant knowing the Entra authorize and token URLs, remembering to include your directory ID in both, and getting the scopes right. Choose the package from the library when adding a connected service and enter the client ID, client secret, and directory ID from your app registration; the scope is prefilled with the recommended set for mail, including the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;offline_access&lt;/code&gt; scope that lets Cerb refresh the access token every hour. The package instructions cover the two most common setup mistakes: a callback URL in Entra that doesn&apos;t match Cerb exactly, and client secrets quietly expiring after six months.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Connected Services/Packages]&lt;/strong&gt; Added a &quot;Microsoft Foundry&quot; package that sets up an API key &lt;a href=&quot;/docs/records/types/connected_account/&quot;&gt;connected account&lt;/a&gt; for Foundry or Azure OpenAI in one step, rather than creating a connected service with the right token provider and then an account to hold the key. Paste a key from your resource&apos;s Keys and Endpoint page and give the account an alias. The instructions cover the part that trips people up afterward: when you add an &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt;, the endpoint is your resource&apos;s OpenAI base URL and the model is your deployment name rather than the underlying model name.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Knowledgebase/Worklists]&lt;/strong&gt; &lt;a href=&quot;/docs/records/types/kb_article/&quot;&gt;Knowledgebase article&lt;/a&gt; worklists now support bulk update, so a batch of articles can be recategorized or edited in one action rather than one at a time.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Workers]&lt;/strong&gt; On &lt;a href=&quot;/docs/records/types/worker/&quot;&gt;worker&lt;/a&gt; editors, &apos;Save &amp;amp; Continue&apos; saves without closing the editor, so a run of small adjustments doesn&apos;t cost your place in the tab each time. This makes it much easier to tweak an agent while it&apos;s running.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Packages/Library]&lt;/strong&gt; A &lt;a href=&quot;/docs/packages/&quot;&gt;package&lt;/a&gt;&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image&lt;/code&gt; can now name the colors its icon is painted in, so a package tile in the library, and in the Add-tab and Add-widget choosers, can match the thing it installs. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;library.image&lt;/code&gt; is either an embedded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data:&lt;/code&gt; image or a space-delimited art spec whose first word is a Cerb icon name and whose optional second and third are the background and glyph colors as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#rgb&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#rrggbb&lt;/code&gt;. Writing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;todo&lt;/code&gt; gives the icon on a neutral gray, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;todo #7f7f7f&lt;/code&gt; sets the background, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;todo #7f7f7f #ffffff&lt;/code&gt; sets both. Either color can be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;light:dark&lt;/code&gt; pair, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;todo #eeeeee:#333333&lt;/code&gt; paints one color in the light theme and the other in dark, and a color with no pair is used in both. The word &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; holds a slot at its default, which is how you set a foreground without pinning a background: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;todo auto #d62728&lt;/code&gt;. Anything unusable falls back on its own slot&apos;s default, so an unrecognized icon name still lets your colors through and a malformed color still lets your icon through.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Connected Services/Packages]&lt;/strong&gt; Added an &quot;OpenRouter&quot; package to the connected services library, so the &lt;a href=&quot;/docs/records/types/connected_account/&quot;&gt;connected account&lt;/a&gt; an OpenRouter &lt;a href=&quot;/docs/records/types/agent_model/&quot;&gt;agent model&lt;/a&gt; authenticates with is one choice from the library rather than a service built by hand.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Roles]&lt;/strong&gt; A &lt;a href=&quot;/docs/records/types/role/&quot;&gt;role&lt;/a&gt;&apos;s profile image can now be set through the &lt;a href=&quot;/docs/api/endpoints/records/&quot;&gt;records API&lt;/a&gt;, &lt;a href=&quot;/docs/packages/&quot;&gt;packages&lt;/a&gt;, and &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt;. Roles could already be given an image in the role editor; now anything that writes records can set one, so a role&apos;s avatar can arrive from a package or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.create:&lt;/code&gt; rather than only from someone uploading it. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image&lt;/code&gt; takes a base64 PNG data URI exactly as &lt;a href=&quot;/docs/records/types/group/&quot;&gt;groups&lt;/a&gt; and &lt;a href=&quot;/docs/records/types/worker/&quot;&gt;workers&lt;/a&gt; do, with the same limits – PNG, between 50x50 and 500x500, and under 1MB. A role also exposes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_image_url&lt;/code&gt; now, so its avatar turns up wherever Cerb draws a record&apos;s image: placeholders, mention chips, custom field forms, comments, and role autocomplete entries.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Agents]&lt;/strong&gt; The &lt;strong&gt;LLM Agent Transcripts&lt;/strong&gt; page has moved out of &lt;strong&gt;Setup » Developers&lt;/strong&gt; and into the new &lt;strong&gt;Setup » AI&lt;/strong&gt; menu, where it&apos;s listed as &lt;strong&gt;Transcripts&lt;/strong&gt; and titled &lt;strong&gt;Agent Transcripts&lt;/strong&gt;. Reading back what an agent did belongs beside the records that agent is made of, rather than in with the schema browser and the token generator. Nothing about the page itself changed, and its address is unchanged.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/KATA]&lt;/strong&gt; In &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt;, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type/name:&lt;/code&gt; name that becomes a dictionary key must now be a valid variable name – letters, numbers, and underscores only. Previously a name containing a dash silently rendered as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; wherever it was read back, because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{{a-b}}&lt;/code&gt; is the subtraction &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a - b&lt;/code&gt; rather than a variable reference. This caused quiet failures like a worklist export column full of zeros, or a snippet placeholder that evaluated to nothing. The check is applied where a name actually lands in a dictionary – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await:form:elements:&lt;/code&gt;, snippet and dashboard prompts, worklist export columns, and LLM tool &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters:&lt;/code&gt; – and is available declaratively as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nameFormat: variable&lt;/code&gt;. The parser still allows the wider character set elsewhere, since most names are labels or handles that are never read back as placeholders.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[UI/Tabs]&lt;/strong&gt; Tweaked the style of tab sets throughout the interface.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Ported popups from jQuery UI dialogs to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Dialog&lt;/code&gt;. Every AJAX popup in the interface is now a Cerb component, which is what makes the shared minimize tray, cascading restore, and unsaved-changes guard work consistently everywhere.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Converted record peeks and bulk update forms to Cerb UI. Every edit popup now uses the same field, label, and section structure, so editing a ticket and editing a custom record look and behave alike.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Cards/UI]&lt;/strong&gt; All record card popups now use the new Cerb UI components and styles. Records without a profile image show a default record type icon, and popup titles include both the record type and the record name – which makes them easy to tell apart in the minimized popup tray.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cards/Cerb UI]&lt;/strong&gt; Restyled card editors with Cerb UI components for all record types and card widget types. Every widget type has a default icon based on its type, displayed next to the title as a visual cue, and the icon can be overridden per widget in the editor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles/Cerb UI]&lt;/strong&gt; Restyled profile widget editors with Cerb UI components for all record types and profile widget types, with the same per-type default icons and per-widget override.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Automations]&lt;/strong&gt; Rebuilt the &lt;a href=&quot;/docs/automations/&quot;&gt;automation&lt;/a&gt; editor on Cerb UI. The script and policy panes are now Cerb&apos;s own KATA editor instead of Ace, and the template picker, form builder, and agent chat are reachable for the first time.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Ported chart widgets to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Chart&lt;/code&gt;. Charts now render through Cerb&apos;s own components instead of c3.js and d3.js.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Ported calendars to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Calendar&lt;/code&gt;. Calendar widgets render in day, week, month, and year views through Cerb&apos;s own component. Previously they were month-only, and prev/today/next each cost a full server round-trip; now switching views and moving between periods is instant. A multi-day event renders as a single strip spanning the days it covers – keeping its track as it wraps from week to week – rather than as a separate chip repeated on each day. Several event sources can be shown at once with a legend, the year view marks active days with pips you can drill into, and each widget chooses which view it opens on. The availability calendar widget is unchanged, since it builds its events differently.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/calendars.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI]&lt;/strong&gt; Converted the worker interaction panel to Cerb UI, and made a failed submit recoverable. A dropped request no longer strands the interaction behind a spinner that never clears.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Cerb UI/Search]&lt;/strong&gt; Refactored the global search menu to use modern Cerb UI components, added record-type icons, and improved keyboard filtering.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Widgets/Fields/Cerb UI]&lt;/strong&gt; Improved the display and configuration of &apos;Record Fields&apos; card, profile, and workspace widgets. The &apos;Fields&apos; tab shows a preview grid matching the actual output, custom fieldsets are collapsible sections with all/none shortcuts, and search buttons and record links use the new badge count toolbar style.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/UI]&lt;/strong&gt; Redesigned the &lt;a href=&quot;/docs/setup/&quot;&gt;Setup&lt;/a&gt; pages on the new Cerb UI design system, across both the Configure sections (authentication, branding, cache, license, localization, security, team) and the mail and Developers sections.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Debug]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEVELOPMENT_MODE_ALLOW_DEBUG&lt;/code&gt; config option. This is replaced by &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;service tokens&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Auth]&lt;/strong&gt; Deprecated the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AUTHORIZED_IPS_DEFAULTS&lt;/code&gt; IP allowlist for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/cron&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/debug&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/update&lt;/code&gt;. This is replaced by &lt;a href=&quot;/docs/records/types/service_token/&quot;&gt;service tokens&lt;/a&gt;, which work regardless of where the request originates.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Docker]&lt;/strong&gt; Updated the Docker examples to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CERB_SERVICE_TOKEN&lt;/code&gt; rather than client IP validation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Docker]&lt;/strong&gt; Updated the Docker examples with automatic configuration from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Docker]&lt;/strong&gt; Added support for customizable environment and port variables in Docker Compose.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Docker]&lt;/strong&gt; Bumped the PHP-FPM &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pm.max_children&lt;/code&gt; default from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10&lt;/code&gt;. This makes it easier to handle &lt;a href=&quot;/docs/queues/&quot;&gt;parallel queue&lt;/a&gt; processing at full capacity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Automations]&lt;/strong&gt; Converted the automations full-text index to a search index record so it can be fully customized or removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Comments]&lt;/strong&gt; Converted the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;comments:&lt;/code&gt; filter on record worklists and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notes:&lt;/code&gt; filter on message records into customizable &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; records. Previously these were hard-coded MySQL FULLTEXT indexes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Contacts]&lt;/strong&gt; Converted the contacts full-text index to a search index record so it can be fully customized or removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Email Address]&lt;/strong&gt; On email address record dictionaries, added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aliases&lt;/code&gt; key to access that data from functionality like sheets and automations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Knowledgebase]&lt;/strong&gt; Converted the knowledgebase articles full-text index to a customizable &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; record so it can be fully customized or removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Mail/Content]&lt;/strong&gt; Converted the message content full-text index to a customizable &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; record. Previously this was a hard-coded MySQL FULLTEXT index, which made it difficult to scale on installations with large amounts of historical message content. The search index extension supports sparse strategies (e.g. only outgoing replies from the past year) for dramatically smaller search spaces.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Mail/Headers]&lt;/strong&gt; Converted the message email header filters (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.cc:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.cerbMailbox:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.deliveredTo:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.from:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.to:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.mailer:&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.forwardedTo:&lt;/code&gt;) into customizable &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; records. Each environment can add additional header filters or drop ones they don&apos;t use. New installations no longer create them by default. Previously these were indexed in MySQL/InnoDB much less efficiently.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Orgs]&lt;/strong&gt; Converted the organizations full-text index to a search index record so it can be fully customized or removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Snippets]&lt;/strong&gt; Converted the snippets full-text index to a search index record so it can be fully customized or removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Tickets]&lt;/strong&gt; On &lt;a href=&quot;/docs/records/types/ticket/&quot;&gt;ticket&lt;/a&gt; worklists, the default search filter is now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;messages&lt;/code&gt; (backed by the new &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; for message content). This behaves like the previous full-text default but no longer requires backend code – admins can fully customize what&apos;s indexed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Workers]&lt;/strong&gt; Converted the workers full-text index to a search index record so it can be fully customized or removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Parser/Filters]&lt;/strong&gt; In the inbound email parser, &lt;a href=&quot;/docs/automations/events/mail.filter/&quot;&gt;mail.filter&lt;/a&gt; &lt;a href=&quot;/docs/automations/&quot;&gt;automations&lt;/a&gt; now run dependently rather than independently. Previously, a change in one mail filter was not reflected in later mail filters (e.g. changing an email header). The state is now updated between each invoked filter automation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Contacts]&lt;/strong&gt; On contact record dictionaries, added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aliases&lt;/code&gt; key to access that data from functionality like sheets and automations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Workers]&lt;/strong&gt; On worker record dictionaries, added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aliases&lt;/code&gt; key to access that data from functionality like sheets and automations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Installer/UX]&lt;/strong&gt; Modernized the style of the web-based installer.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/installer-modernized.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Installer/UX]&lt;/strong&gt; In the guided installer, the first input on each step is automatically focused to improve usability.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Login/UI/UX]&lt;/strong&gt; Restyled the login flow to match the modern dark-mode aesthetic.&lt;/p&gt;

    &lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/12.0/login-restyle.png&quot; class=&quot;screenshot&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[UI/Styles]&lt;/strong&gt; Replaced the old bitmap icons on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt; text inputs with modern inline SVGs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Search]&lt;/strong&gt; In worklist search queries, when specifying a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sort:&lt;/code&gt; filter, the current column sort is reset before parsing. Previously, an invalid sort column was ignored and the previous sort order was retained without warning.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Compose/UX]&lt;/strong&gt; Added validation for invalid email addresses in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cc&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc&lt;/code&gt; fields when composing a new email message from ticket worklists.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Reply/UX]&lt;/strong&gt; Added extra validation for invalid email addresses in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cc&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bcc&lt;/code&gt; fields when replying to a ticket. This catches common errors like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;customer@example,com&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Interactions]&lt;/strong&gt; An agent turn running in the background now makes far fewer requests while you wait for it. Three separate requests watch a running turn – one to advance the &lt;a href=&quot;/docs/queues/&quot;&gt;queue&lt;/a&gt;, one to check whether the turn has landed, and one to refresh the transcript – and together they ran about twice a second for the whole turn whether or not anything was changing. The transcript refresh was the expensive one, rebuilding the entire conversation on the server once a second only to discover it was identical to the previous second. The server now paces the wait itself, stretching its check as a turn runs long and telling the browser when no queue worker is needed because the turn is already being processed elsewhere. The transcript refresh runs at full speed only while an answer is actively being written; while a tool runs, on providers that don&apos;t stream, and in a background tab it slows right down, and when nothing has changed the server answers from a single row instead of rebuilding the conversation. Also fixed: a stopped or expired interaction could keep polling for as long as its tab stayed open.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[UI/Performance]&lt;/strong&gt; Optimized the generation of deeply nested placeholder menus.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Maint/Workers/Watchers]&lt;/strong&gt; Nightly maintenance now clears watcher links on deactivated workers. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/823&quot;&gt;#823&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Branding/UI]&lt;/strong&gt; The user-defined logo and stylesheet are now served from new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/branding/logo&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/branding/logo-dark&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/branding/stylesheet&lt;/code&gt; endpoints instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/resource/cerberusweb.core/css/*&lt;/code&gt;. This lets CDNs and caching layers treat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/resource/*&lt;/code&gt; as immutable non-shared static content. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1135&quot;&gt;#1135&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Custom Fields]&lt;/strong&gt; &apos;Text block&apos; custom fields now support 4-byte UTF-8 characters (e.g. emoji). The underlying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;custom_field_clobvalue.field_value&lt;/code&gt; column was migrated to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;utf8mb4&lt;/code&gt; with collation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;utf8mb4_unicode_ci&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[UI/UX]&lt;/strong&gt; In dark mode, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;color-scheme&lt;/code&gt; CSS property is now set so the browser renders native UI components (scrollbars, form controls, dropdowns) with a matching dark palette.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; In automation scripting, the &lt;a href=&quot;/docs/scripting/filters/#csv&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|csv&lt;/code&gt;&lt;/a&gt; filter will now attempt to convert objects/dictionaries to arrays. Previously, this always failed if the input wasn&apos;t already an array.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Queues]&lt;/strong&gt; In automations, the &lt;a href=&quot;/docs/automations/commands/queue.push/#output&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;output:&lt;/code&gt;&lt;/a&gt; parameter of &lt;a href=&quot;/docs/automations/commands/queue.push/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue.push:&lt;/code&gt;&lt;/a&gt; is now optional. It&apos;s only needed when you want to capture the resulting queue message IDs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Storage/S3/Performance]&lt;/strong&gt; The &apos;S3&apos; storage engine now uses the batch deletion endpoint to remove up to 1,000 objects in a single request. Previously, this engine inefficiently issued one DELETE request per object.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Storage/AWS]&lt;/strong&gt; Secrets in &apos;S3&apos; storage profiles are now stored in encrypted &lt;a href=&quot;/docs/records/types/connected_account/&quot;&gt;connected accounts&lt;/a&gt; rather than in the storage profile configuration. Existing profiles are migrated automatically on upgrade.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers/HuggingFace]&lt;/strong&gt; The Hugging Face &lt;a href=&quot;/docs/agents/#providers&quot;&gt;LLM provider&lt;/a&gt; now uses the OpenAI-compatible serverless &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;router&lt;/code&gt; endpoint rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api-inference&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;deprecated&quot;&gt;Deprecated&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Plugins/Files/Bundles]&lt;/strong&gt; Moved &apos;File Bundle&apos; records into an optional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.file_bundles&lt;/code&gt; plugin that is disabled by default. On upgrade, the plugin is enabled automatically only if you actually have file bundle records; otherwise the empty table is dropped and the plugin recreates it if an admin enables it later. Installations that never used file bundles stay clean.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Bots/Behaviors/Deprecations]&lt;/strong&gt; Moved legacy bot behavior functionality into an optional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.behaviors.legacy&lt;/code&gt; plugin. This will be retired in 12.0. On upgrade, the plugin is automatically enabled only if active behaviors exist, so installations without legacy behaviors stay clean.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;removed&quot;&gt;Removed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Portals/Support Center/Templates]&lt;/strong&gt; Removed custom HTML templates from community &lt;a href=&quot;/docs/portals/&quot;&gt;portals&lt;/a&gt; like the &lt;a href=&quot;/docs/portals/support-center/&quot;&gt;Support Center&lt;/a&gt;. These templates constantly drifted and caused problems on every upgrade (for instance, the 12.0 migration from the Glyphicons font to built-in Cerb SVG icons), and they increased the attack surface by relying on the Smarty sandbox. Customization should now be done through the portal stylesheet, theme, and widget configuration. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_OPT_DEPRECATED_PORTAL_CUSTOM_TEMPLATES&lt;/code&gt; config option was also removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists]&lt;/strong&gt; Removed the &apos;copy&apos; option from legacy worklists, which duplicated a worklist to a new workspace. The modern export/import functionality should be used instead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspaces/UI]&lt;/strong&gt; Removed the &apos;Display tabs as&apos; option on workspace pages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Scheduler/Migrations]&lt;/strong&gt; Retired the &apos;cron.migrations&apos; scheduler job since it was only used once in 10.4 (Feb 2022).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Scheduler/Metrics]&lt;/strong&gt; Retired the standalone &apos;cron.metrics&apos; scheduler job since this is now handled by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cron.background_queue&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Plugins]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerberusweb.plugin.setup&lt;/code&gt; extension point and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Extension_PluginSetup&lt;/code&gt; parent class. No remaining plugins implemented setup steps, and removing the extra step enables single-click plugin enable/disable from the &lt;a href=&quot;/docs/plugins/&quot;&gt;Setup » Configure » Plugins&lt;/a&gt; worklist. The &apos;uninstall&apos; action was also removed from the GUI – plugin removal is now a filesystem operation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Setup/Search]&lt;/strong&gt; Removed the &apos;Search&apos; page from &lt;a href=&quot;/docs/setup/&quot;&gt;Setup » Configure&lt;/a&gt;. Search engines and schemas are now configured directly on &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; records, where each index can be independently tuned, paused, and re-indexed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Search]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devblocks.search.engine&lt;/code&gt; extension point and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Extension_DevblocksSearchEngine&lt;/code&gt; parent class (along with the bundled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DevblocksSearchEngineMysqlFulltext&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DevblocksSearchEngineElasticSearch&lt;/code&gt; engines). Custom search backends are now implemented as &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; extensions, which integrate directly with worklist filters and the background queue.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Search]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devblocks.search.schema&lt;/code&gt; extension point and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Extension_DevblocksSearchSchema&lt;/code&gt; parent class. Per-record full-text schemas are now expressed as &lt;a href=&quot;/docs/records/types/search_index/&quot;&gt;search index&lt;/a&gt; records and can be created or modified without code changes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Activity Log/Metrics]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worker.seat_expired&lt;/code&gt; activity log entry and its notification, along with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.sessions.seat.kicks&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.sessions.seat.kicks.duration&lt;/code&gt; metrics. All four existed to report a worker session that had been ended to free a license seat, and with &lt;a href=&quot;#setup-and-developers&quot;&gt;seat enforcement gone&lt;/a&gt; no session is ever ended for that reason. Historical samples on the two metrics are left in place; nothing new is written to them.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Devblocks/Registry]&lt;/strong&gt; Fixed an issue in the Devblocks &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;registry&lt;/code&gt; service where a key wasn&apos;t deleted from backend storage if it hadn&apos;t been loaded.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles]&lt;/strong&gt; Fixed an issue on profile pages where a newly created tab couldn&apos;t be selected until the page had been reloaded.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mailboxes]&lt;/strong&gt; Fixed an issue where a mailbox&apos;s consecutive failure count could exceed the field&apos;s range of 0–127.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Search]&lt;/strong&gt; In worklist search autocomplete, fixed an issue with hybrid text and parameterized filters such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;created:&lt;/code&gt;, where accepting a suggestion broke any further suggestions on that filter.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data Queries]&lt;/strong&gt; Fixed an issue with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worklist.subtotals&lt;/code&gt; data queries when grouping time-series data by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@quarter&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@quarterofyear&lt;/code&gt; against a &apos;date&apos; custom field.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Bots/Behaviors]&lt;/strong&gt; Fixed an issue where the same bot behavior tree shown in more than one place – a profile page and a popup, for instance – was only editable in one of them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Resources/Storage]&lt;/strong&gt; Fixed a bug in &lt;strong&gt;Setup » Developers » Platform&lt;/strong&gt; where reloading &lt;a href=&quot;/docs/records/types/resource/&quot;&gt;resource&lt;/a&gt; records that used a non-local storage profile, such as S3, reset the storage engine to &apos;database&apos; without also resetting the profile ID.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Storage/Schemas]&lt;/strong&gt; Fixed an extension ID inconsistency between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Storage_RecordChangeset&lt;/code&gt; class and its plugin manifest.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/UX]&lt;/strong&gt; Updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.reply.isBannedDefunct&lt;/code&gt; to ignore senders on outgoing messages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Time Tracking/Roles]&lt;/strong&gt; Workers without the time tracking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; privilege can no longer close entries from the worklist. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/901&quot;&gt;#901&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Calendars]&lt;/strong&gt; Fixed a long-standing bug where all-day events could appear to span two days for half the year. Times were handled as a fixed offset captured at one point in the year, so once daylight saving shifted, every all-day event&apos;s end rolled into the following day. Timezones are now resolved by name, so an event sits on the day it belongs to regardless of season.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspace/Widgets/Calendar]&lt;/strong&gt; Fixed exporting CSV/JSON from calendar workspace widgets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspace/Widgets/TimeBlocks]&lt;/strong&gt; Fixed CSV exports in Time Blocks workspace widgets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workspaces/Widgets]&lt;/strong&gt; Fixed URL datasource caching for legacy workspace widgets. Previously, the cache was always disabled and didn&apos;t invalidate immediately if the URL changed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Sheets/Export]&lt;/strong&gt; Fixed an issue with &lt;a href=&quot;/docs/sheets/&quot;&gt;sheets&lt;/a&gt; when exporting CSV data from workspace widgets for unknown column types or null values.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[UI/Styles]&lt;/strong&gt; Fixed the forced white background on IFRAMEs in the attachment viewer. This now falls back to the OS light/dark preference. Previously in OS dark mode it was showing white-on-white text.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Login/UX]&lt;/strong&gt; Fixed a dead-end error page when the CSRF token expired on the login form. The worker is now redirected back to the login form with an error message instead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Support Center/Profiles]&lt;/strong&gt; Fixed an issue in the Support Center portal where the stricter Content-Security-Policy prevented the avatar image editor from working.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Worklists]&lt;/strong&gt; A failed &lt;a href=&quot;/docs/worklists/&quot;&gt;worklist&lt;/a&gt; refresh no longer blanks the list. Creating or editing a record from a chooser popup could leave that popup&apos;s worklist empty until you closed and reopened it, and any refresh that failed behaved the same way – the list was replaced with nothing and no error was shown, so there was no indication anything had gone wrong. A failed refresh now leaves the existing rows in place and reports what happened, including server errors that previously went entirely unreported, while requests that were merely cancelled by navigating away or closing a popup mid-request are ignored rather than reported as failures. Chooser popups also keep their search text after a refresh.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Integrations/AWS]&lt;/strong&gt; Fixed the &quot;Get pre-signed URL&quot; bot action failing with a fatal error. It called a Guzzle 6 function that Guzzle 7 removed, so every invocation crashed instead of returning a URL.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Fixed AWS Bedrock rejecting a turn when a model called several tools at once. Parallel tool results are now sent as the single conversation turn the API expects, so agents on models that batch their tool calls no longer fail mid-loop.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; AWS Bedrock no longer fails a turn when one of its tools has no description. Its Converse API treats a description as optional but rejects an empty one, and refuses the entire request rather than just the offending tool – so one undescribed tool disabled every tool on that turn. Cerb now leaves the description out instead of sending it empty.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; DeepSeek models on AWS Bedrock no longer leak their internal tool-call markup into replies. The structured tool call is unaffected; only the duplicate markup in the visible text is removed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Policies]&lt;/strong&gt; Fixed an issue in &lt;a href=&quot;/docs/automations/#policies&quot;&gt;automation policies&lt;/a&gt; where annotations on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;settings:&lt;/code&gt; keys – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time_limit_ms@int&lt;/code&gt;, for instance – weren&apos;t handled properly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Data Queries/Platform]&lt;/strong&gt; Fixed &lt;a href=&quot;/docs/data-queries/platform/extensions/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;platform.extensions&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;/docs/data-queries/platform/points/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;platform.extension.points&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;/docs/data-queries/&quot;&gt;data queries&lt;/a&gt; drifting from the installation they describe. Both lists are now built from the actual platform registry and enriched from documentation, rather than from a hand-maintained array that live extension points had gone missing from.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[KATA]&lt;/strong&gt; In &lt;a href=&quot;/docs/kata/&quot;&gt;KATA&lt;/a&gt;, the &lt;a href=&quot;/docs/kata/#float&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@float&lt;/code&gt;&lt;/a&gt; annotation now accepts a multiple-line indented value like the other annotations. Following a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@float&lt;/code&gt; key with an indented block was a syntax error, and leaving its value blank produced an empty object rather than a number.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; The scripting editors no longer suggest a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{% filter %}&lt;/code&gt; command that can&apos;t run. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{% filter %}&lt;/code&gt; was removed from the template engine years ago in favor of &lt;a href=&quot;/docs/scripting/commands/#apply&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{% apply %}&lt;/code&gt;&lt;/a&gt;, but it stayed in the editor&apos;s autocomplete, so it was offered to authors and then rejected with a parse error when the script ran. Typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{% f&lt;/code&gt; now offers &lt;a href=&quot;/docs/scripting/commands/#for&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt;&lt;/a&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;platform&quot;&gt;Platform&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/PHP]&lt;/strong&gt; Updated the minimum required PHP version to 8.5.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Docker]&lt;/strong&gt; Updated the Dockerfile to Ubuntu 26.04 LTS and PHP 8.5.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Updated the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;css-to-inline-styles&lt;/code&gt; library from v2.2.4 to v2.3.0.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Updated the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twig&lt;/code&gt; library from v3.8.0 to v3.26.0.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Composer/Twig]&lt;/strong&gt; Replaced our forked Twig dependency with the official &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twig/twig&lt;/code&gt; package. Rather than maintaining a patch against their source for our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DevblocksDictionaryDelegate&lt;/code&gt; fallback on undefined variables, we now override &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Environment&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ContextVariable&lt;/code&gt; and implement a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_DevblocksUndefinedVariableNodeVisitor&lt;/code&gt;. A new test suite catches regressions. This makes it much easier to follow Twig&apos;s official updates and security notices.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Services/AWS]&lt;/strong&gt; Added an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws&lt;/code&gt; service to the platform that consolidates AWS functionality like request signature generation. It&apos;s used by connected accounts for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http.request:&lt;/code&gt; and by storage profiles for S3-compatible storage backends.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the legacy &apos;Amazon S3 PHP Class&apos; library. This functionality is now handled entirely within Cerb by the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aws&lt;/code&gt; service.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the Glyphicons icon font in favor of the new custom Cerb SVG &lt;a href=&quot;/docs/developers/icons/&quot;&gt;icon set&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async.js&lt;/code&gt; library in favor of the new Cerb UI async utilities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed jQuery UI. Cerb now implements its own &lt;a href=&quot;/docs/developers/cerb-ui/&quot;&gt;component library&lt;/a&gt;. (jQuery itself is still present – only jQuery &lt;em&gt;UI&lt;/em&gt; was retired.) An earlier step in this release updated jQuery UI from v1.13.1 to v1.13.3 and dropped its Accordion, Datepicker, and Tooltip components as Cerb UI replaced them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed Ace.js and ace-diff. Cerb now implements its own code editors and diff viewer in Cerb UI.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the D3.js library. It was used for visualizations that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Chart&lt;/code&gt; now handles.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c3&lt;/code&gt; charting library, along with the legacy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jquery.devblocksCharts&lt;/code&gt; plugin. Cerb UI now handles this functionality natively.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the TopoJSON library. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.Map&lt;/code&gt; decodes and projects TopoJSON itself.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the Dagre-D3 library. It was used for the directed graphs in the automation editor&apos;s &apos;Visualization&apos; tab, which the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.NodeEditor&lt;/code&gt; and node graph components now provide.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Removed the miniColors jQuery plugin, replaced by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerbUI.ColorPicker&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Cerb UI/Developers]&lt;/strong&gt; Removed the legacy jQuery plugins and shims that &lt;a href=&quot;/docs/developers/cerb-ui/#retired-dependencies&quot;&gt;Cerb UI&lt;/a&gt; supersedes, including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cerbCodeEditor&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cerbPropertyGrid&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cerbQueryTrigger&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cerbChooserTrigger&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerbTextEditor&lt;/code&gt; family, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jquery.qrcode&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Devblocks.tooltip&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Devblocks.selectValue&lt;/code&gt;. If a third-party plugin calls any of these, it will need updating to the Cerb UI equivalents.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/XML]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DevblocksPlatform::parseXml()&lt;/code&gt; helper that suppresses errors while parsing XML.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Upgraded the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lcobucci/jwt&lt;/code&gt; library to v5.6.0 and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;league/oauth2-server&lt;/code&gt; library to v9.3.0 for PHP 8.5 compatibility.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Upgraded the Horde IMAP library from v2.30.6 to v2.34.1 for PHP 8.x support.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Dependencies]&lt;/strong&gt; Added a PorterStemmer class for stemming tokens in search indexes. Credit to Richard Heyes (phpguru.org).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Search/Developers]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search&lt;/code&gt; service to the Devblocks platform. This handles common functionality like tokenization, stop words, hashing, stemming, and indexing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/Developers/Tests]&lt;/strong&gt; Upgraded phpUnit from 9.6.34 to 12.5.33.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Docker]&lt;/strong&gt; In the reference Docker environment, queue and scheduler drains now run on their own PHP-FPM pool in their own container, so a long agent turn or &lt;a href=&quot;/docs/queues/&quot;&gt;queue&lt;/a&gt; job can no longer occupy a worker that page loads needed. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/queue&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/cron&lt;/code&gt; route to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-fpm-background&lt;/code&gt; container running a pool tuned for long holds, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-fpm&lt;/code&gt; serves everything else – one request can hold a child for the length of an agent turn, so keeping the two apart is what stops a busy queue from making the interface feel slow. Scale the drain capacity with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker compose up --scale php-fpm-background=3&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CERB_WEB_CHILDREN&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CERB_BACKGROUND_CHILDREN&lt;/code&gt; size the two pools, defaulting to 6 and 4 – the same ten children the image previously ran as one shared pool. Size the background pool on memory and database connections rather than cores: a drain worker burns almost no CPU while it waits on a provider, but holds roughly 50-60MB and one MySQL connection for the length of the drain. This is a reference environment rather than a production topology – backpressure stays in the app, where a drain that can&apos;t get a concurrency slot answers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;529&lt;/code&gt; with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Retry-After&lt;/code&gt;, so it works the same however your own edge is built.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security-1&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Support Center/Security]&lt;/strong&gt; In the Support Center portal, added a stricter Content-Security-Policy that requires nonce tokens for scripts and removes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsafe-inline&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Markdown]&lt;/strong&gt; When parsing Markdown with HTML allowed (safe mode disabled), the following HTML tags are still disallowed: title, textarea, style, xmp, iframe, noembed, noframes, script, and plaintext.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security]&lt;/strong&gt; HMAC-signed all cache engine payloads (disk, Redis, Memcached) to prevent deserialization of attacker-controlled data.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Composer]&lt;/strong&gt; Pinned Composer dependencies to audited versions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Queues/Jobs/Security]&lt;/strong&gt; Tightened permissions on &lt;a href=&quot;/docs/records/types/queue_job/&quot;&gt;queue jobs&lt;/a&gt; so only the initiating worker and admins can view a job&apos;s details or its file attachments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;symfony/mailer&lt;/code&gt; to v7.4.12 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;guzzlehttp/guzzle&lt;/code&gt; to v7.15.3 in response to security advisories.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpseclib/phpseclib&lt;/code&gt; to v3.0.54 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smarty/smarty&lt;/code&gt; to v4.5.7 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;league/commonmark&lt;/code&gt; to v2.10.0 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phpunit/phpunit&lt;/code&gt; to v12.5.33 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[OAuth/Security]&lt;/strong&gt; OAuth2 consent is now bound to the app and the scopes it was granted for. Login state is reused for 20 minutes, and in the OAuth flow it was only cleared once an authorization request ran to completion – so a flow abandoned after the consent screen, where a worker approves an app but the browser never makes it back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/oauth/authorize&lt;/code&gt;, left a granted consent sitting in the session. Within that window, following an authorization link for a &lt;em&gt;second&lt;/em&gt; app issued it an authorization code with no consent screen shown at all, and the same gap let an app that had already been approved widen its scopes silently. The login state now records the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;client_id&lt;/code&gt; and the scope set that were actually displayed on the consent screen, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/oauth/authorize&lt;/code&gt; requires both to match the request in hand. Scope comparison ignores order and duplicates, so a reordered scope list doesn&apos;t force a redundant re-prompt. A declined request still counts as answered and continues to return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;access_denied&lt;/code&gt; to the client rather than looping back to the consent screen, and a POST to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/login/consent&lt;/code&gt; with no authorization request pending now grants nothing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[OAuth Apps/Security]&lt;/strong&gt; The OAuth2 authorization flow now returns to the hostname in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_HOSTNAME&lt;/code&gt; after a worker signs in or grants consent. When an authorization request reached &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/oauth/authorize&lt;/code&gt; and the worker still had to sign in or approve the requested scopes, Cerb saved the return address using the hostname from the incoming request instead of the configured one. Where a proxy or load balancer presents a hostname other than the one workers browse, the round trip came back on the wrong origin – and since session cookies are scoped to a single hostname, no session existed there, so the flow either looped back to the sign-in form or stopped with an access denied error. On Cerb Cloud this showed up as a custom domain falling back to the instance&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.cerb.me&lt;/code&gt; address partway through.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/LDAP/SSO]&lt;/strong&gt; Added CA certificate and certificate-verification options for LDAPS. A directory using a self-signed or private CA can now be connected by supplying its CA certificate to Cerb, rather than modifying the system-wide TLS configuration.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twig&lt;/code&gt; to v3.26.0 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/SSO/OIDC]&lt;/strong&gt; Hardened the OpenID Connect SSO callback to validate the OAuth &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt; parameter against a per-request value stored at the start of the authorization request. Previously an attacker could deliver a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?code=...&amp;amp;state=...&lt;/code&gt; URL to a victim and force their browser through the callback, signing them into the attacker&apos;s identity (login CSRF / session injection). Mismatches now abort with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auth.failed&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/SSO/OIDC]&lt;/strong&gt; Hardened the OpenID Connect SSO flow by sending and verifying a per-request &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nonce&lt;/code&gt; (OIDC Core §3.1.2.1, §3.1.3.7). The authorization request now includes a 128-bit random nonce that is persisted in the session and constant-time compared against the ID token&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nonce&lt;/code&gt; claim. This prevents ID-token replay across sessions and devices and brings the implementation into spec compliance for the authorization code flow.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/SSO/OIDC]&lt;/strong&gt; Hardened the OpenID Connect SSO flow by rejecting ID tokens whose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email_verified&lt;/code&gt; claim is present and not strictly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; (OIDC Core §5.1). Without this check, an IdP that allows users to set arbitrary unverified email addresses could let an attacker impersonate any worker by claiming their email. The check passes through when the claim is absent to preserve compatibility with custom IdPs that don&apos;t emit it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/SSO/OIDC]&lt;/strong&gt; Hardened OpenID Connect ID-token signature verification when the IdP omits the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kid&lt;/code&gt; (Key ID) header. Previously the code validated against only the first JWK in the JWKS, which silently failed if the JWKS contained multiple keys (e.g. during key rotation) and the signer wasn&apos;t first. The kid-less branch now iterates through every JWK and uses the one whose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SignedWith&lt;/code&gt; constraint validates the token; if none match, a specific &quot;did not validate against any JWKS key&quot; error is surfaced. IdPs that emit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kid&lt;/code&gt; continue to use the exact-key lookup unchanged.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/SSO/SAML]&lt;/strong&gt; Closed an open-redirect path through SAML SSO. The callback was pushing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RelayState&lt;/code&gt; directly into the post-login redirect stack without origin validation, so a malicious or compromised IdP (or a forged callback POST) could pin an absolute attacker URL and hijack the user post-auth. Redirect URIs are now restricted to relative paths or absolute URLs whose scheme, host, and port match the configured base URL. Same-origin absolute URLs (e.g. the OAuth2 server &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/oauth/authorize&lt;/code&gt; round-trip) continue to work.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Auth]&lt;/strong&gt; Switched the remaining secret-vs-secret comparisons across the codebase to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash_equals()&lt;/code&gt; so comparisons are constant-time and don&apos;t leak secrets one byte at a time. Sites updated: the centralized CSRF token check, the Support Center CSRF check, the REST API HMAC signature compare, the OAuth2 server &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;client_secret&lt;/code&gt; verification, the worker password recovery code and secret-question answer compares, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_SERVICE_TOKEN&lt;/code&gt; compare, and the portal image HMAC compare.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Auth]&lt;/strong&gt; Tightened login-state hygiene so abandoned authentication flows can&apos;t bleed into the next attempt. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clearAuthState()&lt;/code&gt; now also resets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motd&lt;/code&gt; so a previous attempt&apos;s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worker.authenticated&lt;/code&gt; automation result doesn&apos;t surface on the next login form. The redirect URI stack is cleared at the two true abandonment points: when the MFA retry limit is exceeded, and when password recovery wrong-guesses are exhausted.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Recovery]&lt;/strong&gt; When a worker completes the password recovery flow, all of their existing sessions are now evicted immediately after the password is rewritten. Previously a stolen session cookie would keep working until natural expiration even after the legitimate user reset their password specifically to evict the attacker. The eviction fires only after every gate of the recovery flow has passed (email control via the recovery code, second factor via TOTP or secret questions, and the password rewrite).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 07 Sep 2026 09:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/12.0/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/12.0/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.10</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.10.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.10)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on June 22, 2026. It includes &lt;strong&gt;6&lt;/strong&gt; minor fixes and security patches covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[LLM/Providers]&lt;/strong&gt; Updated the Anthropic API Claude model IDs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Updated symfony/mailer to v7.4.12 in response to security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded Twig to v3.27.1 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded phpseclib/phpseclib to 3.0.54 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded guzzlehttp/guzzle to 7.12.1 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Pinned all Composer dependencies to tested and audited versions.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 22 Jun 2026 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.10/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.10/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.9</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.9.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.9)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on May 13, 2026. It includes &lt;strong&gt;11&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Logs/Mailboxes]&lt;/strong&gt; Mailbox creation is now recorded in the activity log.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles/Widgets]&lt;/strong&gt; Added support for manually specifying a ticket ID in the &apos;Ticket Conversation&apos; profile widget, with fallback to auto-detection for tickets, drafts, and messages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles/Tickets]&lt;/strong&gt; Added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cc:&lt;/code&gt; header to forwarded messages when replying to tickets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/UX]&lt;/strong&gt; Included &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bcc:&lt;/code&gt; headers in outgoing email headers for SMTP and null mail transports.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/UX]&lt;/strong&gt; Improved row selection behavior with text selection handling in worklists. It&apos;s now possible to select and copy text again.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Roles/UX]&lt;/strong&gt; Workers without the comment create permission on a record type no longer see the &apos;Comment&apos; button on profile pages. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1020&quot;&gt;#1020&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Workflows/Builder]&lt;/strong&gt; Fixed an issue in the workflow builder where a KATA parse error (e.g. having both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version@date:&lt;/code&gt; as sibling keys) silently produced an empty workflow template. [&lt;a href=&quot;https://github.com/jstanden/cerb/issues/1873&quot;&gt;#1873&lt;/a&gt;]&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security]&lt;/strong&gt; Hardened the random number generator used for security-sensitive secrets. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CerberusApplication::generatePassword()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_DevblocksMultiFactorAuthService::generateMultiFactorOtpSeed()&lt;/code&gt; now use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;random_int()&lt;/code&gt; (CSPRNG-backed) instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mt_rand()&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str_shuffle()&lt;/code&gt;. This affects the session CSRF token, password recovery codes, worker invitation codes, support center contact recovery/captcha codes/password salts, and TOTP/MFA shared secrets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security]&lt;/strong&gt; Equalized response timing on the worker login form to mitigate user enumeration. Previously, when the submitted email didn&apos;t match a worker, the request short-circuited before any bcrypt work — letting an attacker time the response to learn whether an email is registered. The &quot;no such worker&quot; branch now runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password_verify($password, $dummy_hash)&lt;/code&gt; against a precomputed PASSWORD_DEFAULT bcrypt hash before redirecting, so the response time matches the &quot;wrong password&quot; path. The hash&apos;s plaintext is random and discarded, so the verify always returns false. Empty email/password still fails fast (not an enumeration vector).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security]&lt;/strong&gt; Replaced the legacy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt; password-hash comparison in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DAO_Worker::login()&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash_equals()&lt;/code&gt;. The modern (method=1) path already uses constant-time &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password_verify()&lt;/code&gt;; this closes the last byte-by-byte string compare on the legacy SHA1(salt+MD5) path that pre-9.4 worker auth hashes use until they auto-upgrade on next successful login.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security]&lt;/strong&gt; Improved validation in the Support Center history view.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 13 May 2026 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.9/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.9/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.8</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.8.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.8)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on April 16, 2026. It includes &lt;strong&gt;6&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Behaviors]&lt;/strong&gt; On events where automations and legacy bot behaviors are both triggered, automations with priorities 0-127 run &lt;em&gt;before&lt;/em&gt; behaviors, and automations with priorities 128-255 run &lt;em&gt;after&lt;/em&gt; behaviors. Previously automations always ran first. This affects the events: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mail.received&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mail.sent&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record.viewed&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Performance/Worklists/Export]&lt;/strong&gt; Optimized bulk-loading of custom fields in worklist exports for better performance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles/UX]&lt;/strong&gt; Added a more description &apos;Access Denied&apos; error to profile pages when a worker lacks permission to view a record.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[Devblocks/Platform]&lt;/strong&gt; Suppressed repeated errors within a single request in the error handler.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; In response to security advisories, updated robrichards/xmlseclibs to 3.1.5+, phpseclib to 3.0.50+, and league/commonmark to 2.8.2+.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; In response to a security advisory, updated phpseclib to 3.0.51+.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 16 Apr 2026 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.8/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.8/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.7</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.7.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.7)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on March 06, 2026. It includes &lt;strong&gt;14&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;added&quot;&gt;Added&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[Automations/Scripting]&lt;/strong&gt; Added an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|xml_encode(format)&lt;/code&gt; filter to automation scripting. This converts dictionaries and arrays to XML format. Special &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@tag&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@attributes&lt;/code&gt; keys allow for redundant XML tag names and attribute key/value pairs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Search]&lt;/strong&gt; Improved autocompletion for record search queries on card widgets, connected services, and profile widgets.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Routing]&lt;/strong&gt; In mail routing KATA, the &apos;body&apos; filter can match linefeed characters with wildcards. Previously this only matched the first line.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Messages]&lt;/strong&gt; On message worklists, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; column is now available for display and sorting.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Orgs]&lt;/strong&gt; In organization record dictionaries, added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aliases&lt;/code&gt; field to make that data available to functionality like sheets and automations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Sheets]&lt;/strong&gt; In sheets, added the ability to disable link underlines on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interaction&lt;/code&gt; columns.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; Updated the LLM model autocompletion for modern AWS Bedrock and Anthropic models in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.chat:&lt;/code&gt; commands.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent&lt;/code&gt; automation command, fixed an issue with models that invoke multiple tools in parallel (Claude Sonnet 4.6).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLM]&lt;/strong&gt; In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.agent&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm.chat&lt;/code&gt; automation commands, increased the maximum length of the system prompt parameter. Previously this could be truncated.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Snippets/UX]&lt;/strong&gt; Fixed an issue with inserting placeholders in the snippet editor. They were always being inserted at the beginning of the content rather than at the cursor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Snippets/UX]&lt;/strong&gt; Fixed an issue where multiple snippet editors couldn&apos;t be previewed at the same time.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Sheets]&lt;/strong&gt; Fixed an issue in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slider&lt;/code&gt; sheet columns when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max:&lt;/code&gt; produce a zero-length range.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Security/Dependencies]&lt;/strong&gt; Upgraded the phpunit library to v9.6.33 in response to a security advisory. This would have not affected production instances, as they don&apos;t include development-only dependencies.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Composer/Dependencies]&lt;/strong&gt; Updated thephpleague/commonmark to v2.8.1 in response to a security advisory.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 06 Mar 2026 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.7/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.7/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.6</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.6.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.6)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on January 09, 2026. It includes &lt;strong&gt;11&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;added&quot;&gt;Added&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the OpenAI LLM provider, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reasoning_effort&lt;/code&gt; parameter for reasoning models may now be set to: none, low, medium, high, xhigh.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the Gemini LLM provider, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking_level&lt;/code&gt; parameter for reasoning models may now be set to: minimal, low, medium, high.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the Gemini LLM provider, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thinking_include&lt;/code&gt; parameter may be enabled to return thinking content.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Search/Fulltext]&lt;/strong&gt; Added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_OPT_FULLTEXT_ALLOW_WILDCARDS&lt;/code&gt; option to allow wildcards in fulltext search terms. Since 10.4 this is disabled by default for comments and messages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Developers/Database/Schema]&lt;/strong&gt; Added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm_agent_session&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llm_agent_message&lt;/code&gt; tables to the database schema reference.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the Anthropic LLM provider, updated the list of available models.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the AWS Bedrock LLM provider, updated the list of available models.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the Gemini LLM provider, updated the list of available models.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[LLM/Agents]&lt;/strong&gt; In the OpenAI LLM provider, updated the list of available models.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Comments/UX]&lt;/strong&gt; On record profiles, comments now display the &apos;Date:&apos; header consistent with email messages with an absolute and relative date. Previously this was only a relative date.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Drafts]&lt;/strong&gt; On &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draft&lt;/code&gt; records, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org_id&lt;/code&gt; can be provided instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org_name&lt;/code&gt; when there are duplicates.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 09 Jan 2026 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.6/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.6/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.5</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.5.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.5)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on September 30, 2025. It includes &lt;strong&gt;14&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;added&quot;&gt;Added&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[Mail/HTML/Images]&lt;/strong&gt; Added an image external URL allowlist to HTML email message security. When a pattern matches an image is displayed by default while others remain blocked.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[Platform/Stats/Performance]&lt;/strong&gt; When comparing vectors, cosine similarity now uses pure PHP rather than bcmath since the latter is much slower.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Validation]&lt;/strong&gt; Fixed an issue where validating a set of email addresses uppercased them rather than lowercasing. This was only used in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.email.relay&lt;/code&gt; automation API command.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/Email/Relay]&lt;/strong&gt; Fixed an issue in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cerb.email.relay&lt;/code&gt; automation API command that prevented relayed messages from sending.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Email]&lt;/strong&gt; Fixed a PHP notice in the &apos;Re:&apos; subject line tagging for non-reply message types (e.g. transactional).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Comments]&lt;/strong&gt; Fixed a rendering issue with comments in ticket threads. Comments are now converted from Markdown to HTML as untrusted and partial tags are escaped.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/HTML]&lt;/strong&gt; Fixed an issue in sent HTML messages. The de-duplication SHA-1 content was not being saved, which impacted the ability to download those files from the Support Center. &lt;a href=&quot;https://github.com/jstanden/cerb/issues/1820&quot;&gt;[#1820]&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Portals/Support Center]&lt;/strong&gt; In the Support Center, when displaying a conversation, attachments without an SHA-1 content hash are omitted as download links.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Behaviors]&lt;/strong&gt; Fixed an issue with &quot;Record worklist rendered&quot; behaviors where modified worklists didn&apos;t contain a notice and links back to the behaviors.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Parser]&lt;/strong&gt; Fixed an issue in the inbound email parser when a message contains multiple &apos;Message-Id:&apos; headers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Mail/Parser]&lt;/strong&gt; Fixed an issue in the inbound email parser when a message contains multiple &apos;In-Reply-To:&apos; or &apos;References:&apos; headers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Resources]&lt;/strong&gt; Added more error reporting when uploading resource files larger than the configured limits.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Widgets/Charts]&lt;/strong&gt; In &apos;Chart KATA&apos; widgets, fixed an issue where tooltips didn&apos;t display for negative y-values.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[Security/Composer]&lt;/strong&gt; Updated the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enshrined/svg-sanitize&lt;/code&gt; dependency from 0.15.4 to 0.22.0 in response to a security advisory.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 30 Sep 2025 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.5/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.5/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.4</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.4.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.4)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on August 04, 2025. It includes &lt;strong&gt;11&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Snippet]&lt;/strong&gt; Snippet dictionaries now include a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prompts&lt;/code&gt; key with structured data on the defined placeholder prompts.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Email/SMTP]&lt;/strong&gt; In the SMTP mail transport, added support for the &apos;PLAIN&apos; authenticator in addition to &apos;LOGIN&apos; and &apos;XOAUTH2&apos;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Search]&lt;/strong&gt; Fixed an issue with search query optimization (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_OPT_SQL_SUBQUERY_TO_IDS&lt;/code&gt;) on record filters where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; is a valid value (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;worker.id:&lt;/code&gt;). Empty result sets were converted to a zero value which unexpectedly matched unlinked records.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Worklists/Search]&lt;/strong&gt; Fixed an issue with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APP_OPT_SQL_SUBQUERY_TO_IDS&lt;/code&gt; query optimization with negated filters.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Merge]&lt;/strong&gt; Fixed a display issue when merging records with &apos;Decimal&apos; custom fields. The fields displayed without a floating point indicator.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Merge]&lt;/strong&gt; Fixed an issue with merging currency and decimal custom fields.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[KATA/Automations]&lt;/strong&gt; Fixed an issue in KATA parsing when using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@kata&lt;/code&gt; annotation. The value now properly evaluates its own annotations and placeholders.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Email/HTML]&lt;/strong&gt; Fixed an issue with secure links in HTML email messages where the content was wrapped in an inline-block which added scroll bars to elements like code blocks. Thanks to &lt;a href=&quot;https://www.knownhost.com/&quot;&gt;KnownHost&lt;/a&gt; for the bug report!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Email/Automations/UX]&lt;/strong&gt; Fixed an issue where &apos;Re:&apos; was prepended to the subject of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ticket.reply&lt;/code&gt; drafts created on empty tickets. The &apos;Re:&apos; tag is only added if a conversation has at least one message and the subject line doesn&apos;t already contain &apos;Re:&apos;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Email/UX]&lt;/strong&gt; Fixed an issue in plaintext email messages where the &apos;Expand quoted text&apos; button didn&apos;t display the quoted text in some situations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Database/Update]&lt;/strong&gt; Fixed several issues with database migrations from 9.x versions. Thanks to &lt;a href=&quot;https://github.com/Sn0wCrack&quot;&gt;Sn0wCrack&lt;/a&gt; for the contribution!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 04 Aug 2025 07:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.4/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.4/</guid>
        
        
      </item>
    
      <item>
        <title>11.1.3</title>
        <description>&lt;div class=&quot;cerb-screenshot&quot;&gt;
&lt;img src=&quot;/assets/images/releases/11.1/11.1.3.png&quot; class=&quot;screenshot&quot; width=&quot;500&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cerb (11.1.3)&lt;/strong&gt; is a &lt;strong&gt;maintenance update&lt;/strong&gt; released on June 17, 2025. It includes &lt;strong&gt;9&lt;/strong&gt; minor features and fixes from community feedback covering the &lt;a href=&quot;/releases/11.1/&quot;&gt;11.1&lt;/a&gt; update.  You can &lt;a href=&quot;/docs/upgrading/&quot;&gt;follow these instructions&lt;/a&gt; to upgrade.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;Changelog&lt;/h1&gt;

&lt;h2 id=&quot;added&quot;&gt;Added&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Automations/LLMs]&lt;/strong&gt; In automations, added a new &lt;a href=&quot;/docs/automations/commands/llm.chat/&quot;&gt;llm.chat:&lt;/a&gt; command for single-turn chat completions without transcripts, memory, or tools. For instance, this is useful for text classification or summarization tasks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Connected Services/Packages]&lt;/strong&gt; In the package library, added a connected service for Google Gemini. This prompts for an API key to access AI APIs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/LLMs]&lt;/strong&gt; Added a &apos;docker&apos; LLM provider. This uses local model containers in Docker Model Runner.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Platform/LLMs]&lt;/strong&gt; Added a &lt;a href=&quot;/solutions/integrations/gemini/&quot;&gt;gemini&lt;/a&gt; LLM provider. This uses Google&apos;s Gemini AI models.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Records/Card Widgets]&lt;/strong&gt; On &lt;a href=&quot;/docs/records/types/card_widget/&quot;&gt;card widget&lt;/a&gt; worklists, added a filter for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record:&lt;/code&gt; type.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;changed&quot;&gt;Changed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Profiles/Widgets]&lt;/strong&gt; On profile widgets, added more practical examples for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hidden@bool:&lt;/code&gt; option.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Plugins/UX]&lt;/strong&gt; Updated several plugin icons for consistent styling.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fixed&quot;&gt;Fixed&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Toolbars/Interactions]&lt;/strong&gt; Fixed an issue on &lt;a href=&quot;/docs/toolbars/interactions/draft.read/&quot;&gt;draft.read&lt;/a&gt; toolbars where interactions didn&apos;t trigger the common actions upon completion (e.g. alert, clipboard, search, snippet).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;[Toolbars/Interactions]&lt;/strong&gt; Fixed an issue on &lt;a href=&quot;/docs/toolbars/interactions/mail.read/&quot;&gt;mail.read&lt;/a&gt; toolbars where interactions didn&apos;t trigger the common actions upon completion (e.g. alert, clipboard, search, snippet).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 17 Jun 2025 19:00:00 +0000</pubDate>
        <link>https://cerb.ai/releases/11.1.3/</link>
        <guid isPermaLink="true">https://cerb.ai/releases/11.1.3/</guid>
        
        
      </item>
    
  </channel>
</rss>
