Ruby Engineering
Use this skill for repository-backed Ruby implementation and workflow decisions.
Inspect the supported Ruby version, Bundler and gem policy, source layout, test
framework, style tools, and execution targets before assuming a universal Ruby
setup.
Use script-engineering when the primary
decision is whether automation should be a script or whether Ruby fits better
than shell, Python, PowerShell, or JavaScript. This skill owns the Ruby mechanics
after Ruby is selected.
MCP SDK Deferral
For an MCP request, load
mcp-server-engineering and its dated
SDK selection record.
That record owns Ruby's current eligibility, authority, package/version, tier,
core-revision, transport, lifecycle, and conformance caveats.
Do not prescribe Ruby MCP gem APIs or server/client wiring from this skill.
Defer implementation selection until current official evidence and target
validation qualify the selected surface; retain this skill for ordinary Ruby
mechanics only.
Workflow
- Read repository instructions,
.ruby-version, version-manager files,
Gemfile, Gemfile.lock, gemspecs, Rakefile, source/tests, CI, and existing
Ruby commands.
- Identify supported Ruby and Bundler versions, target operating systems, and
whether the code is an application, library, gem, CLI, or repository script.
- Preserve the repository's framework and conventions. Do not introduce Rails,
RSpec, Minitest, RuboCop, Sorbet, Steep, or another tool without evidence or
an explicit adoption goal.
- Define observable behavior and choose the narrowest useful test boundary.
- Implement small explicit objects, modules, and functions; isolate external
processes, filesystems, clocks, networks, and databases behind testable
boundaries.
- Run focused syntax, test, lint, and packaging checks before broader
repository-native validation.
- Report versions and commands observed, files and dependencies changed,
validation run, skipped targets, and remaining compatibility risk.
Runtime And Dependency Discipline
- Treat
.ruby-version, .tool-versions, mise.toml, gem metadata, CI images,
and deployment configuration as runtime evidence. A locally available ruby
does not prove every target supports that version.
- Use the repository's Bundler workflow. Prefer
bundle exec <command> for
project-owned executables when that is the established way to bind commands to
the lockfile.
- Keep
Gemfile intent and Gemfile.lock changes aligned. Do not hand-edit
lockfile resolution or introduce a global gem dependency for project behavior.
- Prefer the standard library for small needs when it is clear and sufficient.
Add a gem only when its maintained behavior outweighs dependency, native
extension, startup, licensing, and supply-chain cost.
- Load
dependency-supply-chain-review
for new gems, lockfile churn, native extensions, sources, install hooks,
provenance, or advisory questions.
Local CPU Parallelism Routing
Compose with parallelism-engineering
when a local CPU-bound Ruby workload needs data or task decomposition, partition
sizing, bounded worker-pool design, deterministic reduction, cancellation, or
nested-parallelism control. That skill owns the cross-language parallel design;
this skill owns Ruby runtime, library, gem, test, and process/thread mechanics.
Do not route routine async I/O, event-loop behavior, fibers, ordinary background
work, or generic Ruby concurrency to parallelism-engineering; keep that work
with Ruby's implementation owner. Spark/PySpark execution remains with
data-platform-engineering, not local
parallelism engineering.
WebAssembly Routing
Compose with webassembly-engineering
when Ruby work includes a general WebAssembly decision: a WAT or .wasm
artifact, WASI or WIT, the Component Model, host/guest contract, runtime or
target selection, capability grants, or Wasm packaging and deployment. That
skill owns those Wasm boundary and compatibility decisions. This skill retains
Ruby source, gem, compiler or binding-tool, host-integration, and test
mechanics; the Wasm skill does not establish Ruby toolchain or binding support.
Idiomatic Ruby
- Prefer clear message-oriented objects, modules, blocks, enumerators, keyword
arguments, and standard collection APIs over manual indexing or framework
ceremony.
- Keep methods cohesive and make mutation visible. Return useful domain values
instead of relying on unrelated global or process state.
- Use modules for shared behavior or namespaces deliberately; do not use mixins
as an unstructured substitute for object boundaries.
- Make public APIs explicit about accepted values, returned values, exceptions,
side effects, and destructive or mutating behavior. Use
? and ! names only
when they follow established Ruby meaning in the repository.
- Prefer ordinary methods, delegation, and explicit registration over dynamic
dispatch. Use metaprogramming only when it materially reduces repeated
structure and leaves discoverable behavior, tests, and error messages.
- Preserve exception context. Rescue only errors the current boundary can
handle, and convert them into a stable domain or CLI result where appropriate.
- Keep load-time work cheap and deterministic. Avoid network, filesystem,
process, or environment-dependent side effects during
require.
- Follow the repository's formatter and style configuration instead of applying
a different community style mechanically.
Ruby Anti-Patterns
Avoid:
- global monkey patches to core classes or dependencies;
method_missing, callbacks, DSL magic, or reflection where an explicit API is
simpler and easier to test;
- mutable constants, global variables, class variables used as shared state, or
singleton service registries that hide ownership;
- rescuing
Exception, broad rescue-and-continue behavior, swallowed failures,
or retry loops without bounds and an error policy;
- shell command strings assembled from input, backticks for complex process
control, or ignored subprocess exit status;
- implicit working-directory assumptions and unscoped temporary files;
- tests that stub the object under test, assert private call order, or replace so
many collaborators that no real behavior remains; and
- framework models, callbacks, or persistence types leaking into domain APIs
without an intentional boundary.
Testing Ruby
Use the test framework already owned by the repository.
- Unit: test value objects, parsers, formatters, validation, domain rules,
enumerators, and error behavior without external resources.
- Integration: exercise real filesystem, subprocess, database, framework,
gem, serialization, and adapter boundaries in isolated fixtures.
- CLI/process: invoke the executable when arguments, environment, stdout,
stderr, signals, or exit status are part of the contract.
- End to end: cover a complete supported user or operator workflow only when
lower levels cannot prove the behavior. Use the repository's web/system-test
stack; do not assume Rails, Capybara, Selenium, or a browser runner.
For Minitest, preserve the repository's spec-style or class-style convention and
run its configured Rake or direct Ruby lane. For RSpec, preserve configured
formatters, tags, helpers, and suite boundaries and use the Bundler-bound command.
Do not migrate between them merely for preference.
Keep tests deterministic and isolated. Use temporary directories, fake clocks,
seeded randomness, and boundary substitutes where needed; avoid live networks,
shared databases, process-global leakage, order dependence, and unbounded sleeps.
Mock external boundaries, not the behavior being specified.
Typical checks to derive from repository evidence include:
ruby -c path/to/file.rb
bundle exec ruby -Itest path/to/test_file.rb
bundle exec rake test
bundle exec rspec path/to/spec_file.rb
bundle exec rubocop
Do not claim a command exists or passed without observing it. Use
test-driven-development for behavior
changes and regressions, and systematic-debugging
for an active unexplained Ruby failure.
Ruby As A Script Choice
Prefer Ruby when all required targets provide the supported runtime and one or
more of these are true:
- the repository already uses Ruby and the script can reuse maintained code or
locked gems;
- structured text, files, APIs, reusable functions, or CLI parsing have outgrown
a small shell wrapper;
- Ruby's collection, string, regular-expression, or DSL capabilities express the
task clearly without introducing an additional runtime; or
- the automation is naturally adjacent to a Ruby application, gem, or Rake
workflow.
Do not choose Ruby when a short portable shell command is clearer, Ruby is
absent from a bootstrap or deployment target, the repository already has a
suitable supported automation language, or author familiarity is the only
advantage. Domain behavior that callers should import belongs in the application
or library, with a thin script or CLI entry point at most.
Security And Completion
Load security-review when Ruby code handles
untrusted input, paths, serialization, templates, commands, credentials,
privileged operations, or remote targets. Use
security-review-evidence when logs,
fixtures, reports, or reproduced output may contain sensitive values.
Before handoff, report the Ruby and Bundler evidence, why Ruby fit the task,
tests and quality gates run, dependency or lockfile impact, skipped platforms,
and residual runtime, compatibility, or security risk.
1---2name: ruby-engineering3description: Ruby engineering guidance. Use when creating, changing, reviewing, testing, packaging, or scripting Ruby source, gems, Gemfiles, Bundler, Rake, Minitest, RSpec, Rails-adjacent Ruby, or Ruby CLIs. Do not use merely to choose among scripting languages without Ruby implementation, or for framework-specific behavior whose owning skill is more precise.4---56# Ruby Engineering78Use this skill for repository-backed Ruby implementation and workflow decisions.9Inspect the supported Ruby version, Bundler and gem policy, source layout, test10framework, style tools, and execution targets before assuming a universal Ruby11setup.1213Use [`script-engineering`](../script-engineering/SKILL.md) when the primary14decision is whether automation should be a script or whether Ruby fits better15than shell, Python, PowerShell, or JavaScript. This skill owns the Ruby mechanics16after Ruby is selected.1718## MCP SDK Deferral1920For an MCP request, load21[`mcp-server-engineering`](../mcp-server-engineering/SKILL.md) and its dated22[SDK selection record](../mcp-server-engineering/references/sdk-selection.md).23That record owns Ruby's current eligibility, authority, package/version, tier,24core-revision, transport, lifecycle, and conformance caveats.2526Do not prescribe Ruby MCP gem APIs or server/client wiring from this skill.27Defer implementation selection until current official evidence and target28validation qualify the selected surface; retain this skill for ordinary Ruby29mechanics only.3031## Workflow32331. Read repository instructions, `.ruby-version`, version-manager files,34 `Gemfile`, `Gemfile.lock`, gemspecs, `Rakefile`, source/tests, CI, and existing35 Ruby commands.362. Identify supported Ruby and Bundler versions, target operating systems, and37 whether the code is an application, library, gem, CLI, or repository script.383. Preserve the repository's framework and conventions. Do not introduce Rails,39 RSpec, Minitest, RuboCop, Sorbet, Steep, or another tool without evidence or40 an explicit adoption goal.414. Define observable behavior and choose the narrowest useful test boundary.425. Implement small explicit objects, modules, and functions; isolate external43 processes, filesystems, clocks, networks, and databases behind testable44 boundaries.456. Run focused syntax, test, lint, and packaging checks before broader46 repository-native validation.477. Report versions and commands observed, files and dependencies changed,48 validation run, skipped targets, and remaining compatibility risk.4950## Runtime And Dependency Discipline5152- Treat `.ruby-version`, `.tool-versions`, `mise.toml`, gem metadata, CI images,53 and deployment configuration as runtime evidence. A locally available `ruby`54 does not prove every target supports that version.55- Use the repository's Bundler workflow. Prefer `bundle exec <command>` for56 project-owned executables when that is the established way to bind commands to57 the lockfile.58- Keep `Gemfile` intent and `Gemfile.lock` changes aligned. Do not hand-edit59 lockfile resolution or introduce a global gem dependency for project behavior.60- Prefer the standard library for small needs when it is clear and sufficient.61 Add a gem only when its maintained behavior outweighs dependency, native62 extension, startup, licensing, and supply-chain cost.63- Load64 [`dependency-supply-chain-review`](../dependency-supply-chain-review/SKILL.md)65 for new gems, lockfile churn, native extensions, sources, install hooks,66 provenance, or advisory questions.6768## Local CPU Parallelism Routing6970Compose with [`parallelism-engineering`](../parallelism-engineering/SKILL.md)71when a local CPU-bound Ruby workload needs data or task decomposition, partition72sizing, bounded worker-pool design, deterministic reduction, cancellation, or73nested-parallelism control. That skill owns the cross-language parallel design;74this skill owns Ruby runtime, library, gem, test, and process/thread mechanics.7576Do not route routine async I/O, event-loop behavior, fibers, ordinary background77work, or generic Ruby concurrency to `parallelism-engineering`; keep that work78with Ruby's implementation owner. Spark/PySpark execution remains with79[`data-platform-engineering`](../data-platform-engineering/SKILL.md), not local80parallelism engineering.8182## WebAssembly Routing8384Compose with [`webassembly-engineering`](../webassembly-engineering/SKILL.md)85when Ruby work includes a general WebAssembly decision: a WAT or `.wasm`86artifact, WASI or WIT, the Component Model, host/guest contract, runtime or87target selection, capability grants, or Wasm packaging and deployment. That88skill owns those Wasm boundary and compatibility decisions. This skill retains89Ruby source, gem, compiler or binding-tool, host-integration, and test90mechanics; the Wasm skill does not establish Ruby toolchain or binding support.9192## Idiomatic Ruby9394- Prefer clear message-oriented objects, modules, blocks, enumerators, keyword95 arguments, and standard collection APIs over manual indexing or framework96 ceremony.97- Keep methods cohesive and make mutation visible. Return useful domain values98 instead of relying on unrelated global or process state.99- Use modules for shared behavior or namespaces deliberately; do not use mixins100 as an unstructured substitute for object boundaries.101- Make public APIs explicit about accepted values, returned values, exceptions,102 side effects, and destructive or mutating behavior. Use `?` and `!` names only103 when they follow established Ruby meaning in the repository.104- Prefer ordinary methods, delegation, and explicit registration over dynamic105 dispatch. Use metaprogramming only when it materially reduces repeated106 structure and leaves discoverable behavior, tests, and error messages.107- Preserve exception context. Rescue only errors the current boundary can108 handle, and convert them into a stable domain or CLI result where appropriate.109- Keep load-time work cheap and deterministic. Avoid network, filesystem,110 process, or environment-dependent side effects during `require`.111- Follow the repository's formatter and style configuration instead of applying112 a different community style mechanically.113114## Ruby Anti-Patterns115116Avoid:117118- global monkey patches to core classes or dependencies;119- `method_missing`, callbacks, DSL magic, or reflection where an explicit API is120 simpler and easier to test;121- mutable constants, global variables, class variables used as shared state, or122 singleton service registries that hide ownership;123- rescuing `Exception`, broad rescue-and-continue behavior, swallowed failures,124 or retry loops without bounds and an error policy;125- shell command strings assembled from input, backticks for complex process126 control, or ignored subprocess exit status;127- implicit working-directory assumptions and unscoped temporary files;128- tests that stub the object under test, assert private call order, or replace so129 many collaborators that no real behavior remains; and130- framework models, callbacks, or persistence types leaking into domain APIs131 without an intentional boundary.132133## Testing Ruby134135Use the test framework already owned by the repository.136137- **Unit:** test value objects, parsers, formatters, validation, domain rules,138 enumerators, and error behavior without external resources.139- **Integration:** exercise real filesystem, subprocess, database, framework,140 gem, serialization, and adapter boundaries in isolated fixtures.141- **CLI/process:** invoke the executable when arguments, environment, stdout,142 stderr, signals, or exit status are part of the contract.143- **End to end:** cover a complete supported user or operator workflow only when144 lower levels cannot prove the behavior. Use the repository's web/system-test145 stack; do not assume Rails, Capybara, Selenium, or a browser runner.146147For Minitest, preserve the repository's spec-style or class-style convention and148run its configured Rake or direct Ruby lane. For RSpec, preserve configured149formatters, tags, helpers, and suite boundaries and use the Bundler-bound command.150Do not migrate between them merely for preference.151152Keep tests deterministic and isolated. Use temporary directories, fake clocks,153seeded randomness, and boundary substitutes where needed; avoid live networks,154shared databases, process-global leakage, order dependence, and unbounded sleeps.155Mock external boundaries, not the behavior being specified.156157Typical checks to derive from repository evidence include:158159```sh160ruby -c path/to/file.rb161bundle exec ruby -Itest path/to/test_file.rb162bundle exec rake test163bundle exec rspec path/to/spec_file.rb164bundle exec rubocop165```166167Do not claim a command exists or passed without observing it. Use168[`test-driven-development`](../test-driven-development/SKILL.md) for behavior169changes and regressions, and [`systematic-debugging`](../systematic-debugging/SKILL.md)170for an active unexplained Ruby failure.171172## Ruby As A Script Choice173174Prefer Ruby when all required targets provide the supported runtime and one or175more of these are true:176177- the repository already uses Ruby and the script can reuse maintained code or178 locked gems;179- structured text, files, APIs, reusable functions, or CLI parsing have outgrown180 a small shell wrapper;181- Ruby's collection, string, regular-expression, or DSL capabilities express the182 task clearly without introducing an additional runtime; or183- the automation is naturally adjacent to a Ruby application, gem, or Rake184 workflow.185186Do not choose Ruby when a short portable shell command is clearer, Ruby is187absent from a bootstrap or deployment target, the repository already has a188suitable supported automation language, or author familiarity is the only189advantage. Domain behavior that callers should import belongs in the application190or library, with a thin script or CLI entry point at most.191192## Security And Completion193194Load [`security-review`](../security-review/SKILL.md) when Ruby code handles195untrusted input, paths, serialization, templates, commands, credentials,196privileged operations, or remote targets. Use197[`security-review-evidence`](../security-review-evidence/SKILL.md) when logs,198fixtures, reports, or reproduced output may contain sensitive values.199200Before handoff, report the Ruby and Bundler evidence, why Ruby fit the task,201tests and quality gates run, dependency or lockfile impact, skipped platforms,202and residual runtime, compatibility, or security risk.