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.
Why MonkeyLens?
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?
Install
Add the gem to your bundle:
gem "monkey_lens"Then run:
bundle installInstall directly from the official RubyGems release:
gem install monkey_lensQuick start
Create .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 checkCLI
monkeylens 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
Load an application before capture
bundle exec monkeylens capture \
--require ./config/environment \
--output .monkeylens.jsonJSON or SARIF output
bundle 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.
Library API
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?Rake integration
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.
Rails integration
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"
endChange severities
| Change | Default severity |
|---|---|
| Method owner changed | Critical |
| Super-method owner changed | High |
| Method source changed | High |
| Method removed | High |
| Prepend/ancestor order changed | High |
| Method signature changed | Medium |
| Visibility changed | Medium |
| Method aliases changed | Medium |
| Method added | Low |
The threshold is configured with fail_on: low|medium|high|critical.
Design guarantees
- 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.
Documentation
Funding
MonkeyLens supports:
License
MIT © 2026 Matthew Looney