Skip to main content

Release Notes — November 2026

v9.0.0 (2026-11-05)​

Catalyst v9.0.0 — 2026-11-05

⚠️ WARNING: Breaking Changes — Project settings are now separate from platform settings, and cm_custom_method has been renamed to cm_custom_action. Move project values into config/application.rb and update affected references. No database migration or rake task is required.

🚀 Features​

  • 🚀 Adopted ar_lazy_preload for admin index and filtering associations. Associations are batch-loaded on first access rather than eagerly at query time, while preserving N+1 protection. #1764 (#austinjb32)

🐛 Bug Fixes​

  • 🐛 Regenerated stale root and Rails 8.0/8.1 appraisal lockfiles so frozen Bundler installs can resolve the current gem version and dependencies. #1823 (#austinjb32)

✨ Improvements​

  • ✨ Platform settings now use a Rails.cache-backed reader, with cache invalidation on changes so updates apply across processes without a restart. Missing settings raise CmAdmin::PlatformSettings::NotFound, and fetch supports explicit fallbacks. #1803 (#mikevic)
  • 🛡️ Reworked MCP authentication and tool registration around a per-request Rails controller flow and class-based MCP::Tool tools. Authorization now fails closed when a policy scope is missing. #1805 (#Mahaveer1141)
  • ✨ MCP tools now set the current user's permissions before each tool execution, keeping permission setup with authorization logic. #1824 (#Mahaveer1141)
  • ♻️ Refactored resource-controller request handling into declarative action services and shared helpers, making response behavior more explicit and testable. #1818 (#Mahaveer1141) #1801 (#mikevic)

⚠️ Breaking Changes​

  • ⚠️ Project settings are no longer overridden by platform-setting rows. Move any admin-managed project name, slug, logo URL, favicon URL, or default email into config/application.rb. The old PLATFORM_SETTINGS constant is deprecated; file settings now return a path string rather than a lambda, and missing slugs raise an error instead of returning nil. Replace cm_custom_method references with cm_custom_action. #1803 (#mikevic) #1818 (#Mahaveer1141)

    To preserve project values, set the relevant values in config/application.rb, for example:

    config.x.project_settings.name = "Acme"
    config.x.project_settings.slug = "acme"
    config.x.project_settings.logo_url = "https://cdn.example.com/logo.png"
    config.x.project_settings.favicon_url = "https://cdn.example.com/favicon.png"
    config.x.project_settings.default_from_email = "no-reply@example.com"

    If legacy project-setting rows exist, remove them from a Rails console:

    CmPlatformSetting.where(slug: %w[project-name project-slug logo-url favicon-url default-email]).destroy_all

    Replace PLATFORM_SETTINGS[...] with CmAdmin::PlatformSettings[...] or .fetch(slug, default) where a fallback is expected. Remove .call from file-setting access, and remove calls to CmPlatformSetting.sync_project_settings_to_config. No database migration or rake task is required.

📚 Documentation​

  • 📚 Updated the DSL guide to explain lazy association preloading and the optional ArLazyPreload.config.auto_preload = true initializer setting. #1764 (#austinjb32)
  • 📚 Updated MCP documentation with the controller-based authentication and tool architecture, Rails console tool usage, and the fields returned by list and get tools. #1805 (#Mahaveer1141)
  • 📚 Added platform-settings guidance covering the distinction between project and platform settings, cache behavior, lookup methods, fallbacks, and file-setting paths. #1803 (#mikevic)
  • 📚 Updated auditing documentation to use the renamed cm_custom_action method. #1818 (#Mahaveer1141)

v8.5.4 (2026-11-05)​

Catalyst v8.5.4 — 2026-11-05

⚠️ WARNING: Breaking Changes — Platform settings are now separate from project settings, and cm_custom_method has been renamed to cm_custom_action. Move project values into config/application.rb, update references to the renamed action and deprecated settings API, and remove obsolete project-setting rows as described below. No database migration or rake task is required.

🚀 Features​

  • 🚀 Adopted ar_lazy_preload for admin index and filtering associations. Associations are batch-loaded on first access rather than eagerly at query time, while preserving N+1 protection. #1764 (#austinjb32)

🐛 Bug Fixes​

  • 🐛 Regenerated stale root and Rails 8.0/8.1 appraisal lockfiles so frozen Bundler installs can resolve the current gem version and dependencies. #1823 (#austinjb32)

✨ Improvements​

  • ✨ Platform settings now use a Rails.cache-backed reader, with cache invalidation on changes so updates apply across processes without a restart. Missing settings raise CmAdmin::PlatformSettings::NotFound, and fetch supports explicit fallbacks. #1803 (#mikevic)
  • 🛡️ Reworked MCP authentication and tool registration around a per-request Rails controller flow and class-based MCP::Tool tools. Authorization now fails closed when a policy scope is missing. #1805 (#Mahaveer1141)
  • ✨ MCP tools now set the current user's permissions before each tool execution, keeping permission setup with authorization logic. #1824 (#Mahaveer1141)
  • ♻️ Refactored resource-controller request handling into declarative action services and shared helpers, making response behavior more explicit and testable. #1818 (#Mahaveer1141) #1801 (#mikevic)

