Audit monkey patches, method ownership, prepend layers, and Ruby runtime drift.
Official RubyGems gem · Documentation website · Latest GitHub release
MonkeyLens captures the effective Ruby method table for selected classes and modules, records who owns every method, tracks source locations, visibility, signatures, and ancestor order, then compares that runtime against a committed baseline.
It turns invisible runtime mutation into reviewable evidence.
Ruby deliberately makes classes open. That flexibility is powerful, but a production process can behave differently because a gem reopened a core class, a concern used prepend, a test helper redefined a method, or load order changed which implementation won.
MonkeyLens answers:
- Which methods were added, removed, or redefined?
- Which module currently owns the method Ruby will dispatch?
- Did a
prependlayer enter or leave the ancestor chain? - Did arity, parameters, visibility, or source location change?
- Does CI boot with the same runtime shape as the approved baseline?
Add the gem to your bundle:
gem "monkey_lens"Then run:
bundle installInstall directly from the official RubyGems release:
gem install monkey_lensCreate .monkeylens.yml:
targets:
- String
- Array
- MyApp::User
fail_on: high
format: textCapture the approved runtime:
bundle exec monkeylens capture --output .monkeylens.jsonCheck for drift:
bundle exec monkeylens checkmonkeylens capture Capture a runtime baseline
monkeylens check Compare the current runtime with a baseline
monkeylens diff Compare two saved snapshots
monkeylens inspect Explain one target's effective method table
monkeylens doctor Validate configuration and runtime support
monkeylens version Print the installed version
bundle exec monkeylens capture \
--require ./config/environment \
--output .monkeylens.jsonbundle exec monkeylens check --format json
bundle exec monkeylens check --format sarif > monkeylens.sarifSARIF output can be uploaded to GitHub code scanning or processed by other security tooling.
require "monkey_lens"
baseline = MonkeyLens.capture(targets: ["String", "MyApp::User"])
baseline.write(".monkeylens.json")
current = MonkeyLens.capture(targets: ["String", "MyApp::User"])
result = MonkeyLens.diff(baseline, current)
abort result.to_text unless result.clean?require "monkey_lens/rake_task"
MonkeyLens::RakeTask.new do |task|
task.config = ".monkeylens.yml"
task.baseline = ".monkeylens.json"
endThis creates monkey_lens:capture and monkey_lens:check tasks.
Add MonkeyLens to your development and test groups. Its Railtie adds the same Rake tasks after the application environment loads.
group :development, :test do
gem "monkey_lens"
end| Change | Default severity |
|---|---|
| Method owner changed | Critical |
| Method source changed | High |
| Method removed | High |
| Prepend/ancestor order changed | High |
| Method signature changed | Medium |
| Visibility changed | Medium |
| Method added | Low |
The threshold is configured with fail_on: low|medium|high|critical.
- Does not execute arbitrary project files unless explicitly passed with
--require. - Does not upload runtime information.
- Produces deterministic JSON for the same runtime state.
- Uses Ruby's public reflection APIs.
- Supports Ruby 3.2 and newer.
MonkeyLens supports:
MIT © 2026 Matthew Looney