Debugging with the keys you already know

DetentShell · August 2026 · 2 min read

Set a breakpoint by clicking the gutter or pressing F9. Press F5. Execution stops on the red dot. F10 steps over, F11 steps into, Shift+F11 steps out, F5 continues, Shift+F5 ends the session. If you’ve debugged in the ISE or Visual Studio, you already know how to debug in DetentShell.

One behavior took us a while to get right, and it’s worth explaining because it looks like a small thing. In an early build, F5 always did a plain run. Breakpoints only fired if you used the separate Start Debugging menu item. Technically documented, completely wrong in practice: people set a breakpoint, pressed F5, watched the script run straight through, and concluded breakpoints were broken. Now F5 checks whether you have an enabled breakpoint. If you do, it runs under the debugger and stops there. The red dot means what it appears to mean.

At a stop, the Call Stack panel lists frames innermost first with file and line. Clicking a frame moves the execution pointer and re-scopes the Watch panel to that frame. The watch evaluator runs your expressions through the engine’s debugger channel in the paused frame. That detail matters because the obvious implementation, sneaking the expression into the console, would deadlock against the very pipeline you just paused.

Everything rides on PowerShell 7’s own debugger API. A stop is a real DebuggerStop event, a step is a real resume action, and that’s why the odd corners behave: Break All (Ctrl+B) pauses a running script at its next statement, disabled breakpoints stay visible in the gutter without firing, and ending a debug session leaves your session variables in place so you can inspect the aftermath at the prompt.

You’ll also notice DetentShell asks you to save before debugging an unsaved buffer, and there’s no “debug anyway” option. That’s covered in its own post about breakpoints, but the short version: breakpoints bind to a file and line number, and debugging text that doesn’t match any file gets you stops on lines you can’t see.

The whole flow runs as automated UI tests against the compiled app on every release: F5 stops at the breakpoint, F10 advances the stack from line 1 to line 2, Shift+F5 disables the Continue button, gutter clicks register. Each scenario records a video. When the F5 continue path broke once, a test failed with footage attached, and the fix shipped with a regression test before any user saw the bug.

← All posts