⚠️ Breaking Changes​

  • ⚠️ Project settings are no longer overridden by platform-setting rows. Move any admin-managed project name, slug, logo URL, favicon URL, or default email into config/application.rb. The old PLATFORM_SETTINGS constant is deprecated; file settings now return a path string rather than a lambda, and missing slugs raise an error instead of returning nil. Replace cm_custom_method references with cm_custom_action. #1803 (#mikevic) #1818 (#Mahaveer1141)

    To preserve project values, set the relevant values in config/application.rb, for example:

    config.x.project_settings.name = "Acme"
    config.x.project_settings.slug = "acme"
    config.x.project_settings.logo_url = "https://cdn.example.com/logo.png"
    config.x.project_settings.favicon_url = "https://cdn.example.com/favicon.png"
    config.x.project_settings.default_from_email = "no-reply@example.com"

    If the legacy rows exist, remove them from a Rails console:

    CmPlatformSetting.where(slug: %w[project-name project-slug logo-url favicon-url default-email]).destroy_all

    Replace PLATFORM_SETTINGS[...] with CmAdmin::PlatformSettings[...] or .fetch(slug, default) where a fallback is expected. Remove .call from file-setting access, and remove calls to CmPlatformSetting.sync_project_settings_to_config. No migration or rake command is required.

📚 Documentation​

  • 📚 Updated the DSL guide to explain lazy association preloading and the optional ArLazyPreload.config.auto_preload = true initializer setting. #1764 (#austinjb32)
  • 📚 Updated MCP documentation with the controller-based authentication and tool architecture, Rails console tool usage, and the fields returned by list and get tools. #1805 (#Mahaveer1141)
  • 📚 Added platform-settings guidance covering the distinction between project and platform settings, cache behavior, lookup methods, fallbacks, and file-setting paths. #1803 (#mikevic)
  • 📚 Updated auditing documentation to use the renamed cm_custom_action method. #1818 (#Mahaveer1141)

v8.5.3 (2026-11-04)​

Catalyst v8.5.3 — 2026-11-04

🚀 Features​

  • 🚀 File fields now support Active Storage direct uploads for single_file_upload and multi_file_upload. Files upload directly to the storage service, with per-file progress feedback, while preserving normal form-upload behavior when direct uploads are unavailable. #1814 (#austinjb32)

🐛 Bug Fixes​

  • 🐛 Restored appends to the engine’s eager_load_paths in the initializer. dfc4635

✨ Improvements​

No additional improvements in this release.

⚠️ Breaking Changes​

No breaking changes in this release.

📚 Documentation​

  • 📚 Updated review-app deployment guidance to note that the Tigris bucket needs CORS rules for browser-based direct uploads, and updated the November changelog. 9ebd550

v8.5.2 (2026-11-04)​

Catalyst v8.5.2 — 2026-11-04

🚀 Features​

  • 🚀 Large index pages can use PostgreSQL planner row estimates instead of running an exact count query. Estimated totals display a + suffix, and fast_count is available on ActiveRecord models and relations. #1767 (#austinjb32)
  • 🚀 File fields now support Active Storage direct uploads, with per-file progress and previews, so large files can upload outside the form submission request. #1745 (#austinjb32)

🐛 Bug Fixes​

  • 🐛 Aborted direct uploads now reject with AbortError and prevent pending requests from being sent, avoiding uploads that otherwise remained unsettled or continued after cancellation. #1813 (#mikevic)
  • 🐛 Required single- and multi-file upload fields now validate correctly when no file is selected, including nested form fields. #1808 (#BrijeshSajeev)
  • 🐛 Improved direct-upload handling across review-app domains and chat uploads, including URL resolution and upload guards. 1bcc808 · d6583d7 · b38d8e8
  • 🐛 Added a tooltip during form submission. f3cea83

✨ Improvements​

  • ✨ Updated Bootstrap JavaScript, Popper, and vendored SCSS to compatible Bootstrap 5.3.8 versions, retaining Catalyst’s existing SCSS customizations. #1804 (#mikevic)
  • ✨ File uploads now block form submission while uploading and are aborted when the drawer closes. 77c65d5

⚠️ Breaking Changes​

No breaking changes in this release.

📚 Documentation​

  • 📚 Documented the count_threshold pagination setting and fast_count, including configuration examples, PostgreSQL behavior, and how to disable estimates. #1767 (#austinjb32)
  • 📚 Updated the November changelog with the v8.5.1 release notes. 24f1883

v8.5.1 (2026-11-02)​

Catalyst v8.5.1 — 2026-11-02

