Pry, the Ruby console that walks bindings and shells out
A runtime developer console and IRB alternative with powerful introspection capabilities.
At a glance
- What is it?
- Pry is a Ruby REPL where almost everything is a command: cd walks the binding stack, ls filters what is in scope, a line starting with a period goes to the shell, and binding.pry drops you into live program state. Its two documented install routes disagree with each other, and the containerised test setup still builds against Ruby 2.1.
- Who is it for?
- Adopt Pry if you want state navigation, shell escape and history replay inside a Ruby session rather than a bare prompt, and install it with gem install pry so you get the current release instead of the pinned 0.15 line. Verify first that your Ruby version works with v0.16.1, since the install snippets name no interpreter (the README has a Supported Rubies section), and add pry-doc separately if you need to browse core C source.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- pry/pry6,840 ★ · +4
| Repository | 2026-09-27 | 2026-11-14 |
|---|---|---|
| pry/pry | 6.8k | 6.8k |
4 Stars in the last 48 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Install line pins 0.15.0 while v0.16.0 shipped
There are two documented ways in, and they disagree. The manual route is one command:
gem install pryThe Bundler route is written as a pinned dependency:
gem 'pry', '~> 0.15.0'That constraint has already gone stale. The newest release is v0.16.1, published 2026-10-20, following v0.16.0 on 2025-12-27 and v0.15.2 on 2024-12-24. A developer who copies the Bundler snippet into a Gemfile therefore gets the previous minor series, while gem install pry takes the current one, which is a confusing way to discover why a colleague's session behaves differently from yours.
Neither snippet names a Ruby version. The Dockerfile names Ruby 2.1.1 and 2.1.2, but it belongs to a different job; the README lists a Supported Rubies section.
The Docker file pins Ruby 2.1.1 and 2.1.2
The repository ships a Dockerfile on ubuntu:latest that installs wget, make and git, fetches ruby-install 0.4.3, compiles it and then installs two interpreters:
RUN ruby-install ruby 2.1.1Both 2.1.1 and 2.1.2 are installed, so the setup expects to compare two interpreters side by side. A script named multi_test_inside_docker.sh at the repository root is the obvious candidate for driving that.
The versions are the weak point. Both sit far behind the gem's current release line, and nothing in the file pins a newer interpreter. The last push to the repository was on 2026-09-27 and v0.16.1 shipped on 2026-10-20, so this container records how the project was set up to test at the time it was written rather than how the gem behaves against the interpreter you have installed. Weight it as history when you judge Ruby compatibility.
Commands must start at column zero, so pasted indentation fails
Nearly every piece of Pry's functionality is a command, and one rule governs all of them: a command is not a method, and it must start at the beginning of a line with no whitespace in between. That single sentence predicts a whole class of surprise. Paste a method body with its usual indentation and those lines are not commands; type a command with one leading space and it is not a command either.
Options behave the way they do in a shell. The example given for filtering what is in scope is:
ls -Mp --grep ^paRun inside YARD::Parser::SourceParser, it lists the private instance methods in scope beginning with pa, and the sample output is parse, parser_class, parser_type, parser_type= and parser_type_for_filename.
What you gain is one consistent grammar to learn and to script against.
readline in, puts out, and any object can host a shell
The architectural claim is about duck typing rather than subclassing. Pry reads from any object with a readline method and writes to any object with a puts method, and much of the rest is configurable through a customization wiki. That is why the project presents itself as a reasonable base for custom shells and not only as a console.
Two things follow from that shape. A front end written on top of Pry does not have to reimplement a terminal; it needs two endpoints that look method-compatible.
The same openness carries the cost. Because so much is pluggable, behaviour a reader assumes is fixed lives in plugins and in local files instead of inside the gem. A pryrc file in $XDG_CONFIG_HOME/pry/ or in the user's home directory is loaded if it exists, so two machines on the same gem version can hold different sessions.
cd, nesting and jump-to walk the binding stack
cd moves the session into another object, and ls reports what is available there. The worked example climbs the whole ladder: define class Hello with an instance variable at top level, cd Hello, ls -i to see @x, cd @x to land inside the value 20, then cd .. twice to climb back out.
The number after the colon in the prompt is the nesting level, a small detail that carries a lot of weight. nesting prints the stack with every level named, and jump-to takes a level number and lands you there directly, so returning to an earlier scope does not mean retyping the cd chain. In the sample, jump-to 1 from inside a string leaves the session at Hello.
The feature list also names exotic objects, BasicObject instances and IClasses, as supported.
binding.pry keeps whatever you changed in the session
Pry can be invoked in the middle of a running program, on any object with the my_object.pry syntax or on the current binding with binding.pry. The session opens at that point with all program state in reach, starts inside the scope of the object or binding, and when the session ends the program continues with the modifications you made.
The example makes that persistence concrete. A program requires pry, defines class A with a hello method, creates an instance and calls binding.pry. Inside the session the developer calls a.hello, then adds a method to the live object:
def a.goodbye
puts "goodbye cruel world!"
endCalling a.goodbye in the same session prints the new message, exit ends the session, and the program resumes. That behaviour is what makes Pry usable for debugging, for embedding a developer console and for applying hot patches. It is also the sharp edge: an edit made in the session is live in the running process with no confirmation step and no undo.
shell-mode puts the working directory in the prompt
A line that begins with a period is forwarded to the command shell, which is how you move around the file system, spawn an editor, or run git and rake without leaving the session. shell-mode goes further and folds the present working directory into the Pry prompt itself, together with file name completion that the project describes as limited at this stage.
shell-mode
.emacsclient .pryrcRuby string interpolation works inside those forwarded lines, so a shell command can be assembled from live values instead of typed out each time.
One limit deserves plain statement: the README calls file name completion limited at this stage.
pry-doc carries the C source browsing, not the gem
Some headline capabilities are not in the gem you install. Source code browsing, including core C source, is delegated to the pry-doc gem, and full debugging plus remote sessions arrive through plugins rather than through Pry itself. The project links a wiki page listing available plugins for exactly that reason.
That placement is the main thing to weigh against IRB. Pry puts a command system, state navigation, history replay and shell integration in the core, then pushes browsing and debugging outward. Its convenience commands are borrowed from IPython and Smalltalk, which is where the vocabulary comes from.
The boundary is also where the rough edges sit. Two capabilities people expect from a console stay unavailable until you add another gem.
Editorial conclusion
Adopt Pry if you want state navigation, shell escape and history replay inside a Ruby session rather than a bare prompt, and install it with gem install pry so you get the current release instead of the pinned 0.15 line. Verify first that your Ruby version works with v0.16.1, since the install snippets name no interpreter (the README has a Supported Rubies section), and add pry-doc separately if you need to browse core C source.
Frequently asked questions
How do I install Pry in a Ruby project?
Add it to your Gemfile as gem 'pry', '~> 0.15.0', or install it directly with gem install pry. The pinned constraint still targets the 0.15 series while the newest published release is v0.16.1 from 2026-10-20.
How do I start a Pry session inside a running Ruby program?
Require pry and call binding.pry where you want to stop, or call my_object.pry on a specific object. The session opens with the program state available at that point, and the program continues when you exit, keeping the changes made in the session.
What does the cd command do in Pry?
cd moves the session into another object or scope so ls can report what is there. The number after the colon in the prompt is the nesting level, nesting prints the whole stack, and jump-to returns you to an earlier level by number.
How do I run shell commands from inside Pry?
A line beginning with a period is forwarded to the command shell, which lets you navigate the file system, spawn an editor, or run git and rake. shell-mode adds the working directory to the prompt along with limited file name completion, and Ruby interpolation works inside those forwarded lines.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pry-pry)Star history chart for your README
[](https://hysenlabs.com/projects/pry-pry)Was this useful?