A Debug Adapter Protocol server for Clojure. Enables debugging UIs in Neovim, Helix, VS Code, and any other DAP-capable editor via CIDER's nREPL debug middleware.
Beta software. This works end-to-end but is under active development. Feedback welcome.
- A running nREPL server with CIDER middleware
- Java 21+ and Clojure CLI
clojure-dap is published to Clojars. No separate install is needed — the Clojure CLI fetches and caches the dependency on first run. The server is started with:
clojure -Sdeps '{:deps {uk.me.oli/clojure-dap {:mvn/version "RELEASE"}}}' -X clojure-dap.main/runPin to a specific version for reproducibility:
clojure -Sdeps '{:deps {uk.me.oli/clojure-dap {:mvn/version "0.1.311"}}}' -X clojure-dap.main/runVersions follow 0.1.<git-rev-count> — each release is a higher number. Use "RELEASE" to always get the latest, or pin a version in your editor config for stability.
clojure-dap is a standalone JVM the editor spawns when you start a debug session. It connects to your existing nREPL — start that however you like (Conjure, Calva, lein repl, clj with CIDER middleware, mise dev, etc.) so it writes .nrepl-port to your project root, and clojure-dap will pick the port up automatically. You can also pass host/port explicitly in the editor's attach config.
Keep stdout clean. The DAP server talks to the editor over stdio using JSON-RPC framing. The launch command itself must not print anything to stdout. The default
clojure -Sdeps … -X clojure-dap.main/runinvocation is safe; if you wrap it in your own script (e.g. formise-managed Clojure) make sure that wrapper doesn't print banners, status, or its own logs to stdout.
Requires nvim-dap. See its docs for keybindings and UI options like nvim-dap-ui.
local dap = require('dap')
dap.adapters.clojure = {
type = 'executable',
command = 'clojure',
args = {
'-Sdeps', '{:deps {uk.me.oli/clojure-dap {:mvn/version "RELEASE"}}}',
'-X', 'clojure-dap.main/run',
},
}
dap.configurations.clojure = {
{
name = 'Attach to nREPL',
type = 'clojure',
request = 'attach',
},
}Helix has built-in (experimental) DAP support. Add to ~/.config/helix/languages.toml:
[[language]]
name = "clojure"
[language.debugger]
name = "clojure-dap"
transport = "stdio"
command = "clojure"
args = ["-Sdeps", "{:deps {uk.me.oli/clojure-dap {:mvn/version \"RELEASE\"}}}", "-X", "clojure-dap.main/run"]
[[language.debugger.templates]]
name = "Attach to nREPL"
request = "attach"
args = {}Install Clojure DAP from the Visual Studio Marketplace, or from the command line:
code --install-extension olical.clojure-dapFor development, you can build and install a local .vsix from the vscode-extension/ directory with mise run vscode-package, then code --install-extension vscode-extension/clojure-dap-<version>.vsix.
The extension spawns the DAP server on demand when you start a debug session. Two settings tune the launch:
| Setting | Default | Purpose |
|---|---|---|
clojure-dap.command |
clojure |
Executable launched as the DAP server. Set to an absolute path if your clojure binary isn't on the GUI PATH (mise/asdf users) or to a wrapper that activates project tooling. |
clojure-dap.args |
["-Sdeps", "{:deps {uk.me.oli/clojure-dap {:mvn/version \"RELEASE\"}}}", "-X", "clojure-dap.main/run"] |
Arguments passed to the launch command. Override the :mvn/version to pin a specific clojure-dap release. |
Edit them from Settings → Extensions → Clojure DAP, scoped per workspace via the Workspace tab. Workspace settings land in .vscode/settings.json, so you can commit them with the project.
The DAP server logs at :trace level to a per-OS file path, plus stderr (which the editor captures). Defaults:
- Linux:
${XDG_STATE_HOME:-~/.local/state}/clojure-dap/clojure-dap.log - macOS:
~/Library/Logs/clojure-dap/clojure-dap.log - Windows:
%LOCALAPPDATA%\clojure-dap\clojure-dap.log
Set CLOJURE_DAP_LOG=/some/path/clojure-dap.log to override. The resolved path is logged on startup so the editor's debug console shows it too.
- Start your nREPL server with CIDER middleware
- Set breakpoints in your editor
- Attach the debug adapter
- Trigger the breakpointed code from a REPL
- Inspect variables, evaluate expressions, step through code
For an end-to-end walkthrough on a self-contained tiny project, see example/ — clojure -M:dev boots an nREPL with CIDER, code . opens the folder, F5 attaches.
By default clojure-dap connects to 127.0.0.1 and reads the port from .nrepl-port. You can pass explicit connection options in the attach config:
{
"clojure_dap": {
"type": "nrepl",
"nrepl": { "host": "127.0.0.1", "port": 7888 }
}
}Set breakpoints, hit them, inspect locals, evaluate expressions with access to local variables, step over/in/out, continue. See the protocol checklist below for details.
Tools are managed by mise. Run mise install to set up Java and Clojure CLI.
mise run test # Run all tests
mise run format # Format code
mise run repl # Start dev REPL
mise run outdated # Check for outdated depsSee doc/architecture.md for how DAP maps to CIDER's debug protocol.
- Attach
- ConfigurationDone
- Continue
- Disconnect
- Evaluate
- Initialize
- Next
- Scopes
- SetBreakpoints
- SetExceptionBreakpoints
- StackTrace
- StepIn
- StepOut
- Threads
- Variables
- Initialized
- Output
- Stopped
- Terminated