🚀 Features​

  • 🚀 Added a :string filter for text columns, with is, is_not, contains, does_not_contain, is_empty, and is_not_empty conditions. String matches are case-insensitive, treat wildcard characters literally, and support custom filter scopes. #1751 (#anbublacky)

🐛 Bug Fixes​

  • 🐛 Corrected default-value handling for :range filters and made empty dropdown selections behave as no filter. #1751 (#anbublacky)

✨ Improvements​

  • ✨ Standardized filter popup behavior: multi-select, range, and string filters now apply changes with the Apply button, Enter, or when the popup closes. Clear and Apply actions are shared across these popups. #1751 (#anbublacky)
  • ✨ String filter conditions handle empty strings and NULL rows as appropriate, with parameterized, case-insensitive matching. #1751 (#anbublacky)

⚠️ Breaking Changes​

No breaking changes in this release.

📚 Documentation​

  • 📚 Updated the filter DSL reference and Advanced Filters and Custom Filter Method guides to document the :string type, its supported conditions, and custom-scope usage. #1751 (#anbublacky)

v8.5.0 (2026-11-02)​

Catalyst v8.5.0 — 2026-11-02

⚠️ WARNING: Breaking Changes — API token status is now derived from expires_at, and the api_tokens.status database column is removed. Generate and run the migration, and update custom ApiToken models to derive status from expires_at.

🔄 WARNING: Migration Required — Run these commands to generate and apply the migration:

rails generate cm_admin:remove_status_from_api_token
rails db:migrate

🚀 Features​

  • 🔐 API tokens now respect expires_at for authentication and are reported as expired as soon as their expiry passes. Admins can set or extend token validity and expire live tokens from the API Token page. #1715 (#anbublacky)

🐛 Bug Fixes​

  • 🛡️ Token verification now rejects tokens whose expiry has passed, without depending on a background task to update a stored status. #1715 (#anbublacky)

✨ Improvements​

  • ✨ expires_at is now the single source of truth for token expiry. The status, live?, expired?, live scope, and expired scope are derived from it, keeping model behavior and database queries consistent. #1787 (#mikevic)
  • ✨ The API Token “Expire” action now updates only expires_at; expiry no longer needs a status-sync rake task or callbacks. #1787 (#mikevic)

⚠️ Breaking Changes​

  • ⚠️ Removed the api_tokens.status column. Use the cm_admin:remove_status_from_api_token generator, apply its migration, and update any custom ApiToken model to derive status and expiry scopes from expires_at. The migration preserves manually expired tokens before dropping the column. #1787 (#mikevic)

📚 Documentation​

  • 📚 Updated the MCP setup example to omit the removed status column and use an expiry-based live scope. Added generator documentation for removing API token status, including migration behavior and the model changes apps need to make. #1787 (#mikevic)

v8.4.3 (2026-11-02)​

Catalyst v8.4.3 — 2026-11-02

🚀 Features​

  • 🚀 Added job listings and an application flow with job-specific questions, answer validation, and safeguards against duplicate applications. #1779 (#BrijeshSajeev)
  • 🚀 Added selected-record counts and refreshed bulk-action controls on index and associated-index tables, with counts updating as selections change. #1753 (#anbublacky)

🐛 Bug Fixes​

  • 🐛 Bulk-action modals now show success and error banners together for partial success. Error details are escaped, failure counts are accurate, and custom error bodies replace the default message as intended. #1718 (#anbublacky)
  • 🐛 Fixed fresh Rails 8.1 PostgreSQL app installation: generated migrations now create the expected tables with unique versions, and the installer completes database setup before copying the initializer. #1754 (#mikevic)
  • 🐛 Fixed filter dropdown errors by pinning Popper to its production ESM build and removing the global window.process shim. #1798 (#mikevic)

✨ Improvements​

  • 🛡️ Permission scopes are now enforced for record mutations as well as reads. Out-of-scope records cannot be changed through member actions, and create/update operations are checked against the applicable scope. #1775 (#BrijeshSajeev)
  • ✨ Added the ct_path helper to centralize per-model admin route generation and replace repeated dynamic route-helper calls. #1799 (#mikevic)
  • ✨ Consolidated repeated controller model lookups into a memoized helper without changing behavior. #1797 (#mikevic)
  • ✨ Aligned test and review-app Ruby versions with the repository’s Ruby version file, updated the test workflow’s Node version source, and upgraded GitHub cache actions to v6. #1773 (#mikevic) #1790 (#mikevic) #1789 (#mikevic)
  • ✨ Added Claude Code session setup and edit-formatting hooks, and a command allowlist to make cloud development and routine checks easier. #1791 (#mikevic) #1793 (#mikevic)
  • ✨ Added bin/ci to run local lint checks and support the required signoff process. #1755 (#BrijeshSajeev)

⚠️ Breaking Changes​

No breaking changes.

📚 Documentation​