Keyboard-driven terminal debugger for MeTTa with split panes, live space inspection, watches, breakpoints, trace browsing, and a scriptable CLI.
Terminal UI · Interactive debugging · JSON-RPC debugger · Multi-pane inspection · Batch CLI
Tape-driven HD terminal session: pane navigation, stepping, watches,
breakpoints, inline eval, space filtering, live load, themes, and help.
Source tape: docs/tapes/metta-tui-debugger-demo.tape.
MeTTa TUI Debugger brings step-through MeTTa debugging to a full-screen terminal workflow. It includes panes for source state, atomspace inspection, trace history, watch expressions, bindings, call stack, reduction trace, and command input.
The TUI launches metta-debugger as a subprocess and speaks JSON-RPC over
stdin/stdout. The debugger runtime and the terminal UI are packaged together in
one local Rust package, metta-tui, with three binaries:
metta-tui: full-screen terminal debuggermetta-debugger: JSON-RPC debugger engine linked with vendored Hyperonmetta-debug-cli: non-TUI command-line debugger for scripts and agents
- Step into, step over, step out, step back, continue, and run to completion.
- Inspect live atomspace contents with filtering, pagination, and space switching.
- Add watch expressions and re-evaluate them at each debugger stop.
- Use pattern, line, conditional, atom-type, depth-bound, mutation, and logpoint breakpoints.
- Search within panes, filter traces, and export session state.
- Explore nondeterministic branches and inspect alternate outcomes.
- Save checkpoints, restore state, diff atomspace changes, and inspect a timeline view.
- Switch themes, use ASCII borders, copy pane contents, and replay tape scripts.
- Drive the same debugger engine from
metta-debug-cliwithout opening the TUI.
cargo build -p metta-tui --bins --offlineThe built binaries land under Cargo's target directory. Prebuilt release
binaries may also be available in bin/.
The wrapper sets METTA_DEBUGGER_BIN so the TUI uses the bundled debugger:
./run-tui.shOpen a specific file:
./run-tui.sh path/to/file.mettaRun the debug binary directly after building from source:
./target/debug/metta-tui crates/metta-tui/examples/quickstart.mettaIf the debugger binary is not next to the TUI binary, point the TUI at it:
METTA_DEBUGGER_BIN=./target/debug/metta-debugger \
./target/debug/metta-tui crates/metta-tui/examples/quickstart.metta# Debug a .metta file
metta-tui path/to/program.metta
# Debug a source string directly
metta-tui --source "(= (double $x) (* $x 2))\n!(double 21)"
# Interactive mode, then use :load or :file inside the TUI
metta-tuimetta-debug-cli initializes a fresh debugger session for each invocation,
optionally loads --file or --source, runs one command, and prints a
human-readable summary by default.
Use --llm for structured pretty JSON, or --compact-json for one-line JSON:
./bin/metta-debug-cli --source '!(+ 1 2)' run
./bin/metta-debug-cli --llm --source '!(+ 1 2)' run
./bin/metta-debug-cli --source '!(+ 1 2)' step --count 1
./bin/metta-debug-cli --file path/to/file.metta inspect-space --limit 25
./bin/metta-debug-cli self-test
./bin/metta-debug-cli protocol-helpThe rpc subcommand accepts raw debugger protocol command JSON when you need a
command that does not have a dedicated shell shortcut:
./bin/metta-debug-cli --source '!(+ 1 2)' rpc '{"command":"getState"}'Detailed CLI documentation is in docs/metta-debug-cli.md. A model-agnostic agent cheat sheet is in agent-skills/metta-debug-cli/SKILL.md.
| Flag | Description |
|---|---|
--source <code> |
Load a MeTTa source string directly |
--fps |
Show a real-time FPS counter in the top-right corner |
--ascii |
Use ASCII box-drawing characters instead of Unicode |
--log[=path] |
Enable logging to stderr or to a file |
--bug-report |
Print system info for bug reports and exit |
Eight panes are arranged in a resizable terminal grid:
| Pane | Purpose |
|---|---|
| Source | Current atom, step info, plan stack, and breakpoints |
| Space | Atomspace contents |
| Trace | Step-by-step reduction history |
| Watches | Live expression values |
| Bindings | Current variable bindings |
| Call Stack | Stack frames and current evaluation path |
| Reduction Trace | Detailed runtime reduction trace |
| Input | Command line |
Tab cycles focus between panes. The focused pane gets a highlighted border. Split handles between quadrants can be dragged with the mouse to resize.
| Key | Action |
|---|---|
| F11 / s | Step into one reduction |
| F10 / n | Step over the current expression |
| Shift+F11 / o | Step out to the caller depth |
| F5 / c | Continue until next breakpoint or completion |
| R | Run to completion with no breakpoint stop |
| F6 / p | Pause a running evaluation |
| b | Step back one step |
| r | Reset session while keeping the runtime |
| Key | Action |
|---|---|
| Tab | Cycle pane focus |
| Up / Down | Scroll focused pane vertically |
| Left / Right | Scroll horizontally or cycle branches |
| j / k | Vim-style scroll down or up |
| g / G | Jump to top or bottom |
| Home / End | Jump to top or bottom |
| Page Up / Page Down | Scroll by page |
| = | Reset split handles |
| Key | Action |
|---|---|
| Ctrl+T | Toggle Source pane between debug view and file view |
| / | Enter search mode |
| n / N | Next or previous search match |
| Esc | Exit search or command mode |
| ? | Toggle help overlay |
| i | Refresh space inspection |
| t | Refresh trace |
| Key | Action |
|---|---|
| Ctrl+Y | Copy focused pane content to the system clipboard |
| Shift+Drag | Select and copy text with terminal native selection |
| : | Enter command mode |
| q / Ctrl+C | Quit |
Press : to enter command mode. Type a command and press Enter to run it, or
Esc to cancel. Up and Down cycle through command history. Tab completes command
names.
| Command | Description |
|---|---|
b <pattern> |
Set a pattern breakpoint, such as b (double $x) |
b-line <line> |
Set a breakpoint on a source file line number |
bc <condition> |
Set a conditional breakpoint |
ba <metatype> |
Set an atom-type breakpoint |
bdb <min> <max> |
Set a depth-bound breakpoint |
lp <pattern> <expr> |
Set a logpoint |
bd <id> |
Remove a breakpoint by ID |
bl |
List all breakpoints |
bt <id> |
Toggle a breakpoint on or off |
mb <pattern> |
Set a mutation breakpoint |
| Command | Description |
|---|---|
e <expr> |
Evaluate a MeTTa expression in the current space |
evalb <expr> |
Evaluate with bindings |
inspect <atom> |
Inspect atom detail |
stepUntil <predicate> |
Step until a predicate condition is met |
| Command | Description |
|---|---|
w <expr> |
Add a watch expression |
wd <id> |
Remove a watch by ID |
| Command | Description |
|---|---|
spaces |
List all available spaces |
space [name] |
Switch to a different inspection space |
space-filter [pattern] |
Filter displayed atoms by substring |
space-next / space-prev |
Paginate through large spaces |
| Command | Description |
|---|---|
load <source> |
Load a MeTTa source string |
file <path> |
Load a MeTTa file |
view debug / view file |
Switch Source pane view |
| Command | Description |
|---|---|
checkpoint [id] [label] / cp |
Save debugger state |
restore [id] / rcp |
Restore a checkpoint |
diff |
Show space diff since last checkpoint |
timeline |
Open timeline scrubbing |
| Command | Description |
|---|---|
tc |
Clear the trace pane |
rt |
Refresh the reduction trace |
filter <pattern> |
Filter trace lines by substring |
filter |
Clear trace filter |
export <path> |
Export session state to JSON |
history |
Show expression evaluation history |
search-all |
Search across all panes |
| Command | Description |
|---|---|
copy |
Copy focused pane content to clipboard |
theme [name] |
Switch theme |
| `profile [on | off]` |
help |
Show command summary |
branch <index> |
Select a nondeterministic branch |
branches |
List branches at the current step |
metta-tui uses a poll-based event loop. The main loop runs at configurable
intervals and only renders when the app state is dirty:
- Drain pending debugger events such as stopped, completed, space changed, and output.
- Render the frame with ratatui when needed.
- Poll for terminal input.
- Dispatch key and mouse events to the app state machine.
The debugger subprocess runs separately. A background reader thread reads its stdout line by line and pushes parsed JSON-RPC events into a channel. The main loop drains that channel on each tick.
Terminal setup uses crossterm alternate screen mode, so the TUI does not pollute the user's scrollback buffer. A panic hook restores the terminal to its original state on crashes.
The Source pane's debug view pretty-prints deeply nested Rust Debug output with structural indentation. Short blocks stay inline; longer blocks expand with 2-space indentation. The output is syntax-highlighted using the active theme.
Long atoms in the Space pane are formatted with a tree-sitter-based Wadler-Lindig pretty-printer. Short atoms stay on one line. Long atoms break with indentation and form-specific formatting for common MeTTa constructs.
The Call Stack pane applies the MeTTa syntax highlighter to atom text in each stack frame, matching the coloring used in the Space and Trace panes.
The TUI reads ~/.config/metta-tui/config.toml on startup. See
crates/metta-tui/src/config.rs for available
options. Key bindings can be remapped through the [keybinds] section.
Use the bundled test runner after source edits or before handing the bundle to another agent:
./test-everything.shIt checks formatting, Rust tests, clippy, release builds, the CLI self-test, direct CLI commands, JSON-RPC server framing, TUI tape replay, and a PTY fast-input stress run.
Useful focused checks:
./bin/metta-debug-cli self-test
./bin/metta-debug-cli --llm self-test
timeout 12s script -qfec './bin/metta-tui --tape smoke-quit.tape --log=smoke-tui.log crates/metta-tui/examples/quickstart.metta' /tmp/metta-tui-debugger-smoke.typescript- ratatui: terminal UI rendering
- crossterm: terminal input, raw mode, and alternate screen
- tui-textarea: multi-line text input widget
- serde / serde_json: JSON encoding and debugger protocol decoding
- clap: CLI argument parsing
- anyhow: error handling
- arboard: system clipboard access
- fancy-regex: TextMate grammar regex support
- tracing / tracing-subscriber: structured logging
- notify: file watching and config reload infrastructure
- tree-sitter / tree-sitter-metta: MeTTa parsing and formatting
- Hyperon: vendored MeTTa runtime used by the debugger engine
See CONTRIBUTING.md for the basic workflow, focused commit guidance, checks, and documentation expectations.
MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.