Studio Engine
Shared Rails engine for McRitchie apps. Provides authentication, error handling, dynamic theming, and common concerns used by McRitchie Studio and Turf Monster.
Part of the McRitchie ecosystem — see
ECOSYSTEM.mdfor the 5-repo map;house-burn-down.mdfor fresh-Mac recovery.
Installation
# Gemfile — install from RubyGems (recommended)
gem "studio-engine", "~> 0.5"
Then bundle install. The current release is v0.5.2; see CHANGELOG.md for the history.
Published to RubyGems as of v0.4.0 (2026-05-17). New installs should use the RubyGems form, which the consumer Rails apps (
mcritchie-studio,turf-monster) already use.
What It Provides
- Authentication: Passwordless magic-link auth, optional password auth, Google OAuth via OmniAuth, Solana wallet sign-in, and optional one-way SSO patterns
- Error handling:
Studio::ErrorHandlingconcern withrescue_and_log,ErrorLogmodel withcapture!, error log viewer at/error_logs - Theme system: Dynamic CSS custom properties generated from 7 role colors (primary, dark, light, success, accent, warning, danger). Dark/light mode toggle. Admin theme editor at
/admin/theme. - Sluggable concern:
before_save :set_slugwithto_paramfor human-readable URLs - ThemeSetting model: Per-app DB overrides with fallback to config defaults
Configuration
Each consuming app configures the engine in config/initializers/studio.rb:
Studio.configure do |config|
config.app_name = "My App"
config.session_key = :my_app_user_id
config. = ->(user) { "Welcome, #{user.display_name}!" }
config.auth_methods = %i[magic_link google]
config.registration_params = [:name, :email]
config.magic_link_token_name = "magic_link_my_app_v1"
config.mailer_from = ENV.fetch("MAILER_FROM", "noreply@example.com")
config.theme_primary = "#4BAF50" # Override default violet
config.theme_logos = ["logo.svg"]
end
Transactional mail transport is shared through Studio::MailTransport:
# config/initializers/studio_mail_transport.rb
Studio::MailTransport.configure!
It selects SES SMTP when MAIL_TRANSPORT=ses and SES SMTP credentials are
present, otherwise falls back to Resend when RESEND_API_KEY is present.
Routes
In the consuming app's config/routes.rb:
Rails.application.routes.draw do
Studio.routes(self)
# ... app routes
end
This draws the enabled auth routes (/login, /signup, /logout, magic-link routes, Solana routes), OAuth callbacks, optional SSO routes, /error_logs, and /admin/theme.
Overriding Views
This is a non-isolated engine -- app views at the same path automatically override engine views. For example, placing app/views/sessions/new.html.erb in the consuming app replaces the engine's login page.
Releasing
Engine releases use semantic versions and are published to RubyGems. The full
operator checklist lives in docs/RELEASE.md.
Short form:
- Update
CHANGELOG.mdandlib/studio/version.rb. - Run
bin/release-check --build. - Publish the gem only after explicit approval.
- Tag the release after RubyGems accepts the gem.
- In each consumer app, run
bundle update studio-engine, verify the lockfile, and run app smoke checks.
Semver guide
- PATCH: bug fix; no API change. Consumers can update the gem with zero diff elsewhere.
- MINOR: backward-compatible feature add. Consumers may opt in to new APIs.
- MAJOR: breaking change. Consumers will need code changes alongside the tag bump.
Local development (against an unreleased engine)
When iterating on engine code from a consumer app, point bundler at the local path so you don't need to push + tag for every edit:
# in the consumer app
bundle config set --local local.studio /Users/alex/projects/studio-engine
bundle install
# ... iterate in both repos ...
bundle config unset --local local.studio # restore RubyGems resolution
For short local experiments, temporarily point a consumer Gemfile at path: "../studio-engine" and restore the RubyGems dependency before merging.
Development Notes
See CLAUDE.md only as legacy migration context while neutral agent docs are being extracted. Current cross-repo setup, ports, credentials, and workflow guidance live in McRitchie Studio's docs/agents/.