Appendix D — The Debugger
Nex includes an interactive debugger in the CLI REPL. This appendix condenses the main commands from docs/md/DEBUGGER.md into a tutorial-oriented quick reference.
D.1 Starting the Debugger
Start the REPL:
clojure -M:replEnable debugging:
:debug on
Check status:
:debug status
Disable:
:debug off
D.2 Breakpoints
Create breakpoints:
:break <spec>
:break <spec> if <expr>
:tbreak <spec>
Common breakpoint forms:
Class.methodClass.method:42file.nex:42field:statusOrder#status
List breakpoints:
:breaks
Remove them:
:clearbreak <id>
:clearbreak <spec>
:clearbreak all
Enable or disable without removing:
:enable <id>
:disable <id>
D.3 Watchpoints
Watchpoints pause when an expression’s value changes.
:watch <expr>
:watch <expr> if <expr>
:watches
:clearwatch <id|all>
:enablewatch <id|all>
:disablewatch <id|all>
Useful for fields or derived state that change across a long execution.
D.4 Break-On Policies
Pause automatically on failures:
:breakon exception on
:breakon contract on
Show status:
:breakon status
Filters:
:breakon exception on <substring>
:breakon contract on <pre|post|invariant>
These are particularly helpful in a contract-heavy language because they let you stop exactly when a precondition, postcondition, or invariant fails.
D.5 Debug Prompt Commands
When execution pauses, the prompt changes to dbg>.
Execution control:
:continueor:c:stepor:s:nextor:n:finishor:f
Inspection:
:where:frames:frame <n>:locals:print <expr>
The most useful first commands at a breakpoint are usually:
:where:locals:print <expr>
D.6 Typical Workflow
nex> :debug on
nex> :break Wallet.spend
nex> :breakon contract on
nex> :load examples/wallet.nex
nex> run_wallet_demo()
dbg> :where
dbg> :locals
dbg> :print money
dbg> :next
dbg> :continue
This is enough for most day-to-day debugging:
- stop at a routine
- inspect the active frame
- step through the logic
- continue once the cause is understood
D.7 Hit-Frequency Controls
Breakpoints can be tuned:
:ignore <id> <n>
:every <id> <n>
Use these when a loop or frequently called routine hits too often to inspect comfortably.
D.8 Saving and Scripting Debug State
Persist breakpoints and watchpoints:
:breaksave path/to/debug_state.edn
:breakload path/to/debug_state.edn
Drive the debugger from a command file:
:debugscript path/to/commands.dbg
:debugscript status
:debugscript off
D.9 Limits to Remember
- Stepping is statement-level, not expression-level.
file:linebreakpoints are most useful for code loaded from files.- Breakpoints are session-local unless saved.
:print <expr>runs in the paused context and may have side effects.
D.10 Worked Session
Suppose Wallet.spend has a precondition and an invariant:
class Wallet
feature
money: Real
spend(amount: Real)
require
enough: amount <= money
do
money := money - amount
ensure
decreased: money = old money - amount
end
invariant
non_negative: money >= 0.0
end
If you enable:
:debug on
:breakon contract on
and then violate the contract, the debugger will stop at the failure point. At that moment:
:whereshows the current routine and source location:localsshowsamount,money, and any locals:print amount <= moneychecks the failing condition directly
This is often faster than reading the whole routine from the top.
D.11 Further Reading
For the complete command set and current implementation notes, see docs/md/DEBUGGER.md.