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_methodhas been renamed tocm_custom_action. Move project values intoconfig/application.rband update affected references. No database migration or rake task is required.
🚀 Features
- 🚀 Adopted
ar_lazy_preloadfor 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 raiseCmAdmin::PlatformSettings::NotFound, andfetchsupports explicit fallbacks. #1803 (#mikevic) - 🛡️ Reworked MCP authentication and tool registration around a per-request Rails controller flow and class-based
MCP::Tooltools. 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 oldPLATFORM_SETTINGSconstant is deprecated; file settings now return a path string rather than a lambda, and missing slugs raise an error instead of returningnil. Replacecm_custom_methodreferences withcm_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_allReplace
PLATFORM_SETTINGS[...]withCmAdmin::PlatformSettings[...]or.fetch(slug, default)where a fallback is expected. Remove.callfrom file-setting access, and remove calls toCmPlatformSetting.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 = trueinitializer 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_actionmethod. #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_methodhas been renamed tocm_custom_action. Move project values intoconfig/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_preloadfor 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 raiseCmAdmin::PlatformSettings::NotFound, andfetchsupports explicit fallbacks. #1803 (#mikevic) - 🛡️ Reworked MCP authentication and tool registration around a per-request Rails controller flow and class-based
MCP::Tooltools. 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 oldPLATFORM_SETTINGSconstant is deprecated; file settings now return a path string rather than a lambda, and missing slugs raise an error instead of returningnil. Replacecm_custom_methodreferences withcm_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_allReplace
PLATFORM_SETTINGS[...]withCmAdmin::PlatformSettings[...]or.fetch(slug, default)where a fallback is expected. Remove.callfrom file-setting access, and remove calls toCmPlatformSetting.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 = trueinitializer 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_actionmethod. #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_uploadandmulti_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_pathsin 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, andfast_countis 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
AbortErrorand 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_thresholdpagination setting andfast_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
:stringfilter for text columns, withis,is_not,contains,does_not_contain,is_empty, andis_not_emptyconditions. String matches are case-insensitive, treat wildcard characters literally, and support custom filter scopes. #1751 (#anbublacky)
🐛 Bug Fixes
- 🐛 Corrected default-value handling for
:rangefilters 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
NULLrows 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
:stringtype, 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 theapi_tokens.statusdatabase column is removed. Generate and run the migration, and update customApiTokenmodels to derive status fromexpires_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_atfor 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_atis now the single source of truth for token expiry. Thestatus,live?,expired?,livescope, andexpiredscope 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.statuscolumn. Use thecm_admin:remove_status_from_api_tokengenerator, apply its migration, and update any customApiTokenmodel to derive status and expiry scopes fromexpires_at. The migration preserves manually expired tokens before dropping the column. #1787 (#mikevic)
📚 Documentation
- 📚 Updated the MCP setup example to omit the removed
statuscolumn and use an expiry-basedlivescope. 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.processshim. #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_pathhelper 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/cito run local lint checks and support the required signoff process. #1755 (#BrijeshSajeev)
⚠️ Breaking Changes
No breaking changes.
📚 Documentation
- 📚 Added a repository setup and testing guide for agents, documented signoff and linting steps, corrected stale workflow and spec references, and added a
CLAUDE.mdpointer toAGENTS.md. #1772 (#git-pranavr) #1785 (#mikevic) #1786 (#mikevic) #1784 (#mikevic) #1792 (#mikevic) - 📚 Updated the installer documentation to list the tables it creates, and updated the October 2026 changelog with the v8.4.2 release notes. #1754 (#mikevic) decf0f8c0