Blog

Release announcements, helpful tips, and community discussion

In Development: 10.5

Cerb (10.5) is a feature upgrade in development as of October 08, 2024. It includes more than 107 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 December 31, 2023 then you can upgrade without renewing your license. Cerb Cloud subscribers will be upgraded automatically.

Important Release Notes

Changelog

Added

  • [Workflows] Implemented workflows. Unlike packages that create a set of records once, workflows provide ongoing versioned updates to keep a related set of records in sync between multiple environments (e.g. dev, staging, production). Workflow templates use KATA rather than JSON.

    workflow:
      name: example.newTask
      version@date: 2025-12-31T00:00:00Z
      description: This example workflow manages a task record
      requirements:
        cerb_version: >=10.5 <11.0
        cerb_plugins: cerberusweb.core,
      config:
        text/taskName:
          label: Task name:
          default: New task from a workflow
        chooser/taskOwner:
          label: Task owner:
          multiple@bool: no
          record_type: worker
          record_query: isDisabled:n
      
    records:
      task/newTask:
        deletionPolicy: retain
        fields:
          owner_id: $${config.taskOwner_id|default(0)}
          title: $${config.taskName}
    
  • [Workflows] In workflows, requirements can now be enforced from the workflow:requirements: key of the template. The cerb_version: constraint verifies the current Cerb version is compatible (e.g. >=10.5 <11.0). The cerb_plugins constraint verifies the comma-delimited list of plugin IDs are installed and enabled (e.g. cerberusweb.core, cerb.classifiers).

  • [Automations/Scripting] In automation scripting, added a cerb_workflow_config() function for retrieving and sharing workflow configuration values in any feature that support scripting (e.g. automations, workflows, snippets). If key is omitted the function will return all configuration values for the matching workflow. For instance, this can share API keys across multiple records while simplifying key rotation in a single place. It also allows workflow configurations to change without rewriting existing records.

  • [Automations/Scripting] In automation scripting, added a cerb_workflow_resources() function for retrieving workflow managed record IDs in any feature that support scripting (e.g. automations, workflows, snippets).

  • [Workflows] In workflows, records may define an updatePolicy: as a list of fields to update once a record is created. For instance, if a workflow creates a snippet that workers can edit, it should never overwrite the contents of the snippet if the template changes.

  • [Tutorial] Added a built-in ‘Tutorial’ workflow that manages a workspace page with detailed descriptions and examples of Cerb features. This is particularly useful for demonstration, testing, development, and onboarding new workers. The tutorial adapts its examples to the current environment. As a workflow, the tutorial is automatically updated for new versions. This is installed automatically on new instances. Existing instances can install it from Search » Workflows » (+) » Tutorial.

  • [Workflows/UX] When creating workflows, a library of pre-built templates covers common use cases (e.g. tutorial, auto-responder, auto-dispatcher). Options are only displayed if they aren’t currently in use.

  • [Mail/Routing] The most common mail routing scenarios have been greatly simplified with Routing KATA. Automations (mail.route) remain available for complex workflows but are no longer required. Routing can be found at Setup » Mail » Incoming » Routing. Multiple conditions in a single if: node are “all of these”, and multiple if: nodes are “any of these”. Conditions include script, recipients, sender_email, spam_score, subject, body, and header; and actions include bucket, comment, group, importance, owner, and watchers.

    rule/dev:
      if/to:
        recipients: dev@, development@, bugs@
      if/subj:
        subject: [Bugs] *
      then:
        group: Development
      
    rule/sales:
      if:
        recipients: sales@, leads@, prospects@
      then:
        group: Sales
      
    rule/support:
      if:
        recipients: support@, team@, help@
      then:
        group: Support
    
    • [Mail/Routing/Groups] In the group editor, inbox Routing KATA can be configured by managers on the new ‘Incoming Mail’ tab. This routes mail without requiring automations or bot behaviors.
  • [Mail/Routing/Metrics] Added a cerb.mail.routing.rule.matches metric for tracking mail routing rule usage over time. It includes dimensions for rule_id (by ruleset record), rule_key (by rule), and node_key (by condition).

  • [Mail/Logs] Added a mail delivery log in Setup » Mail » Outgoing » Log. This saves a copy of the raw message on success or failure through all mail transports for a retention period of 90 days. On failure, a status message provides more information. If a message is marked as ‘sensitive’ (e.g. password reset) then the content is redacted unless DEVELOPMENT_MODE is enabled. Previously, there was no log in Cerb for outbound mail if a ticket message record wasn’t created (e.g. mail.transactional, bots, etc), which tediously required checking the mail server logs to verify if such messages were delivered. This log also indexes the Message-Id: header, which can be used by webhook callbacks in email delivery services like Postmark to record deliveries and bounces.

  • [Mail/Logs] Added an inbound mail log in Setup » Mail » Incoming » Log. This stores metadata and metrics for every processed message an clearly denotes an exit state of: parsed, failed, or rejected. For mail filtering and routing it also records every triggered automation, behavior, or KATA ruleset, with their outputs and elapsed duration. The total parse duration per message is recorded to aid with optimization. If messages are downloaded from a POP3/IMAP mailbox that record is also linked for reporting (e.g. inbound messages per mailbox over time). Inbound logs are retained for 90 days by default. Previously there was no inbound mail log, and errors were instead saved to the app log or output by the background scheduler.

  • [Workspaces/Tabs] On workspace pages, tabs are no longer sorted in a custom order for each worker. The purpose of workspace pages is to provide a consistent experience for each viewer. This is particularly important when tabs are ordered by priority (e.g. my work, open, waiting). Page owners can sort tabs from the final ‘config’ tab. Previously, when a worker viewed a workspace for the first time, its tabs were sorted in the order they were created.

  • [Workspaces/Tabs] On workspace pages, tabs can now be conditionally visible/hidden. For instance, certain tabs may only be visible for admins or members of a specific group. This improves the reusability of workspace pages by not requiring near duplicates for minor variations. Page owners can view hidden pages and their logic from the final ‘config’ tab. As a consequence, workspace tabs are no longer directly draggable into a new order because this would ignore hidden tabs.

  • [Profiles/Tabs] On record profile pages, tabs can now be conditionally visible/hidden. For instance, a different ‘Overview’ tab could be displayed based on a ticket custom fieldset; making it possible to handle non-email tickets like SMS, calls, forum posts, and bug tracker issues. Rather than a ‘Reply’ button, these tabs could use an interaction toolbar and send updates through an external API (e.g. Twilio). Admins can view hidden tabs and their logic from the final ‘config’ tab.

  • [Automations/Editor/UX] In the automation editor, the toolbar has a new ‘commands’ icon. This displays a searchable list of all editor commands and their keyboard shortcuts. For instance: fold code blocks to level 3, unfold all, duplicate selection, move selection up/down, find, select all, go to line, resize editor height, etc. Previously, these useful commands and shortcuts weren’t referenced anywhere.

  • [Mail/Routing/Metrics] Added a cerb.mail.routing.group.matches metric for tracking group inbox routing rule usage over time. It includes dimensions for group_id (by group), rule_key (by rule), and node_key (by condition).

  • [OAuth Apps/Tokens] Each OAuth App can now independently configure the expiration time for access and refresh tokens. Previously these were hardcoded at 1 hour and 1 month respectively. This caused issues when generating a long-lived token from Setup » Developers that refreshed with a 1-hour expiration. Thanks to 1Password for the feature request.

  • [Cards/Widgets] On card popups, widgets may now be shown or hidden using conditional logic. For instance, a widget may only be visible when tickets are within a certain group, or lack a custom field value. When at least one widget is hidden, admins will see a ‘Hidden’ button at the top of a card popup. This allows hidden widgets to still be rendered or edited.

  • [Workspaces/Widgets] On workspace dashboards, widgets may now be shown or hidden using conditional logic. For instance, a widget may only be visible when tickets are within a certain group, or lack a custom field value. When at least one widget is hidden, admins will see a ‘Hidden’ button at the top of a dashboard. This allows hidden widgets to still be rendered or edited.

  • [Automations/Events/Listeners] Automation Event Listener records now conditionally bind automations to events using KATA. Previously this was done directly on the event record, which frequently caused conflicts when merging events from packages, workflows, etc. A listener is a group of related bindings. The priority of a listener determines when it is evaluated compared to other listeners. When managed by a workflow, a listener can’t be modified directly in order to provide consistency. Listeners can be disabled as a set without having to comment out Event KATA. The existing KATA for each event has been moved to a new listener named ‘Default’.

  • [Toolbars/Sections] Toolbar Section records now conditionally bind items to toolbars using KATA (e.g. interactions). Previously this was done directly on the toolbar record, which frequently caused conflicts when merging toolbar items from packages, workflows, etc. A toolbar section is a group of related items. The priority of a section determines when it is rendered relative to other sections on the same toolbar. When managed by a workflow, a section can’t be modified directly in order to provide consistency. Toolbar sections can be disabled as a set without having to comment out Toolbar KATA. The existing KATA for each toolbar has been moved to a new section named ‘Default’.

  • [Automations/Search] Added a full-text search index to automation records on the script: filter. This indexes the automation name and scripting code. Previously the code was not searchable.

  • [Automations/Editor] In the automation editor, a new ‘Usage’ tab displays the records that refer to the current automation (e.g. automations, events, toolbars, timers, card/profile/workspace widgets, portals, webhooks). This makes it much easier to find dependencies and unused automations.

  • [Interactions/Worker/Audio] In interaction.worker automations, added an audio: form element to play MP3, OGG, or WAV files. The audio can be provided in source:uri: as an automation resource (e.g. from an HTTP API response) or source:blob: as a base64-encoded data: URI. The audio plays using a browser’s HTML5 player, which supports autoplay, controls, and looping. For instance, this can play text-to-speech from a virtual assistant.

    See: Generate spoken audio from text with OpenAI

  • [Interactions/Worker/Chart] In interaction.worker automations, added a chart: form element to render highly customizable interactive charts from multiple datasets (data query, automation, manual) using Chart KATA.

  • [Interactions/Worker] In interaction.worker automations, added a chooser: form element for selecting records using a search popup. This can perform single or multiple selection for any record type using search filters and autocompletion.

  • [Mail/Reply/UX] When replying to messages, a warning is now displayed if the recipient is banned or defunct. Previously, messages to defunct recipients were silently disregarded without any indication in the UI.

  • [Connected Services/Packages] Added ‘Anthropic’ to the connected services package library.

  • [Platform/Developers/Datasets] Added a ‘Dataset’ service to the platform. This parses Dataset KATA for features like charts to display multiple series. It can fetch data from automations, data queries, or manual.

  • [Profiles/Tickets] On ticket profiles, the ‘Status’ widget can now quickly set a ticket to the ‘waiting’ status with presets (e.g. 1 hour, tomorrow 8am, next week). On existing environments, add a new ‘Status’ widget from the library to update it.

  • [Interactions/Worker] In interaction.worker automations, a return:callout: key will now trigger a callout in the UI. This is particularly useful for onboarding, tutorials, and tours. A callout requires a DOM selector and message to display. Optional my and at position elements align the callout to the target element (e.g. right top, left+20 bottom-5.

  • [Sheets/Icons] In sheets, icon: columns and options can now render arbitrary in-line SVG images with the new svg: key. Rendered SVG images are automatically sanitized. This is particularly useful for dynamic or single-use images. For instance, a survey could display happy/sad or thumbs up/down images on buttons.

  • [Interactions/Worker] In interaction.worker automations, a fileDownload: prompt can now optionally provide data: directly without requiring an automation resource or attachment.

  • [Workspaces/Dashboards] On workspace ‘Dashboard’ tabs, added a new ‘halves’ layout. This organizes widgets into two equal width columns without requiring aligned pairs between the columns.

  • [Profiles/Dashboards] On profiles, ‘Dashboard’ tabs now have additional ‘halves’ and ‘thirds’ columnar layouts.

  • [Automation/Scripting] Added a cerb_plugin_enabled() function to automation scripting. For instance, this can be used to make dashboard tabs or widgets conditional on a particular plugin being enabled (e.g. project boards).

  • [Developers/Database] In Setup->Developers->Database Schema, it’s now possible to validate an environment’s database schema against the official schema. For instance, it’s possible to make changes to the database directly (new indices, column types, encoding) and these can interfere with Cerb’s functionality. This page also highlights extra tables (e.g. in-place table backups, deprecated plugins).

  • [Sheets] In sheets, added a text_align: option to columns to align text within a cell. This supports the values: left, center, and right.

  • [Sheets/Slider] In sheets, a slider: column may now set a show_labels: yes option to show the min and max values on either side of the slider. This defaults to no.

  • [Sheets/Sliders] In sheets, slider: columns can specify custom threshold_colors: to override the defaults. This is a map with limits as keys and colors as values.

  • [Sheets/Search] On sheets, search: columns can now provide an optional icon: image.

  • [Workspaces] Dashboard workspace tabs now support a locked@bool: advanced option. This hides the editing toolbar (add widget, edit dashboard) at the top of the tab even from owners of the page. It also prevents dragging widgets. Tabs can still be edited from the top-right menu.

  • [Records/Packages/Library] Library packages can now be created from workflows, automations, and the API. For instance, a workflow could add a new type of workspace widget. Clicking ‘Add widget’ would use the package to create copies of it.

  • [Setup/Teams] When creating a new worker account, default pages can be automatically added to their menu. This is configured in Setup » Teams » Configure.

  • [Installer/Tutorial/UX] The installer now automatically adds the ‘Tutorial’ and ‘Checklist’ workspace pages to the first worker’s menu.

Changed

  • [Mail/Drafts] Drafts of ticket.reply type can now be created without a worker_id by automations (e.g. auto replies). These drafts are only editable by admins and will be attributed to a worker who edits them.

  • [Installer] In the installer, combined the ‘demo’ and ‘prod’ packages into a single ‘base’ package. There are separate workflows for ‘cerb.tutorial’, ‘cerb.demo.data’, and ‘cerb.quickstart’. This makes it possible to completely remove demo data when moving into production.

  • [Installer/Styles] Changed the installer to use dark mode.

  • [Installer/UX] In the installer, streamlined the final two steps (register/finished) into a single step.

  • [Workspaces/Pages] When adding a new workspace page, the ‘Home’ template in the library now includes tabs for ‘Open’ and ‘Waiting’ after ‘My Work’. Workers would check this after their assignments unless using an auto-dispatcher.

  • [Automations] In automations, the http.request: command no longer treats non-2XX response status codes as errors (e.g. 404, 503). This allows them to be properly handled by subsequent automation logic rather than requiring an on_error: handler.

  • [Activity Log/Performance] Optimized activity log storage for large environments. The context_activity_log database table is among the largest in busy Cerb Cloud instances (~20GB). Previously, log entries stored the activity translation ID and the record label/url for the actor/target. These are no longer stored and are instead fetched from the database when displaying a page of log entries. Internal URLs are stored using the shorter cerb:record_type:id format. These changes reduce the table size by ~80% for new log entries.

  • [Maint/Performance] In the nightly maintenance scheduler job, further optimized the bulk purge of deleted tickets that exceed the ‘undo’ window. Previously, purging message content in the database storage engine deleted rows individually by ID. Now it can delete batches of IDs. Optimized the deletion of context_link and context_activity_log. In a test of deleting over 1M tickets the changes performed 250% faster.

  • [Maint/Performance] In the nightly maintenance scheduler job, optimized the bulk purge of unlinked attachments.

  • [Records/Buckets/UX] In the bucket editor, added a ‘Save & Continue’ button.

  • [Platform/JSON] Functionality that exports to JSON (e.g. automations, widgets) no longer escape UTF-8 characters by default.

  • [Profiles/Library/Performance] On ticket profiles, the ‘Participants’ widget in the library now expands contact records in a single query.

  • [Groups/UX] Improved the usability of the group editor popup. It is now organized into tabs for: Profile, Outgoing Mail, and Members. The ‘Members’ splits a long roster into multiple columns. Group membership is now set with a dropdown rather than a trio of radio buttons. The roster bulk update options moved into a toolbar. A new ‘Reset’ bulk option restores the original state of the roster.

  • [Roles/UX] When editing roles, improved the interface for itemized permissions. The ‘Records’ and ‘Other’ tabs have been combined into a single screen. This makes ‘Other’ more obvious after several clients mentioned not noticing it. Record permissions now use three columns (rather than two) on wider displays. The record types are properly sorted by translated label. Added permission IDs to a tooltip.

  • [Workers/Impersonate] The ‘Impersonate’ button for admins moved to worker card and profile toolbars.

  • [Workers/Impersonate] Admin workers can no longer be impersonated by other admins.

  • [Cards/Widgets] On PGP Public key cards, updated the built-in widgets for ‘Subkeys’ and ‘Public Key’.

  • [Search/Data Queries] In search queries and data queries, double-quoted text may contain escaped quote characters by prefixing them with a backslash (e.g.\"). Previously it wasn’t possible to search for literal quote characters.

  • [UI/Buttons] In the UI, buttons and their icons are now sized using relative measurements (em) rather than fixed pixels. For instance, this allows text_size: in sheet columns or toolbars to also change the size of buttons.

  • [Sheets] In sheets, toolbar: columns now respond to the text_size: option by resizing buttons and their icons.

  • [Data Queries] On data.query.types data queries, a docs_url key contains a URL to the documentation for each data query type.

  • [Automations/Workflows] In the automation editor, the export popup now provides ‘package’ and ‘workflow’ formatted output.

  • [Chart KATA] In Chart KATA widgets with a timeseries axis, added an example for 12-hour times (e.g. 4 PM).

  • [Profiles/Performance] Profile tabs per record type now use the cache rather than a database query.

  • [Project Boards] Project Board Column records now have a pos field to rank their position on the board. Previously this was stored in columns_json on the board, which was inefficient when creating boards from packages or workflows (i.e. boards and columns needed to know each other IDs ahead of time).

  • [Classifiers/Plugins] Moved the Classifiers functionality to an optional plugin. When this is needed, it simplifies UX by removing four record types (classifiers, classifications, classifier entity, and classifier example).

  • [Sheets/Sliders] In sheets, slider: columns now support text_size: for scaling.

  • [Mail/UX] When composing and replying to email, more informative error messages are now sent back to the browser. Previously, in some situations, the ‘Please wait’ spinner could display indefinitely.

  • [Mail/Relay] On ticket profiles, revamped the ‘Relay to’ reply option to use an email address chooser (defaulting to worker addresses) rather than an inline menu.

  • [Workers/UI] New worker accounts default to dark mode.

Platform

  • [Platform/Mail/Dependencies] Replaced the abandoned Swiftmailer dependency with Symfony Mailer for outgoing email.

  • [Docker] Updated the Dockerfile to use PHP 8.2 and Ubuntu 23.10.

  • [Platform/Dependencies] Updated the Twig template engine from v3.6.2 to v3.8.0. This adds new capabilities to automation scripting.

  • [Platform/Dependencies] Upgraded the GuzzleHttp dependency from 6.5.8 to 7.8.2.

  • [Platform/Ace] Updated the Ace code editor from v1.12.5 to v1.32.3.

  • [Platform/Mail/Dependencies] In the Devblocks platform, abstracted the outgoing email service to remove the dependency on legacy Swift Mailer. It makes it possible to support non-SMTP mail transports. For instance, email sending web APIs like Postmark.

  • [Platform/HTTP] When an HTTP request receives any error in response, the ‘Please wait’ loading panel will automatically be closed if it is open. Previously this had to be implemented in the error handler of each request.

Deprecated

  • [Installer] Disabled the ‘CRM’ and ‘Knowledgebase’ plugins by default in new installs (use custom records).

  • [Workspaces/Widgets] ‘HTML/Javascript’ workspace and profile widgets are now marked as deprecated. These should be migrated to ‘Sheet’ or ‘Automation’ widgets.

Removed

  • [Connected Services/Packages] Removed ‘Nest’ from the connected accounts package library. The service has been retired and merged into Google Home.

  • [Portals/Templates] In the Support Center portal configuration, several templates for core functionality are no longer customizable (e.g. register, login). Changes to these files often broke portals on upgrades.

  • [Storage/Database] The ‘Database’ object storage engine no longer allows arbitrary MySQL connection details. It always uses the local database. storage_ tables in an external database must be manually migrated to the main database (e.g. SQL dump + import).

  • [Storage/Database] The ‘Disk’ object storage engine no longer allows arbitrary filesystem path details. It always uses the local storage filesystem. Existing storage directories in an external filesystem must be manually merged, symlinked, or mounted. The APP_STORAGE_PATH setting in framework.config.php can override the local base path (e.g. volume mount).

  • [Tour] Removed the neglected ‘tour’ feature in favor of the new ‘Tutorial’ workflow.

  • [Welcome] Removed the neglected ‘Welcome’ page for new workers in favor of the new ‘Tutorial’ workflow.

  • [Plugins/Twitter] Removed the ‘Twitter’ plugin. This functionality can be reimplemented with automations and custom records. This does not remove existing data.

Fixed

  • [Activity Log/UX] In the activity log, the ‘Cerb’ actor no longer shows a broken hyperlink.

  • [Login] Rate-limited submission of the login forms. Previously, it was possible to submit many times by rapidly clicking the button or holding down the enter key.

  • [KATA/UX] In KATA, fixed an issue with block value annotations like @raw where non-indented blank lines terminated the block. This could happen with some code formatting tools. Block values now rewrite blank lines to match the indent of the next non-blank line.

  • [Worklists] Fixed an issue where the last column of a worklist could be omitted if too narrow in proportion to the other columns.

  • [UI/Tabs] Fixed a visual defect when UI tab sets wrapped to additional rows. Also fixed an issue where the selected tab became wider and moved the other tab positions.

  • [Sheets] Fixed an issue with sheets using grid or columns layouts where interaction columns didn’t work properly.

  • [KATA] Fixed an issue when emitting an object to KATA. If a key is a nested array, it’s now written using @json rather than @list.

  • [Project Boards/Profiles] Fixed an issue with ‘Project Board’ profile widgets where placeholders couldn’t be used for the ID: (e.g. {{record_id}}).

  • [Plugins/Domains] Fixed an issue in the ‘Domains’ plugin where worklists didn’t display the value in the ‘Server’ column.

Security

  • [Security/CSP/XSS] The Content-Security-Policy HTTP header no longer permits unsafe-inline in script-src. All script blocks now use a random per-session “nonce” token. This significantly reduces the potential XSS attack surface.

  • [Security/Developers/CSP] Implemented DevblocksPlatform::getRequestNonce() for generating a “nonce” (number used once) for the Content-Security-Policy to harden inline scripts and stylesheets against XSS attacks. This is currently per-session, but ideally it will be per-request in the near future.

  • [Security/CSP] Added a Content-Security-Policy “nonce” attribute to all inline script tags to use a more strict policy by default. This prevents authorized script blocks from being evaluated.

  • [Security/CSP] Added a Content-Security-Policy header on all endpoint responses. Previously this was only enforced on UI pages.

  • [Security/UI/CSP] Untrusted links (e.g. email message) are now rewritten with href #cerb-external-link and a data-cerb-external-link DOM attribute. Previously the links were rewritten with a javascript: scheme, which is no longer permitted with the strict Content-Security-Policy. This approach makes it easier to use sanitized HTML in third-party integrations (e.g. API). The security popup is no longer displayed when the text of a link exactly matches its URL.

  • [Security/CSP/Widgets] ‘HTML/Javascript’ workspace and profile widgets now have a current_worker_nonce placeholder for the per-session Content-Security-Policy script-src ‘nonce’ token. This must be added to the nonce attribute in <script> blocks or custom widgets will no longer work.