Using Ritz to debug Clojure in Emacs

Hugo Duncan / @hugoduncan


debug-repl George Jahad @georgejahad (with an insight by Alex Osborne @atosborne)
swank-clojure Phil Hagelburg @technomancy
CDT George Jahad @georgejahad

Started Ritz to provide Clojure debugging in SLIME via SLDB


  • transport (socket & bencode)

  • middleware stack

Driven by Chas Emerick / @cemerick


load-file op

Support for Clojure and ClojureScript

Leiningen Profiles

Configure your favourite middleware in ~/.lein/profiles.clj.


Or add project specific middleware in project.clj



Colin Jones @trptcolin


Laurent Petit @petitlaurent


Meikel Brandmeyer @kotarak VimClojure.

and …


An Emacs client for the nREPL protocol, unfettered by support of any other lisp.

Driven by Tim King

Install nrepl.el

nrepl.el is available as an Emacs package in Marmalade.

(require 'package)
(add-to-list 'package-archives
   . ""))

The git HEAD is packaged to MELPA.

(add-to-list 'package-archives
   . ""))

Install nrepl.el ...

In either case, to actually install nrepl:

M-x package-install nrepl

Running nrepl.el

Browse to a file in your clojure project an jack-in:

M-x nrepl-jack-in

Running nrepl.el ...

Start an nREPL server, possibly with lein.

lein repl :headless

Connect to the nREPL server. lein announces the port the REPL is running on.

M-x nrepl localhost 41045


Started life as a fork of swank-clojure, but is now a very different codebase.

Initially was to provide SLDB for Clojure in SLIME.

Now refactored to support nREPL.

Ritz Components


Ritz nREPL Middleware

Can be used in any nREPL server

javadoc for symbol
doc for related functions
Clojure doc for symbol
Clojure doc and description
simple and fuzzy completion
keep track of source forms

More Ritz Components

Middleware for function history via codeq
An nREPL server over HornetQ

Ritz Debugger

Refactored after reading Out of the Tar Pit, Ben Moseley, Peter Marks 2006.

  • Isolate mutable state
  • Provide simple data query and update ops
  • No preferred access path

Map for each connection, with assoc and update-in functions for different areas within the connection.

Ritz Debugger Middleware

nREPL and jdi

Could be used by other (non-emacs) clients.

Emacs package for nrepl.el extensions.

Ritz Debugger

debug ops

Using Ritz nREPL Debugger


Install the nrepl-ritz.el Emacs package:

M-x package-install nrepl-ritz

Add lein-ritz to you :plugins in ~/.lein/profiles.clj

:user {:plugins [[lein-ritz "0.6.0"]]

Using Ritz nREPL Debugger


Run the ritz nREPL server:

lein ritz-nrepl

Connect to the repl server, specifying the port:

M-x nrepl 4005

Break on exception

Examine stack traces before the stack unwinds. Needs to be turned on:

M-x nrepl-ritz-break-on-exception
user> (/ 1 0)

Break on exception - restarts

Filtering of exceptions is via "restarts" displayed as part of the stacktrace.

Divide by zero

 0: [CONTINUE] Pass exception to program
 1: [ABORT] Abort request.
 2: [IGNORE] Do not enter debugger for this exception type
 3: [IGNORE-MSG] Do not enter debugger for this exception message
 4: [IGNORE-CATCH] Do not enter debugger for exceptions with
    catch location clojure.lang.Compiler.*
 5: [IGNORE-LOC] Do not enter debugger for exceptions with throw
    location clojure.lang.Numbers.*

  0: clojure.lang.Numbers.divide (
  1: clojure.lang.Numbers.divide (
  2: ritz-conj.example/eval2845 (UNKNOWN:-1)

What's caught, and what's not

Any (try ... (finally ..)) block means that JPDA considers an exception within that block as caught

(with-open [f (io/reader f)] ...)

Makes filtering on caught/uncaught meaningless.

Jump to source

Linking source code to stack frames requires that the source is on the classpath.

The Ritz servers arrange this if the source code is in your local repository.

lein pom
mvn dependency:sources


You can evaluate an expression within the context of a frame. Just select the frame, and press:

  • 'e' and enter an expression to see the result in the message area.
  • 'd' and enter an expression to see a pretty printed result in a separate buffer.


In ritz-swank, just press Enter on any local variable to pop up the SLIME inspector.

Locals Clearing

Clojure does something called locals clearing, to avoid holding onto the head of lazy sequences. This can result in locals showing up as nil, even when they aren't really.

Can be switched off in 1.4+

Locals Clearing - Disable on Compile

Use a prefix argument (C-u)to the following commands to disable locals clearing on the code being compiled.

C-c C-cnrepl-ritz-compile-expression
C-c C-cslime-compile-defun
C-c C-kslime-compile-file

Locals Clearing - Disable Globally

To disable locals clearing globally:

(alter-var-root #'*compiler-options*
  assoc :disable-locals-clearing true)


SLIME only for now

Press C-c C-x C-b to set a breakpoint on any line (of clojure or java).

Restarts for Step, Step Over, and Step Out


Press 'D' on any frame to see the JVM bytecode for the frame


M-x nrepl-ritz-threads
:id  | :name                     | :status  | :at-breakpoint? | :suspended? | :suspend-count
     | system                    |          |                 |             |
     |   main                    |          |                 |             |
1    |     main                  | :wait    | false           | false       | 0
1569 |     JDI-VM-Control-Thread | :running | false           | true        | 1
1782 |     msg-pump4905          | :wait    | false           | false       | 0
5228 |   Reference Handler       | :wait    | false           | false       | 0
5229 |   Finalizer               | :wait    | false           | false       | 0
5230 |   Signal Dispatcher       | :running | false           | false       | 0

Project Support

Reload project to pick up classpath changes.

M-x nrepl-ritz-reload-project

Switch project

M-x nrepl-ritz-load-project

Run lein targets on project

M-x nrepl-ritz-lein

Split out into the nrepl-project project as an nREPL middleware.

Related Work

A version of debug-repl for nrepl.

The simplest thing that could work and not need any extra setup beyond nrepl.el.

Direction - Features

Parity with ritz-swank:

  • Breakpoints
  • Inspector

Other Ideas:

  • Log Evaluation of expressions
  • Make the debugger scriptable

Direction - Other possibilities

Scriptable debugging


nREPL middleware provides flexibility.

Make Ritz the goto place for middleware and debugger.