In Development: 12.0
Cerb (12.0) is a platform upgrade in development as of August 13, 2026. It includes more than 407 new features and improvements from community feedback.
To check if you qualify for this release as a free update, view Setup » Configure » License. If your software updates expire on or after June 30, 2026 then you can upgrade without renewing your license. Cerb Cloud subscribers will be upgraded automatically.
Important Release Notes
-
Cerb 12.0 requires PHP 8.5+ and MySQL 8.0+ (or MariaDB 10.5+).
-
To upgrade your installation, follow these instructions.
Added
AI agents
-
[Agents] Added AI workers. An agent is an ordinary worker record with an
is_aiflag rather than a separate record type, so it can own tickets, be@mentioned, join groups, and hold API credentials like anyone else. An AI worker never has an interactive session (logins and SSO are refused), and doesn't require an email address.
-
[Agent Models/LLMs] Added Agent Model 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 connected account for credentials, its context window, whether it accepts images, a display icon and color, and a block of provider-specific parameters. 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
Testbutton sends one short message to verify the credentials and model string before the record is used. -
[Agent Models/LLMs] The model ID field on an agent model record autocompletes. It starts from the IDs shipped with each provider, and a
Refreshbutton replaces those with your own account'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's in a list. Picking a model fills in the record's name, along with its description, context window, and image support wherever the provider publishes them. A refresh that fails says why, reporting the provider's own error rather than quietly falling back to the shipped list.
-
[Agents/Models/Router] Added Agent Model Router records. A router resolves to a list of models, so an automation can ask for a model without naming one and stay portable between installations. For instance, high-reasoning models, or models that support image inputs. One router can be flagged as the default and will be used when no model is specified.
-
[Automations] In automations, added the
llm.router:command. It resolves an agent model router to a list of models so a script can work with them as data. Omitrouter:to use the default router, then pass the result straight intollm.agent:. For instance, models can be filtered by capabilities or usage/rate limits (e.g., gracefully downgrade to a low-cost model if the high-cost one is overloaded). -
[Automations/Agents] The
llm.agent:command takes an optionalagent:input naming the AI worker a turn runs as. The transcript picks up that worker's name and image, and the turn inherits model routing from the agent record. A human or disabled worker is rejected.
-
[Automations/LLM]
llm.chat:accepts an agent model by name throughmodel: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't be referenced. -
[Interactions] Added the
agentPromptform element for worker interactions – the composer a worker types into when an automation runs an agent conversation. It supports@mentioncompletion 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.
-
[Agents] Added Agent Filesystem records – named volumes of files that agents and workers can both read and write. Each volume tracks its file count and total size.
-
[Agents/Automations] Agents can mount virtual filesystems through a single
agent_fstool. An automation lists the volumes to mount undermounts:, 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. -
[Agents] Agent filesystems are worked with using familiar file commands:
ls,find,cd,read,search,write,append,edit,copy,rm, andpwd. The same command set is available to an agent through its tool and to a worker through the Setup terminal, so the two can't drift. Command output can be piped through a Twig filter chain, and oversized output spools to a/tmpscratch area.
-
[Agents/Filesystem] Added ZIP bulk import for agent filesystems. Upload an archive and its files are imported by a background queue job, with progress shown on the filesystem record.
-
[Agents/Filesystem] Added an 'Agent Filesystem' card widget. It shows a volume's file count and size, imports a ZIP archive, and displays a history of past imports.
-
[Toolbars/Agents] Added the
agent.panetoolbar. The chats an editor's agent pane offers are now configured in Setup, including which editors each one appears in. -
[Interactions] Added the
uiCommandawait for driving a host editor from an interaction. An agent chat can read and write the editor it was launched beside. A singleawait:form:can carry several commands, each gated on what the agent actually asked for. -
[Automations/LLM] An
llm.agent:turn can join an existing conversation. A script mints one session id and hands it to the agent, the composer, and the transcript, so all three work on the same conversation instead of the agent starting its own. -
[Automations/LLM] Added transcript compaction for long agent sessions. A conversation that outgrows the model'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
compaction:. A worker can also fold a session on demand with/compact. -
[Automations/LLM] Agent turns can run off-request through a queue. A long turn survives navigating away and finishes in the background.
-
[Platform/LLM] 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.
-
[LLM/Providers] Added prompt caching for agent turns, on by default. A long conversation re-sends the same prefix every turn, and caching it cuts what that costs.
-
[LLM/Providers] Added per-turn token usage accounting. What each turn consumed is recorded and shown in agent transcripts, along with the conversation's current size and session totals that separate full-price input from cached reads and writes – so it's visible at a glance whether prompt caching is actually earning its keep on a long conversation.
-
[LLM/Providers] Standardized reasoning configuration on a canonical
effort:key plus a groupedthinking:block. One authoring form now drives reasoning across every provider that supports it. -
[LLM/Providers] Added image support to LLM chats. Images can be attached to a turn or pasted into an agent prompt, and they render inline in transcripts.
-
[LLM/Tools] Agent tools can define display
labels:(summary:andactive:) and anicon:for transcripts, so a tool call reads as "Searching the knowledge base" rather than as a raw function name. A label can also carry placeholders, resolved against that call'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 tohammer.
-
[Platform/LLM] Added a neutral
finish_reasonto LLM chat responses. This is what tells a truncated or interrupted turn apart from a completed one, and it's shown in the transcript viewer. -
[LLM/Providers] Added Qwen Cloud and z.ai as first-class LLM providers. Both appear in the provider list with their own endpoints, model hints, and brand icons.
-
[LLM/Providers] Updated the Claude model IDs offered by autocompletion for the Anthropic and AWS Bedrock providers.
-
[Toolbars/Search] A worklist 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's a win everywhere a worklist appears. Click the agent icon at the right of any search bar and a floating window opens over the list, offering the chats configured for it; pick one and the conversation starts there. The window can be dragged wherever suits you. The agent can read what's currently in the field, propose a replacement, write it back, and run it, and it can look up the record type'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 chats a search bar offers is configured in Setup, on the same
agent.panetoolbar the editors already use.
-
[Automations/Interactions] Added an
interaction.worker.agenttrigger for automations that drive an editor from an agent pane.interaction.internalexists 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 offeringuiCommand, which put a worker'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'sinteraction: uri:autocompletion lists agent interactions alongside ordinary worker ones. In every other respect it's an ordinary worker interaction – same form elements, same awaits, same resumable conversations. -
[Automations/Interactions] A parked conversation now describes itself in the lists that offer it back to you. Previously every one looked alike: the automation's own description on a generic clock icon, separated only by "Last active 18 hours ago". 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
llmTranscriptit also picks up the model provider'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 optionalresume:block to itsawait:form:withlabel:,preview:,icon:, orcolor:. Each is sticky – a key that evaluates empty keeps what was stored rather than clearing it, so a long agent turn can't blank the name of the conversation it belongs to. -
[Automations/Interactions] A failed agent turn now returns to the chat instead of ending the interaction. Until now any failure on a background turn ended the conversation with a generic "please try again", 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'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't leave behind a duplicate of a message the model never answered. Automation authors reach the same failure through the
llm.agent:node'son_error:branch, whose output var carrieserror_status,retryable, andretry_promptfor branching on the failure class. -
[LLM/Providers/Interactions] 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's own wait when it names one and backing off 5 seconds and then 15 when it doesn'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.
-
[LLM/Providers] 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'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's supported; add
stream@bool: noto a provider's block to turn it off, which is worth trying against an endpoint that doesn't stream correctly. -
[LLM/Providers] Ollama now streams responses. A streamed turn appears as it'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
stream_stall_secs. -
[LLM/Providers] In the Ollama provider, the Ollama Cloud API endpoint is now offered as a suggestion.
-
[LLM/Providers] Added token usage counts to the Ollama provider, so an Ollama turn reports what it consumed in transcripts like every other provider.
-
[LLM/Providers] AWS Bedrock 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.
-
[LLM/Providers] 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'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.
-
[LLM/Providers] AWS Bedrock now supports prompt caching on the models that offer it. Cerb checks your account's own model catalog to find them, so a model without caching is never sent a cache marker.
-
[LLM/Providers] 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
thinking:block and theeffort:key, and Bedrock ignored both, so a hard problem couldn't be given more thinking and a simple one couldn't be made cheaper. Both keys now work the way they do elsewhere:thinking:withtype: adaptiveon current Anthropic models ortype: enabledon older ones, andeffort: low|medium|high|xhigh|maxfor depth. On older models effort becomes a thinking budget sized to fit insidemax_tokens, and if there'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's autocompletion now offersthinking:,effort:, andstream@bool:. -
[LLM/Providers] AWS Bedrock now lists its available models when you create an agent model record. The list comes from your account's own Bedrock catalog and includes the cross-region inference profile IDs that most current Claude and Nova models require.
-
[LLM/Providers] When adding an agent model record, providers now suggest API endpoints as you type. This is particularly useful on AWS Bedrock, which uses regional endpoints.
-
[LLM/Providers] When listing models fails, the provider's own error message is now shown instead of a bare HTTP status code. On AWS Bedrock this names the exact IAM action that's missing.
-
[LLM/Providers] 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.
Automations
-
[Automations] New automations 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
cerb.automation.templateextension point, and the list gains a filter box once enough templates are installed to need one.
-
[Automations] Added a read-only control-flow graph for automations. It maps out a script's decisions, outcomes, and loops visually, which makes an unfamiliar or deeply nested automation far easier to follow. The graph appears in the editor's 'Visualization' tab and is also available as an 'Automation: Graph' 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.
-
[Automations] Added "Simulate initial state" for priming a test run from the automation editor. Test input is filled in as a form built from the trigger's inputs and the automation's own
inputs:, 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.
-
[Automations] Added a visual Form Builder for interaction
await:form:blocks. Form elements are assembled by dragging components onto a canvas that renders as the finished form, with the KATA generated beneath it as you build. A field'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's options.
-
[Automations/Editor] Added a "What changed" diff between a run's input and output in the automation editor's 'Run' tab. Previously you compared two YAML documents side by side and spotted the differences yourself; now the editor shows what the automation actually changed.
-
[Automations/Editor] Added least-privilege policy generation to the automation 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.
-
[Automations/Interactions] Worker interactions 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.
-
[Cerb UI] 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're easy to pick back up, and an entry carries its automation's description as a subtitle wherever one is set – which is a good reason to write them.
-
[Automation/Scripting/Functions] In automation scripting, added a
uuid()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 composer, and a transcript. -
[Automations/Scripting] In automation scripting, a new
|strip_pem_blocks()filter removes PEM blocks like PGP keys and SSL certificates. This is particularly useful when combined with the new search index functionality, or when otherwise sanitizing blocks of text. -
[Automations/Scripting] In automation scripting, a new
|strip_url_querystrings()filter removes the query string from URLs. This is particularly useful when combined with the new search index functionality or when otherwise sanitizing blocks of text. -
[Automations/Scripting] In automation scripting, a new
|strip_data_uris()filter removes base64-encoded content from data URIs. This is particularly useful when combined with the new search index functionality or when otherwise sanitizing blocks of text.
Queues
-
[Queues/Jobs] Introduced parallel queues with consumer extensions, FIFO ordering, and first-class queue jobs. Added a new
Extension_QueueConsumerextension point with built-in consumers (manual, internal, automation) for routing queue messages. Queue messages can be grouped under ajob_idto track progress against a queue job record with singleton keys, worker ownership, record-level count caches, and arbitrary metadata.
-
[Queues/Automations] Added automation-backed queues. 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.
1for expensive operations, and10-100+for batch operations). An automation is invoked with a batch of messages and inputs for the queue and optional queue job. Any non-error response is considered successful delivery. Like event listeners, the most appropriate automation can be selected programmatically based on the event. -
[Automations/Queues] Added the
queue.consumerautomation event to process messages from automation-backed queues. -
[Queues/Scheduler] The 'Background Queue' 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 queue jobs that are no longer being actively monitored.
-
[Queues] 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). Queue job 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.
-
[Queues/Performance] A new
APP_QUEUE_CONCURRENCY_SLOTSconfiguration option determines the maximum combined concurrency of worker-initiated queue jobs. This parallelizes, throttles, and timeshares queue job processing in high-volume environments to improve performance and UX. Slots are reserved using the MySQL writer connection and are automatically released when the connection closes. -
[Queues/Jobs] Queue Jobs 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's card displays its current progress until complete. A 'singleton_key' ensures certain jobs are only run once at a time (search re-indexing).
-
[Queues/Cards] Added a 'Queue Job Monitor' card widget for queue job records.
-
[Queues/Profiles] Added a 'Queue Job Monitor' profile widget for queue job records.
-
[Queues/Jobs/UX] Queue job monitor widgets display linked attachments directly. For instance, a worklist export's file appears on the job widget rather than only on the worklist marquee – workers can choose to view inline or download.
-
[Automations/Queues/Performance] Moved
record.changedevent processing into the parallel background queue. This particularly improves performance on bulk updates and imports. -
[Worklists/Import/Queues] Worklist file imports (CSV/JSONL) now run as a parallel background queue job instead of blocking the request. [#1408]
-
[Queues/Performance] Added a
queue_job_chunktable 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. -
[Worklists/Export/Queues] Worklist file exports (CSV/JSONL/XML) now run as a parallel background queue job 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. [#1837]
-
[Worklists/Bulk/Queues] Worklist bulk updates now use parallel background queue jobs 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.
-
[Queues/Jobs] Added
cardinalityto queue messages. This represents the work units per message. For instance, each message in therecords.bulk_updateorrecords.exportqueues may represent 100 record IDs. The queue job monitor reports progress in work units rather than raw message counts. -
[Queues/Jobs/Log] Added a permanent log for queue job 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
record_idsfor an audit trail. -
[Queues/Jobs] The queue job 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.
-
[Queues/Jobs] Queue jobs can now be canceled to immediately remove pending messages and end the job. Previously, jobs could only be paused or deleted.
-
[Metrics/Queues] Added a new metric
cerb.queue.messages.opengauge to snapshot available and in-flight message counts per queue. This helps identify stalled queues and backpressure. -
[Metrics/Queues] Added a new metric
cerb.queue.messages.processedcounter for done and failed messages per queue and job. -
[Queues] Queues 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
0disables retries for that queue and makes failures terminal. For instance, thecerb.storage.migrationsqueue 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. -
[Platform/Storage/Queues] Added a
cerb.storage.migrationsqueue covering the whole lifecycle of storage objects – migrations, archival, and deletions. Thecron.storagescheduler job now enqueues storage operations for parallel processing instead of performing them inline and blocking. -
[Platform/Storage/Queues] Storage schema deletions are now handled by the
cerb.storage.migrationsbackground queue rather than thedevblocks_storage_queue_deletetable, and existing rows are migrated to the queue on upgrade. This wasn't used by the 'disk' and 'database' storage engines, but it is by 's3'. -
[Queues] Queues now have a configurable 'claim window' – 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.
Search indexes
-
[Search/Records] Added a Search Index record type. Each index manages a linked custom search filter on any record type. New search index extensions can be implemented with plugins (e.g., TF-IDF, BM25, vector embeddings, Elasticsearch, Qdrant, Pinecone).
Previously, full-text search schemas required backend code and database changes (e.g., email content, comments).
A search index can be created on any combination of fields with a strategy specific to the use case; improving performance and efficiency.
For instance, a "sparse" 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.
Similarly, a search index can be created for a high-traffic custom field, or an arbitrary combination of fields (title + url + summary).
External resources (docs, KB, FAQ, websites) can be indexed using custom records and made available to workers and AI agents.
-
[Search/Full-Text] Implemented a local full-text search index extension that is optimized for performance and intended to replace MySQL'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
filter: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. -
[Search/Full-Text/Developers] 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 'AND' 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.
-
[Search/Records] On all record types, the default search filter is now configurable when no explicit
filter:is given by setting the priority of the search index 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. -
[Search/Full-Text] Added wildcard support to custom search indexes with asterisk (
*). This matches tokens in the vocabulary using OR for that term. For instance:11.1* release*to match11.1.6 releasedand11.1 release.
-
[Search/Full-Text] Added stemming support to custom search indexes with a tilde suffix (
~). This fuzzy matches tokens in the vocabulary using OR. For instance:automate~expands to: automate, automates, automation, automating, automated. -
[Search/Full-Text] Added support for excluded terms in custom search index queries by prefixing a term with a dash (
-). At least one included term is still required. For example,workflow -automationmatches documents that containworkflowwhile excluding any that also containautomation.
-
[Search/Full-Text] Search index filters send additional parameters through to extensions. For instance,
top:10for ranked results. -
[Search/Full-Text] Added support for
top:parameter to limit and rank results by score in full-text search queries. -
[Search/Full-Text] Added support for boosting TF-IDF scores using custom templates in full-text search indexes. This gives more relevancy to document titles, etc.
-
[Search/Scheduler] Updated the
searchscheduler job to handle custom search indexes. -
[Search/Queues] Search index cards now display indexing progress and have a re-index option to launch a background queue job.
-
[Search] Added search facets – 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; AI workers are the obvious case, since they're workers but "Workers" isn't where you'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't disturb the parent type's search.
-
[Metrics/Search] Added a
cerb.search.index.recordsgauge metric for counting records over time per search index and engine. -
[Platform/Search] Added on-demand search re-indexing for specific records, with a defer window for bulk writers. A record can be made searchable immediately after it's written rather than waiting for the next scheduler sweep, so a newly created record is findable right away.
Cerb UI
-
[Platform/Cerb UI] Added a modern, reusable Cerb UI 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
node_modules: whenDEVELOPMENT_MODEis enabled the individual scripts load fromcerberusweb.core/resources/js/cerb-ui/for real-time editing, andcomposer build-js(orcomposer dist) concatenates and minifies them into a singlecerb-ui.jsfor production. The first dozen components totaled around 35KB, compared to jQuery UI's 230KB+. -
[UI/Icons] Replaced Glyphicons with a modern, custom Cerb SVG icon set. 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
glyphicons glyphicons-*CSS classes were replaced withcerb-icons cerb-icon-*versions. The reference set was pared down to the icons actually used, with modern additions likebot. If a sheeticoncolumn specifies an unknown icon name,zapis now used as the default. If you've customized toolbar sections, update them to reference the new icon names.
-
[Cerb UI] Redesigned the ticket conversation view. Messages, drafts, comments, and notes now read as distinct entries with badged author avatars, aligned headers, and hover toolbars.
-
[Platform/Cerb UI] Added a
CerbUI.Dialogcomponent 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. -
[Cerb UI/Dialog] 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 'Restore all' 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.
-
[Cerb UI/Dialog] When two or more popups are minimized to the tray, its menu offers a 'Close all' shortcut.
-
[Cerb UI/Dialog] Added
Shift+Escto minimize the topmost dialog popup to the tray. -
[Cerb UI/Dialog] In
CerbUI.Dialog, added an opt-incloseWarnOnUnsavedChangesguard 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't lost to a stray click. Elements or whole subtrees can be excluded with adata-cerb-ui-dialog-no-dirtyattribute. -
[Cerb UI/Confirm] Added
CerbUI.Confirmas the modern replacement forconfirmPopup(), with a locked-down modal design and customizable title, body, buttons, and callbacks. -
[Platform/Cerb UI] Added a
CerbUI.Menucomponent 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. -
[Platform/Cerb UI] Added a
CerbUI.Tooltipcomponent for floating, auto-positioning tooltips with DOM-aware auto-hide and screen boundary handling. -
[Cerb UI]
CerbUI.Tooltipsupportspointmode for charts andanchoredmode for tutorials and callouts. Anchored mode accepts jQuery-stylemyandatrelative position strings, such ascenter top. -
[Platform/Cerb UI] Added a
CerbUI.Tabscomponent 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. -
[Platform/Cerb UI] Added a
CerbUI.Accordioncomponent for expandable and collapsible sections with keyboard navigation, callbacks, and scrollable panels. This replaces jQuery UI accordions. -
[Cerb UI] Added a
CerbUI.Sidebarcomponent for collapsible vertical navigation rails with sections, icons, and badges. Sidebar options can open internal or external links, fetch content dynamically likeCerbUI.Tabs, or run arbitrary callbacks. Apalettemode variant turns the rail into a library of item templates that can be dragged onto another element or canvas. -
[Cerb UI] Added a
CerbUI.Toolbarcomponent for configurable toolbar strips with buttons, menus, badges, and interaction support. It's the standalone successor to the jQuerycerbToolbar()plugin, and existing worker interactions keep working unchanged. -
[Cerb UI] Added a
CerbUI.SplitPanecomponent: 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. -
[Platform/Cerb UI] Added a
CerbUI.Sortablecomponent for drag-and-drop reordering. During a drag it shows both the item's original slot and the current insertion point, so where it will land is unambiguous. -
[Cerb UI] Added a
CerbUI.Draggablecomponent for lifting and dragging elements into designated drop zones. -
[Cerb UI] Added a
CerbUI.Droppablecomponent for defining drop zones that accept draggable elements. -
[Cerb UI] Added a
CerbUI.KataEditorcomponent to replace the Ace.js in-browser code editor for KATA. It provides KATA-aware syntax highlighting, contextual autocompletion, line numbering, gutter markers, code folding with fold-to-depth controls, indentation guides, find and replace onMod+F, comment toggling onMod+/, and clickablecerb: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 automations.
-
[Cerb UI/Editors] Introduced
diffGutteracross 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. -
[Cerb UI] Added a
CerbUI.JsonEditorcomponent 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. -
[Cerb UI/ScriptingEditor] Added a
CerbUI.ScriptingEditorcomponent for Cerb's Twig and KataScript template documents – email signatures, HTML and widget templates, and bot scripting – replacing the Ace Twig editors. It highlights embedded{{ }}and{% %}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. -
[Cerb UI/MarkdownEditor] Added a
CerbUI.MarkdownEditorcomponent – 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,@mentionautocompletion with rich avatar rows, inline image paste and upload, and find and replace. -
[Cerb UI] Added a
CerbUI.SearchQuerycomponent for building search queries with syntax highlighting and autocompletion, replacing the Ace editor. It understands Cerb'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. -
[Cerb UI/Search] Replaced Ace.js in the worklist quick search editor with
CerbUI.SearchQuery. -
[Cerb UI] In
CerbUI.SearchQuery, added colored field-type icons to the autocomplete suggestions menu, so the kind of field being suggested is obvious at a glance. -
[Cerb UI/DataQuery] Added a
CerbUI.DataQuerymulti-line editor component for data queries, with syntax highlighting for both the query syntax and embedded scripting tags, toolbars, and autocompletion. -
[Cerb UI/DiffViewer] Added a
CerbUI.DiffViewercomponent – a side-by-side KATA 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. -
[Records/Change History] Revamped the 'Change History' popup in the automation, event listener, and widget editors to use the new
CerbUI.DiffViewerrather than ace-diff. Any two revisions can now be compared, not just a revision against the current version, and a 'Restore this version' action copies the historical document back into the editor.
-
[Cerb UI] Added
CerbUI.SyntaxHighlightfor 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. -
[Cerb UI] Added a
CerbUI.RecordChoosercomponent 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's card on click. -
[Cerb UI] Added a
CerbUI.ContextChoosercomponent 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 'Owner' chooser can move between global, role, group, and worker without a separate control for each. -
[Cerb UI/TextChooser] Added a
CerbUI.TextChoosercomponent – a plain text input with optional endpoint-backed suggestions. It's the freeform sibling ofRecordChooserandContextChooser: accepting a suggestion just writes text, and any typed value is always allowed. -
[Cerb UI/ValuePicker] Added a
CerbUI.ValuePickercomponent for small, local option sets, replacing tall page-scrolling 'Multiple Checkbox' lists. Selections show as tags in the options' 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. -
[Cerb UI/TagInput] Added a
CerbUI.TagInputcomponent – a freeform tag field that replaces tall 'List' fields of repeating text inputs. Type and pressEnter(or comma) to turn text into a removable chip, paste to add several at once by splitting on newlines, tabs, or commas, pressBackspaceon an empty input to remove the last tag, and double-click a chip to rename it in place. -
[Platform/Cerb UI] Added a
CerbUI.SelectMenucomponent that enhances native<select>elements with searchable, styled dropdowns. -
[Platform/Cerb UI] Added a
CerbUI.Datepickercomponent for populating date inputs from a calendar. It also provides a free-text field that accepts natural language, parsed on the server – sonext tuesdayorin 3 daysworks as well as a date. -
[Cerb UI]
CerbUI.DatePickercan display indicator pips on the calendar for arbitrary datasets, so days that already have activity stand out before you pick one. -
[Cerb UI] Added a
CerbUI.ColorPickercomponent for Photoshop-style color selection with palette presets, hue, saturation, and opacity. This replaces the miniColors jQuery plugin. -
[Cerb UI/IconPicker] Added a
CerbUI.IconPickercomponent – a zero-dependency icon picker that turns a text input into a "well" button opening a floating, filterable grid of every Cerb icon, with full keyboard navigation and type-to-filter. -
[Cerb UI/ImageEditor] Added a
CerbUI.ImageEditorcomponent – an editable image "well" 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. -
[Cerb UI] 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.
-
[Cerb UI/FileUpload] Added a
CerbUI.FileUploadcomponent 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. -
[Cerb UI/Slider] Added a
CerbUI.Slidercomponent, 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. -
[Cerb UI] Added a
CerbUI.PriorityPickercomponent 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. -
[Cerb UI] Added a
CerbUI.Avatarcomponent 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. -
[Cerb UI] Added a
CerbUI.NodeEditorcomponent – 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.
-
[Cerb UI] Introduced
CerbUI.AgentPromptfor composing an agent turn, with@mentionautocompletion, image paste, and a model picker. It backs the agentPrompt form element in worker interactions. -
[Cerb UI/Agent Transcript] Introduced
CerbUI.AgentTranscriptfor 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. -
[Cerb UI] Introduced
CerbUI.AgentPane, a collapsible agent chat that sits beside an editor. It's available in the automation editor, the Bot Scripting tester, the Data Query tester, the Icon Builder, and mail Reply.
-
[Platform/Cerb UI] Added a
CerbUI.Switchercomponent for segmented toggles, withlocalStoragepersistence so a chosen segment survives a page reload, and programmatic selection. -
[Platform/Cerb UI] Added a
CerbUI.Togglecomponent for styled on/off switches with programmatic control and event callbacks. -
[Platform/Cerb UI] Added a
CerbUI.TimeRingcomponent for rendering SVG countdown and progress rings with customizable labels and dynamic updates. -
[Platform/Cerb UI] Added a
CerbUI.Spinnercomponent for reusable, pure-CSS animated SVG spinners, and integrated it into the header. -
[Cerb UI] Added new
CerbUI.Spinnervariants: arc, dots, and spark. -
[Cerb UI] Added a
CerbUI.datemodule of date and time formatters:remain()for countdowns (45s,2:05,20h,1d),ago()for elapsed time (just now,3m ago,2h ago), andstrftime()for lightweight formatting with GNU-style patterns. -
[Cerb UI] Added a
CerbUI.nummodule for number formatting in chips, legends, and stat values – compact counts (1500renders as1.5k), digit grouping, percentages, and humanized durations. -
[Cerb UI/Async] Added
CerbUI.utils.apply,CerbUI.utils.series, andCerbUI.utils.parallelLimitfor 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. -
[Cerb UI/Effects] Added
CerbUI.effects– small one-shot animation helpers (flash,transfer,pulse) that replace the cosmetic jQuery UI.effect('highlight'|'transfer'|'pulsate')API with CSS animations. Each isprefers-reduced-motionaware: it skips the animation and runs theonEndcallback synchronously, and arms a timeout fallback so a dropped animation event never strands the callback. -
[Cerb UI] Added
cerb-ui-formstyles for consistent form layouts with minimal markup. -
[Cerb UI] Added
cerb-ui-kbdstyles for rendering keyboard key caps. -
[Cerb UI/Separator] In Cerb UI separators, added optional arrows on the start and end lines, plus a
--thickvariant. -
[Cerb UI/Icons] Added
cerb-u-anim-*andcerb-u-anim-*-hovericon animation utilities, so an icon can animate continuously or only on hover. -
[Cerb UI/Icons] Added animated "magic gradient" styles for icons, including sweep, aurora, and cycle effects.
-
[CerbUI/Icons] Updated several editor toolbars for consistency, replacing the 'tags' icon with 'placeholders'.
-
[Cerb UI/Agents]
CerbUI.AgentPanecan 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'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.
-
[Cerb UI/Search]
CerbUI.SearchQuerycan 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.Ctrl/Cmd+Spaceis unchanged. -
[Cerb UI/Icons] Added brand icons for more LLM providers:
logo-azure,logo-deepseek,logo-meta,logo-mistral,logo-moonshot, andlogo-xai.
Charts and dashboards
-
[Cerb UI/Charts] Added
CerbUI.ChartandCerbUI.CartesianChartcomponents 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.
-
[Cerb UI/Charts] Added a
CerbUI.PieChartcomponent 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. -
[Cerb UI/Charts] Added a
CerbUI.ScatterChartcomponent for XY scatterplots with independent series on two continuous axes, including legend support, hover tooltips, and customizable interaction handlers. -
[Cerb UI/Charts] Added a
CerbUI.Gaugecomponent for single-value radial gauges with customizable thresholds that recolor the fill, plus a formatted center value and label. -
[Cerb UI/Charts] Added a
CerbUI.Timeblockscomponent for GitHub-style activity heatmaps, with rows as calendar days and columns as hours, hover tooltips, click events, and customizable color scaling.
-
[Cerb UI/Map] Added a
CerbUI.Mapcomponent for interactive SVG region and point maps 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's equivalents. Projections also pick a sensible default scale now, so choosingalbersUsano longer renders the map too small to read until you find a workable scale by trial and error.
-
[Platform/Cerb UI] Added a
CerbUI.Sparkchartcomponent 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. -
[Platform/Cerb UI] Added stacked bar charts to
CerbUI.Sparkchart– for instance, counting successes in green and failures in red as proportions of the same bar. -
[Platform/Cerb UI] Added a
CerbUI.Distbarcomponent 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. -
[Platform/Cerb UI] Added a
CerbUI.Legendcomponent for color-matched keys with dynamic data binding, palette support, and integration withDistbar. Swatches render as bars or lines in horizontal or vertical layouts. -
[Platform/Cerb UI] Added shared color palettes and an ordinal color scale to Cerb UI.
CerbUI.ColorScaleassigns 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. -
[Cerb UI/QR Code] Added a
CerbUI.QrCodecomponent for generating and rendering self-contained, scalable QR codes as SVGs with no external dependencies. -
[Cerb UI/Calendar] Added a
CerbUI.Calendarcomponent 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. -
[Cards/Widgets/Calendar] Added a configurable 'Calendar' card widget with multi-view displays and linked calendars.
-
[Cards/Widgets/Charts] Added a 'Chart: KATA' card widget type, bringing the full Chart KATA visualizations to record cards. This was previously only available on workspace widgets.
-
[Profiles/Widgets/Charts] Added a 'Chart: KATA' profile widget type, bringing the full Chart KATA visualizations to record profile tabs. The widget resolves
record_placeholders against the profile's record, renders in light or dark mode per the viewer's preference, and offers the same dataset and chart KATA autocompletion and live preview testers in its config as the other Chart KATA widgets. -
[Metrics/Cards] Added a 'Chart: Metrics Explorer' card widget – an interactive, client-side metric 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
metrics.timeseriesdata query, an importable 'Chart: KATA' widget, or an explorer config.
Tasks and projects
-
[Daily Task Boards] Added a Daily Task Board workspace tab – a personal, day-oriented planning board built on real task records and task projects. Unlike project boards, nothing board-specific is stored: every column and day placement is derived from a task's status, active flag, importance, and completion or wake dates, so the board and the underlying tasks can never disagree.
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's TODO once its "stashed until" date passes.
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's meta strip shows the assignee avatar with an "assign to me" claim. 'Jump to Date' renders any off-window day on demand, with month pips marking which days carry completed or waiting tasks.
Quick Triage deals a lane out as a stack of cards and sorts it one keystroke at a time: raise or lower a task's importance by one – or by five holding
Shift– 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's left, and a shuffle re-deals the remainder. It's offered on the TODO column and the Stash, the two places where a pile actually needs sorting.
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 "focus my tasks" preference. A task's permissions derive from its project, and archived or unreadable projects are dropped from the board gracefully.
-
[Tasks/Projects] Added a 'Task Project' record type for grouping related tasks together and sharing ownership. Tasks gain a project and an active flag, and a project's permissions carry through to the tasks inside it.
-
[Tasks/Projects] In task project worklists, added a 'Tasks' distribution bar column showing how a project's tasks are split between done, stashed, todo, and in-progress – so a project that has quietly stalled is visible without opening it.
-
[Tasks/Projects] In task project worklists, added a
tasks: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. -
[Tasks] The
titlefield on task records may now contain 4-byte emoji characters.
Setup and developers
-
[Setup/Records] In Setup » Records 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 'Search' menu. The old 'Custom Fields' and 'Snippets' items were removed from the 'Records' menu since both are better reached elsewhere.
-
[Setup/Automations] A new Setup » Developers » Automation Events overview shows the sequence of every event flow – "On new inbound mail", for instance – as a node graph of each automation 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 "what actually runs when mail arrives, and in what order?"
-
[Setup/Toolbars] Added an overview of every customizable toolbar in Setup » Developers » Toolbars, listing sections by toolbar and by managing workflow. Clicking a toolbar item opens its associated automation or behavior editor.
-
[Platform/Cerb UI/Developers] Added a 'UI Reference' section to Setup » Developers showcasing the full Cerb UI component library with interactive examples, variants, code snippets, and documentation, navigable from a sidebar.
-
[Setup/Developers] Added an Icon Builder for authoring
cerb-iconsglyphs. 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.
-
[Setup/Developers] Added a visual Sheet Builder. Sheet 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's also available from the Form Builder's sheet element, where it loads the existing sheet and writes your changes back.
-
[Setup/Developers] Added an Agent Filesystem Terminal for browsing and editing agent volumes with the same commands an agent uses, so what a worker sees and what an agent sees can't drift apart.
-
[Setup/Developers] 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'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.
-
[Setup/Developers] Reworked the LLM Agent Transcripts browser. Transcripts are listed in a sidebar with Active and Archived filtering and per-transcript actions.
-
[Setup/Developers] 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.
-
[Setup/Developers] An LLM agent transcript now shows the filesystem volumes 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
agent_fsand 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's file count and size, and whether the agent had read-only or read-write access./tmpis listed too, since an agent reads and writes it like any other mount – as per-run scratch rather than a stored volume, it'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'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.
-
[Setup/Developers/Icons] In the 'Icon' component of Setup » Developers » UI Reference, icons can be filtered by name, a 'Show labels' toggle switches between a compact grid and named icons, and clicking an icon copies its HTML fragment to the clipboard.
-
[Scheduler/Setup] Completely redesigned the Setup » Configure » Scheduler page with Cerb UI components. Deployment options are separated into 'Development' and 'Production': the Development section has an 'Auto-Run' option that runs jobs entirely in the browser, with a countdown ring showing the next interval, and the Production section carries an example
/cronrequest using service tokens. Per-job metrics for runs and duration are displayed with a range toggle, and the 'edit' and 'run now' actions open in a popup.
-
[Setup/Storage] Redesigned Setup » Storage 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.
-
[Setup/Storage] In Setup » Storage, a new button starts a migration of objects between storage profiles. Previously objects only moved from the active to the archive profile via the
cron.storagescheduler 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 queue jobs. -
[Setup/Avatars] 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.
-
[Setup/Storage] In Setup » Storage, removed the 'Objects' page. It was exactly the same as Search » Attachments.
-
[Setup/Records] In Setup » Records, removed the 'Snippets' page. It was exactly the same as Search » Snippets.
Worklists
-
[Worklists/UX] When customizing a worklist, 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'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.
-
[Worklists/Sparklines] Added generic 'Sparklines' and 'Distbar' columns to worklists, along with parameterized metrics 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't shown. Because the underlying metrics are queryable, each one also brings a matching quick search filter that accepts
since:anduntil:– the sections below list what each record type exposes.
-
[Worklists/Automations] Added a 'Usage' sparklines column to automation worklists showing runs, errors, and duration, plus a
usage:quick search filter backed by thecerb.automation.invocationsandcerb.automation.durationmetrics. For instance,usage:(runs:>0 since:today)returns automations that ran at least once today, andusage:(runs:>1000)returns those that have run more than a thousand times. -
[Worklists/Automations/Events] Added a 'Usage' sparklines column and a
usage: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. -
[Worklists/Bots/Behaviors] Added a 'Usage' sparklines column and a
usage:quick search filter to bot behavior worklists, showing runs and duration from thecerb.behavior.invocationsandcerb.behavior.durationmetrics. -
[Worklists/Mailboxes] Added a 'Usage' sparklines column and a
usage:quick search filter to mailbox worklists, showing messages received and protocol errors. For instance,usage:(errors:>0)returns mailboxes that have ever had an error, andusage:(received:>0 since:today)returns those that pulled mail today. -
[Worklists/Mail Routing Rules] Added a 'Usage' sparklines column and a
usage: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. -
[Worklists/Mail Transports] Added a 'Usage' sparklines column and a
usage:quick search filter to mail transport worklists, showing deliveries and failures. -
[Worklists/Queues] Added an 'Activity' sparklines column and an
activity:quick search filter to queue worklists, showing done, failed, and open message counts so a backing-up queue is visible without opening it. -
[Worklists/Search Index] Added a 'Records' sparklines column and a
records:quick search filter to search index worklists, tracking indexed record counts over time. -
[Worklists/Service Tokens] Added a 'Usage' sparklines column and a
usage:quick search filter to service token worklists, tracking authentications – which surfaces both unused tokens and unexpected spikes. -
[Worklists/Snippets] Added a 'Usage' sparklines column and a
usage:quick search filter to snippet worklists, tracking how often each snippet is used. -
[Worklists/Webhooks] Added a 'Usage' sparklines column and a
usage:quick search filter to webhook listener worklists, tracking invocations. - [Worklists/Metrics] Added a 'Dataset' sparklines column to metric worklists displaying min, max, average, sum, and count. It adapts automatically to counters versus gauges, so each metric is charted the way it's meant to be read.
-
[Worklists/Import] Records can be imported into worklists using JSONL files. Previously this only supported CSV.
-
[Worklists/Import/UX] When importing CSV/JSONL files into worklists, 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.
-
[Worklists/Search] Added a
comments: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 search index record type. -
[Worklists/Sessions/Subtotals] Added subtotals to the user sessions worklist: worker, ip address, and user agent.
-
[Worklists/Bulk/Comments] Added bulk commenting to the worklist 'Bulk Update' popup for every record type that supports comments (tickets, tasks, organizations, opportunities, time tracking, domains, servers, calls). [#1602]
- [Worklists/Comments] Added bulk delete to comment worklists. Admins can delete any comment; non-admins are limited to their own via per-record ACL. [#857]
Metrics
-
[Metrics] A retention policy 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. [#1554]
-
[Data Queries/Metrics] Added a
metrics.subtotalsdata query type for flat metric subtotals read directly from samples. This is the inverse projection ofmetrics.timeseries– instead of values over time it returns the raw dimension values, which can then be composed into other queries such as subquery worklist filters. -
[Data Queries/Metrics] In
metrics.timeseriesdata queries, added support for negating dimension filters – for instance, on thecerb.tickets.openmetric, every ticket sample wheregroup_id != 1. This makes proportional stacked bar charts straightforward: one dimension versus all the others. -
[Data Queries/Tickets] In
worklist.subtotalsdata queries,of:ticketnow supportsby:sender.firstandby:sender.last. Autocompletion had been suggesting these keys, but using one returned an "Unknown by: field" error. -
[Metrics/Mailboxes] Added a
cerb.mail.mailbox.receivedcounter metric tracking downloaded messages per mailbox. -
[Metrics/Mailboxes] Added a
cerb.mail.mailbox.errorscounter metric tracking protocol errors per mailbox, with a status dimension that breaks errors down by status code – invalid authentication, for instance.
Workspaces
-
[Workspaces] Added auto-refresh to worklist and widget tabs. A dashboard 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't. It stays on for as long as you're on the tab rather than being remembered as a preference, so a tab always opens with it off.
An auto-refreshing page that reloads while you'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't count as interrupting, so a parked peek won'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.
-
[Widgets/Worklists] On profiles and workspaces, 'Worklist' 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.
-
[Workspaces/Worklists] When a workspace widget's configuration changes, its worker-level cache is now cleared. This keeps workflow-managed worklists from diverging – previously a worker could keep seeing the old columns or query after the managing workflow had updated the widget.
-
[Workflows] When a workflow 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.
-
[Workflows/UX] Revamped the
cerb.quickstartonboarding workflow for 12.0, replacing the checklist approach with a guided setup tour, streamlining step navigation, and improving contextual guidance. The 'Guided Setup' interaction is now reachable from the global menu. -
[Workflows/Tutorial/UX] 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.
Service tokens
-
[Service Tokens] Added 'service tokens' for anonymous privileged endpoint access (/cron, /debug, /update). This deprecates IP-based allowlists. A service token can be included in an
Authorization: BearerHTTP header or an_authorizationHTTP 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 usingAPP_SERVICE_TOKEN; which is particularly useful for/updatesince logins would be blocked until the update has finished. Service tokens are managed from Setup » Configure » Security.
-
[Service Tokens/Metrics] Added a
cerb.service.token.usesmetric counter for tracking service token authentications. -
[Security/Service Tokens] When the
APP_SECURITY_ALLOW_ADMIN_SESSION_TOKENconfig option istrue(default), existing admin sessions can be used to authenticate/updateand/cron. Disabling the option always requires a service token.
Scheduler
-
[Scheduler/Background] Added a new
Background Queuescheduler job to process events asynchronously. -
[Scheduler/Parallel] Scheduler jobs can now be flagged as
parallelin their extension manifest (e.g. the Background Queue). These jobs limit by concurrency rather than locking during operation, which enables more real-time background functionality compared to traditional cron jobs. -
[Metrics/Scheduler] Added a new metric
cerb.scheduler.invocationsto count scheduler runs by job. -
[Metrics/Scheduler] Added a new metric
cerb.scheduler.durationto track scheduler execution duration by job.
Security
-
[Security/Workers/MFA] Added backup codes to worker accounts when multifactor authentication (MFA) is enabled.
Plugins
-
[Setup/Plugins/UX] Revamped plugin configuration in Setup » Configure » Plugins. 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 'Link' 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 workflows as the preferred path for most user-level extensibility.
Miscellaneous
-
[Storage/Profiles/S3] The 'S3' storage profile now accepts a host with an optional
https://orhttp://protocol and a non-standard port. This makes it possible to use S3-compatible object storage like MinIO (in self-hosted, local network, or development environments), Google Cloud Storage, and others rather than requiring Amazon S3.
-
[Connected Accounts/AWS] In 'Amazon Web Services' connected accounts, added an "Allow requests to non-AWS endpoints" 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.
-
[Notifications/UX] The unread notifications bell in the top right now occasionally plays a silent 'ring' animation to draw attention to waiting notifications.
-
[Metrics/Sessions] Added a new metric
cerb.sessions.seat.kicksto track worker session terminations for freeing up license seats. -
[Metrics/Sessions] Added a new metric
cerb.sessions.seat.kicks.durationto track session age when a worker session is terminated to freeing up license seats. -
[Records/Workers] Added a
created_atfield toworkerrecords. -
[Groups/Activity Log] The activity log now records when group members are added or removed. [#246]
-
[Workers/Activity Log] The activity log now records when workers are activated or deactivated. [#824]
-
[Sheets/Code/KATA] Added syntax highlighting for
kataincodecolumns of sheets. -
[Installer/UX] Added default card and profile widgets to several record types that previously lacked them: automation, automation event, automation event listener, automation timer, gpg_private_key, gpg_public_key, queue, resource, search index, service token, toolbar, and toolbar section records.
-
[Records/Icons] Added a default icon to every record type, displayed on card popups and profile pages so a record's type is identifiable at a glance even when it has no profile image.
-
[Records/Widgets/Icons] Added default icons to all card, profile, and workspace widget types. This gives a visual cue in configuration menus and on dashboards, and the icon can be overridden per widget.
-
[Cerb UI] Added icons to package library records. Packages now show a glyph in the library and in choosers instead of a generic placeholder.
-
[Records/Autocomplete] 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.
-
[Comments/Notifications] When replying to a comment, the original author's
@mentionis prefilled automatically, so a reply notifies the person you're replying to without having to remember to tag them. -
[Bots/Behaviors] Legacy bot behaviors now track a change history the way automations do. From a behavior tree, click the event and choose 'Edit History' to compare any two revisions in the diff viewer.
-
[Data/Records] Added an
only_customfilter to complementexclude_custominrecord.typesdata queries. -
[Connected Services/UI] Added profile images to connected service records. The image is displayed on the login form's SSO buttons and in the connected service profile and worklists.
-
[Connected Services/Packages] Added a "Microsoft Entra ID" package that sets up the OAuth2 connected service 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
offline_accessscope 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't match Cerb exactly, and client secrets quietly expiring after six months. -
[Connected Services/Packages] Added a "Microsoft Foundry" package that sets up an API key connected account 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'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 agent model, the endpoint is your resource's OpenAI base URL and the model is your deployment name rather than the underlying model name.
Changed
-
[Automations/KATA] In KATA, a
type/name: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 as0wherever it was read back, because{{a-b}}is the subtractiona - brather 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 –inputs:,await:form:elements:, snippet and dashboard prompts, worklist export columns, and LLM toolparameters:– and is available declaratively asnameFormat: variable. The parser still allows the wider character set elsewhere, since most names are labels or handles that are never read back as placeholders. -
[UI/Tabs] Tweaked the style of tab sets throughout the interface.
-
[Cerb UI] Ported popups from jQuery UI dialogs to
CerbUI.Dialog. 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. -
[Cerb UI] 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.
-
[Records/Cards/UI] 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.
-
[Cards/Cerb UI] 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.
-
[Profiles/Cerb UI] 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.
-
[Cerb UI/Automations] Rebuilt the automation editor on Cerb UI. The script and policy panes are now Cerb's own KATA editor instead of Ace, and the template picker, form builder, and agent chat are reachable for the first time.
-
[Cerb UI] Ported chart widgets to
CerbUI.Chart. Charts now render through Cerb's own components instead of c3.js and d3.js. -
[Cerb UI] Ported calendars to
CerbUI.Calendar. Calendar widgets render in day, week, month, and year views through Cerb'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.
-
[Cerb UI] 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.
-
[Cerb UI/Search] Refactored the global search menu to use modern Cerb UI components, added record-type icons, and improved keyboard filtering.
-
[Widgets/Fields/Cerb UI] Improved the display and configuration of 'Record Fields' card, profile, and workspace widgets. The 'Fields' 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.
-
[Setup/UI] Redesigned the Setup 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.
-
[Platform/Debug] Removed the
DEVELOPMENT_MODE_ALLOW_DEBUGconfig option. This is replaced by service tokens. -
[Platform/Auth] Deprecated the
AUTHORIZED_IPS_DEFAULTSIP allowlist for/cron,/debug, and/update. This is replaced by service tokens, which work regardless of where the request originates. -
[Docker] Updated the Docker examples to use
CERB_SERVICE_TOKENrather than client IP validation. -
[Docker] Updated the Docker examples with automatic configuration from
.env. -
[Docker] Added support for customizable environment and port variables in Docker Compose.
-
[Docker] Bumped the PHP-FPM
pm.max_childrendefault from5to10. This makes it easier to handle parallel queue processing at full capacity. -
[Search/Automations] Converted the automations full-text index to a search index record so it can be fully customized or removed.
-
[Search/Comments] Converted the
comments:filter on record worklists and thenotes:filter on message records into customizable search index records. Previously these were hard-coded MySQL FULLTEXT indexes. -
[Search/Contacts] Converted the contacts full-text index to a search index record so it can be fully customized or removed.
-
[Records/Email Address] On email address record dictionaries, added the
aliaseskey to access that data from functionality like sheets and automations. -
[Search/Knowledgebase] Converted the knowledgebase articles full-text index to a customizable search index record so it can be fully customized or removed.
-
[Search/Mail/Content] Converted the message content full-text index to a customizable search index 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.
-
[Search/Mail/Headers] Converted the message email header filters (
header.cc:,header.cerbMailbox:,header.deliveredTo:,header.from:,header.to:,header.mailer:,header.forwardedTo:) into customizable search index records. Each environment can add additional header filters or drop ones they don't use. New installations no longer create them by default. Previously these were indexed in MySQL/InnoDB much less efficiently. -
[Search/Orgs] Converted the organizations full-text index to a search index record so it can be fully customized or removed.
-
[Search/Snippets] Converted the snippets full-text index to a search index record so it can be fully customized or removed.
-
[Search/Tickets] On ticket worklists, the default search filter is now
messages(backed by the new search index for message content). This behaves like the previous full-text default but no longer requires backend code – admins can fully customize what's indexed. -
[Search/Workers] Converted the workers full-text index to a search index record so it can be fully customized or removed.
-
[Mail/Parser/Filters] In the inbound email parser, mail.filter automations 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.
-
[Records/Contacts] On contact record dictionaries, added the
aliaseskey to access that data from functionality like sheets and automations. -
[Records/Workers] On worker record dictionaries, added the
aliaseskey to access that data from functionality like sheets and automations. -
[Installer/UX] Modernized the style of the web-based installer.
-
[Installer/UX] In the guided installer, the first input on each step is automatically focused to improve usability.
-
[Login/UI/UX] Restyled the login flow to match the modern dark-mode aesthetic.
-
[UI/Styles] Replaced the old bitmap icons on
emailandpasswordtext inputs with modern inline SVGs. -
[Worklists/Search] In worklist search queries, when specifying a
sort: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. -
[Mail/Compose/UX] Added validation for invalid email addresses in
to,cc, andbccfields when composing a new email message from ticket worklists. -
[Mail/Reply/UX] Added extra validation for invalid email addresses in
to,cc, andbccfields when replying to a ticket. This catches common errors likecustomer@example,com. -
[Automations/Interactions] 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 queue, 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'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.
-
[UI/Performance] Optimized the generation of deeply nested placeholder menus.
-
[Maint/Workers/Watchers] Nightly maintenance now clears watcher links on deactivated workers. [#823]
-
[Branding/UI] The user-defined logo and stylesheet are now served from new
/branding/logo,/branding/logo-dark, and/branding/stylesheetendpoints instead of/resource/cerberusweb.core/css/*. This lets CDNs and caching layers treat/resource/*as immutable non-shared static content. [#1135] -
[Records/Custom Fields] 'Text block' custom fields now support 4-byte UTF-8 characters (e.g. emoji). The underlying
custom_field_clobvalue.field_valuecolumn was migrated toutf8mb4with collationutf8mb4_unicode_ci. -
[UI/UX] In dark mode, the
color-schemeCSS property is now set so the browser renders native UI components (scrollbars, form controls, dropdowns) with a matching dark palette. -
[Automations/Scripting] In automation scripting, the
|csvfilter will now attempt to convert objects/dictionaries to arrays. Previously, this always failed if the input wasn't already an array. -
[Automations/Queues] In automations, the
output:parameter ofqueue.push:is now optional. It's only needed when you want to capture the resulting queue message IDs. -
[Storage/S3/Performance] The 'S3' 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.
-
[Security/Storage/AWS] Secrets in 'S3' storage profiles are now stored in encrypted connected accounts rather than in the storage profile configuration. Existing profiles are migrated automatically on upgrade.
Deprecated
-
[Plugins/Files/Bundles] Moved 'File Bundle' records into an optional
cerb.file_bundlesplugin 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. -
[Bots/Behaviors/Deprecations] Moved legacy bot behavior functionality into an optional
cerb.behaviors.legacyplugin. 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.
Removed
-
[Portals/Support Center/Templates] Removed custom HTML templates from community portals like the Support Center. 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
APP_OPT_DEPRECATED_PORTAL_CUSTOM_TEMPLATESconfig option was also removed. -
[Worklists] Removed the 'copy' option from legacy worklists, which duplicated a worklist to a new workspace. The modern export/import functionality should be used instead.
-
[Workspaces/UI] Removed the 'Display tabs as' option on workspace pages.
-
[Scheduler/Migrations] Retired the 'cron.migrations' scheduler job since it was only used once in 10.4 (Feb 2022).
-
[Scheduler/Metrics] Retired the standalone 'cron.metrics' scheduler job since this is now handled by
cron.background_queue. -
[Platform/Plugins] Removed the
cerberusweb.plugin.setupextension point and theExtension_PluginSetupparent class. No remaining plugins implemented setup steps, and removing the extra step enables single-click plugin enable/disable from the Setup » Configure » Plugins worklist. The 'uninstall' action was also removed from the GUI – plugin removal is now a filesystem operation. -
[Setup/Search] Removed the 'Search' page from Setup » Configure. Search engines and schemas are now configured directly on search index records, where each index can be independently tuned, paused, and re-indexed.
-
[Platform/Search] Removed the
devblocks.search.engineextension point and theExtension_DevblocksSearchEngineparent class (along with the bundledDevblocksSearchEngineMysqlFulltextandDevblocksSearchEngineElasticSearchengines). Custom search backends are now implemented as search index extensions, which integrate directly with worklist filters and the background queue. -
[Platform/Search] Removed the
devblocks.search.schemaextension point and theExtension_DevblocksSearchSchemaparent class. Per-record full-text schemas are now expressed as search index records and can be created or modified without code changes.
Fixed
-
[Devblocks/Registry] Fixed an issue in the Devblocks
registryservice where a key wasn't deleted from backend storage if it hadn't been loaded. -
[Profiles] Fixed an issue on profile pages where a newly created tab couldn't be selected until the page had been reloaded.
-
[Mailboxes] Fixed an issue where a mailbox's consecutive failure count could exceed the field's range of 0–127.
-
[Worklists/Search] In worklist search autocomplete, fixed an issue with hybrid text and parameterized filters such as
created:, where accepting a suggestion broke any further suggestions on that filter. -
[Data Queries] Fixed an issue with
worklist.subtotalsdata queries when grouping time-series data by@quarteror@quarterofyearagainst a 'date' custom field. -
[Bots/Behaviors] 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.
-
[Resources/Storage] Fixed a bug in Setup » Developers » Platform where reloading resource records that used a non-local storage profile, such as S3, reset the storage engine to 'database' without also resetting the profile ID.
-
[Storage/Schemas] Fixed an extension ID inconsistency between the
Storage_RecordChangesetclass and its plugin manifest. -
[Automations/UX] Updated
cerb.reply.isBannedDefunctto ignore senders on outgoing messages. -
[Time Tracking/Roles] Workers without the time tracking
updateprivilege can no longer close entries from the worklist. [#901] -
[Calendars] 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'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.
-
[Workspace/Widgets/Calendar] Fixed exporting CSV/JSON from calendar workspace widgets.
-
[Workspace/Widgets/TimeBlocks] Fixed CSV exports in Time Blocks workspace widgets.
-
[Workspaces/Widgets] Fixed URL datasource caching for legacy workspace widgets. Previously, the cache was always disabled and didn't invalidate immediately if the URL changed.
-
[Sheets/Export] Fixed an issue with sheets when exporting CSV data from workspace widgets for unknown column types or null values.
-
[UI/Styles] 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.
-
[Login/UX] 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.
-
[Support Center/Profiles] Fixed an issue in the Support Center portal where the stricter Content-Security-Policy prevented the avatar image editor from working.
-
[Platform/Worklists] A failed worklist refresh no longer blanks the list. Creating or editing a record from a chooser popup could leave that popup'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.
-
[Integrations/AWS] Fixed the "Get pre-signed URL" 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.
-
[LLM/Providers] 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.
-
[LLM/Providers] 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.
-
[LLM/Providers] 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.
Platform
-
[Platform/PHP] Updated the minimum required PHP version to 8.5.
-
[Docker] Updated the Dockerfile to Ubuntu 26.04 LTS and PHP 8.5.
-
[Platform/Dependencies] Updated the
css-to-inline-styleslibrary from v2.2.4 to v2.3.0. -
[Platform/Dependencies] Updated the
twiglibrary from v3.8.0 to v3.26.0. -
[Platform/Composer/Twig] Replaced our forked Twig dependency with the official
twig/twigpackage. Rather than maintaining a patch against their source for ourDevblocksDictionaryDelegatefallback on undefined variables, we now overrideEnvironmentandContextVariableand implement a_DevblocksUndefinedVariableNodeVisitor. A new test suite catches regressions. This makes it much easier to follow Twig's official updates and security notices. -
[Platform/Services/AWS] Added an
awsservice to the platform that consolidates AWS functionality like request signature generation. It's used by connected accounts forhttp.request:and by storage profiles for S3-compatible storage backends. -
[Platform/Dependencies] Removed the legacy 'Amazon S3 PHP Class' library. This functionality is now handled entirely within Cerb by the new
awsservice. -
[Platform/Dependencies] Removed the Glyphicons icon font in favor of the new custom Cerb SVG icon set.
-
[Platform/Dependencies] Removed the
async.jslibrary in favor of the new Cerb UI async utilities. -
[Platform/Dependencies] Removed jQuery UI. Cerb now implements its own component library. (jQuery itself is still present – only jQuery UI 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.
-
[Platform/Dependencies] Removed Ace.js and ace-diff. Cerb now implements its own code editors and diff viewer in Cerb UI.
-
[Platform/Dependencies] Removed the D3.js library. It was used for visualizations that
CerbUI.Chartnow handles. -
[Platform/Dependencies] Removed the
c3charting library, along with the legacyjquery.devblocksChartsplugin. Cerb UI now handles this functionality natively. -
[Platform/Dependencies] Removed the TopoJSON library.
CerbUI.Mapdecodes and projects TopoJSON itself. -
[Platform/Dependencies] Removed the Dagre-D3 library. It was used for the directed graphs in the automation editor's 'Visualization' tab, which the new
CerbUI.NodeEditorand node graph components now provide. -
[Platform/Dependencies] Removed the miniColors jQuery plugin, replaced by
CerbUI.ColorPicker. -
[Platform/Cerb UI/Developers] Removed the legacy jQuery plugins and shims that Cerb UI supersedes, including
.cerbCodeEditor,.cerbPropertyGrid,.cerbQueryTrigger,.cerbChooserTrigger, thecerbTextEditorfamily,jquery.qrcode,Devblocks.tooltip, andDevblocks.selectValue. If a third-party plugin calls any of these, it will need updating to the Cerb UI equivalents. -
[Platform/XML] Added a
DevblocksPlatform::parseXml()helper that suppresses errors while parsing XML. -
[Platform/Dependencies] Upgraded the
lcobucci/jwtlibrary to v5.6.0 and theleague/oauth2-serverlibrary to v9.3.0 for PHP 8.5 compatibility. -
[Platform/Dependencies] Upgraded the Horde IMAP library from v2.30.6 to v2.34.1 for PHP 8.x support.
-
[Platform/Dependencies] Added a PorterStemmer class for stemming tokens in search indexes. Credit to Richard Heyes (phpguru.org).
-
[Platform/Search/Developers] Added a
searchservice to the Devblocks platform. This handles common functionality like tokenization, stop words, hashing, stemming, and indexing. -
[Platform/Developers/Tests] Upgraded phpUnit from 9.6.34 to 12.5.33.
Security
-
[Support Center/Security] In the Support Center portal, added a stricter Content-Security-Policy that requires nonce tokens for scripts and removes
unsafe-inline. -
[Security/Markdown] 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.
-
[Security] HMAC-signed all cache engine payloads (disk, Redis, Memcached) to prevent deserialization of attacker-controlled data.
-
[Security/Composer] Pinned Composer dependencies to audited versions.
-
[Queues/Jobs/Security] Tightened permissions on queue jobs so only the initiating worker and admins can view a job's details or its file attachments.
-
[Security/Dependencies] Updated
symfony/mailerto v7.4.12 in response to a security advisory. -
[Security/Dependencies] Upgraded
guzzlehttp/guzzleto v7.15.3 in response to security advisories. -
[Security/Dependencies] Upgraded
phpseclib/phpseclibto v3.0.54 in response to a security advisory. -
[Security/Dependencies] Upgraded
smarty/smartyto v4.5.7 in response to a security advisory. -
[Security/Dependencies] Upgraded
league/commonmarkto v2.9.1 in response to a security advisory. -
[Security/Dependencies] Upgraded
phpunit/phpunitto v12.5.33 in response to a security advisory. -
[Security/LDAP/SSO] 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.
-
[Security/Dependencies] Upgraded
twigto v3.26.0 in response to a security advisory. -
[Security/SSO/OIDC] Hardened the OpenID Connect SSO callback to validate the OAuth
stateparameter against a per-request value stored at the start of the authorization request. Previously an attacker could deliver a?code=...&state=...URL to a victim and force their browser through the callback, signing them into the attacker's identity (login CSRF / session injection). Mismatches now abort withauth.failed. -
[Security/SSO/OIDC] Hardened the OpenID Connect SSO flow by sending and verifying a per-request
nonce(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'snonceclaim. This prevents ID-token replay across sessions and devices and brings the implementation into spec compliance for the authorization code flow. -
[Security/SSO/OIDC] Hardened the OpenID Connect SSO flow by rejecting ID tokens whose
email_verifiedclaim is present and not strictlytrue(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't emit it. -
[Security/SSO/OIDC] Hardened OpenID Connect ID-token signature verification when the IdP omits the
kid(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't first. The kid-less branch now iterates through every JWK and uses the one whoseSignedWithconstraint validates the token; if none match, a specific "did not validate against any JWKS key" error is surfaced. IdPs that emitkidcontinue to use the exact-key lookup unchanged. -
[Security/SSO/SAML] Closed an open-redirect path through SAML SSO. The callback was pushing
RelayStatedirectly 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/oauth/authorizeround-trip) continue to work. -
[Security/Auth] Switched the remaining secret-vs-secret comparisons across the codebase to
hash_equals()so comparisons are constant-time and don'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 serverclient_secretverification, the worker password recovery code and secret-question answer compares, theAPP_SERVICE_TOKENcompare, and the portal image HMAC compare. -
[Security/Auth] Tightened login-state hygiene so abandoned authentication flows can't bleed into the next attempt.
clearAuthState()now also resetsmotdso a previous attempt'sworker.authenticatedautomation result doesn'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. -
[Security/Recovery] 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).