From mise-toolkit
Ruby via mise — .ruby-version / Gemfile ruby directive auto-detection, why system Ruby is always wrong, bundler as the gem manager on top of mise-pinned Ruby, and the OpenSSL / readline build-dep story. Use when setting up Ruby for a project.
npx claudepluginhub ray-manaloto/claude-code-marketplace --plugin mise-toolkitThis skill uses the workspace's default tool permissions.
Ruby has the simplest version-file story (`.ruby-version` is effectively universal) and the hardest install story (compiles from source, needs OpenSSL + readline + yaml + zlib matched to the host). mise handles both.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Share bugs, ideas, or general feedback.
Ruby has the simplest version-file story (.ruby-version is effectively universal) and the hardest install story (compiles from source, needs OpenSSL + readline + yaml + zlib matched to the host). mise handles both.
macOS ships Ruby 2.6. Ubuntu 22.04 ships 3.0. Both are years behind upstream. Worse:
system_profiler, Ubuntu's apt scripts). Installing gems globally can break OS tools.sudo gem install, which is a security smell.Always use a version manager for Ruby. mise is one of those version managers.
mise.toml [tools] ruby — explicit.mise.local.toml..tool-versions.[settings]
idiomatic_version_file_enable_tools = ["ruby"]
Reads .ruby-version and the ruby directive in Gemfile.[tools]
ruby = "3.3" # major.minor
ruby = "3.3.6" # exact
ruby = "latest"
ruby = "truffleruby-24.1.1" # alternative runtimes supported
Rule: pin exact for Rails apps in production. Ruby minor versions introduce subtle behavior changes that can surprise.
Gemfile integration# Gemfile
source "https://rubygems.org"
ruby "3.3.6"
gem "rails", "~> 7.1"
# ...
The ruby "3.3.6" line at the top of Gemfile is the convention. With the idiomatic reader enabled, mise picks it up automatically — no duplication in mise.toml.
Ruby compiles from source (no pre-built option as of early 2026). Host needs:
Debian/Ubuntu:
sudo apt-get install -y build-essential libssl-dev libreadline-dev zlib1g-dev \
libyaml-dev libffi-dev libgdbm-dev libncurses5-dev autoconf bison
macOS (Homebrew):
brew install openssl@3 readline libyaml gmp autoconf
Missing OpenSSL is the #1 failure mode. Symptom: ruby -e "require 'net/https'" fails with cannot load such file -- openssl. Fix: install the right OpenSSL dev libs, then mise install ruby@<version> again.
On Apple Silicon macOS, mise's ruby-build helper usually finds Homebrew's OpenSSL automatically. If not:
[env]
RUBY_CONFIGURE_OPTS = "--with-openssl-dir=$(brew --prefix openssl@3)"
Bundler is how Ruby projects manage gems. It's separate from mise, but they cooperate cleanly:
mise install ruby@3.3.6 # via mise.toml
gem install bundler # installs into mise's per-version gem dir
bundle install # reads Gemfile, installs deps into the project
The default gem install dir is ~/.local/share/mise/installs/ruby/3.3.6/lib/ruby/gems/3.3.0/. This means bundle install without --path writes into mise's install tree, which is fine but commingles project gems with the Ruby install.
Recommended: scope bundler to the project:
bundle config set --local path 'vendor/bundle'
bundle install
Now gems live in ./vendor/bundle/ (add to .gitignore) and bundle exec finds them there. Blowing away a project's gems is rm -rf vendor/bundle.
Add to mise.toml:
[env]
BUNDLE_PATH = "vendor/bundle"
[tasks.install]
run = "bundle install"
sources = ["Gemfile", "Gemfile.lock", "*.gemspec"]
[tasks.test]
depends = ["install"]
run = "bundle exec rspec"
[tools]
ruby = "3.3.6"
node = "22" # for asset pipeline / esbuild / jsbundling-rails
[env]
BUNDLE_PATH = "vendor/bundle"
RAILS_ENV = { required = "development, test, or production" }
[tasks.install]
run = [
"bundle install",
"yarn install || npm install || true",
]
[tasks.db]
run = "bin/rails db:migrate"
[tasks.dev]
run = "bin/dev"
[tasks.test]
depends = ["install"]
run = "bin/rails test"
[tools]
ruby = "3.3"
[tasks.install]
run = "bundle install"
[tasks.test]
run = "bundle exec rspec"
[tasks.lint]
run = "bundle exec rubocop"
[tasks.release]
run = "bundle exec rake release"
[tools]
ruby = "3.3"
[env]
RACK_ENV = { required = "development or production" }
BUNDLE_PATH = "vendor/bundle"
[tasks.dev]
run = "bundle exec puma"
.ruby-version with a pre-release tag (3.4.0-preview1) — mise supports pre-releases but make sure the exact string matches what mise ls-remote ruby shows.Gemfile ruby directive as a range (ruby ">= 3.2") — bundler's range syntax; mise won't install a range. Pin explicitly.Gemfile.lock records the bundler version at the bottom. Use bundle update --bundler when upgrading Ruby, not a manual gem install bundler -v ….ruby = "jruby-9.4", ruby = "truffleruby-24.1"), but gems with C extensions often don't work. Pure-Ruby projects only.mise-lang-ruby-gems — bundler, rubocop/standard, solargraph, the gem-vs-aqua decision.mise-migrate-from-rbenv — moving off rbenv.mise-trust-and-security — why sudo gem install is a smell.mise.jdx.dev/lang/ruby.html.