Every explanation is grounded in real interpreter state — not a guess about what a line of code "probably" does.
Live stack & heap graph
Every frame and heap object gets rendered as a node in a live graph — you see the call stack grow and shrink, not just printed text.
A tool-calling agent, not a narrator
The explanation agent calls state_diff, ast_scope_lookup, and a concept search tool — it only explains what actually changed.
Mutation vs. rebind, correctly
state_diff checks heap identity, not just value — so "the list changed" and "the name points somewhere new" are never confused.
Jina-embedded concept search
A small curated knowledge base — mutation vs. rebind, call/return, exception propagation — is embedded with Jina and searched via Qdrant for grounding.
Sandboxed by default
Imports are blocked, builtins are restricted, dunder-escape patterns are rejected — plus a step limit and wall-clock timeout on every run.
Structured output, always
Every explanation is validated JSON — title, body, key concept, and UI highlight targets — so the frontend never has to parse free text.