Skip to content

feat: add --log flag for non-pausing logpoints#1

Open
mvanhorn wants to merge 1 commit intoillscience:mainfrom
mvanhorn:feat/logpoints
Open

feat: add --log flag for non-pausing logpoints#1
mvanhorn wants to merge 1 commit intoillscience:mainfrom
mvanhorn:feat/logpoints

Conversation

@mvanhorn
Copy link
Copy Markdown

@mvanhorn mvanhorn commented May 9, 2026

Summary

vibe-debug debug-python now supports --log 'FILE:LINE | MESSAGE' for non-pausing logpoints. The debugger continues past the line and emits the formatted message into the run's output (text and JSON), letting an agent observe state inside hot loops or async paths without paying the pause-eval-continue round-trip cost.

Why this matters

Today the only observation surface in debug-python is a pausing breakpoint plus --eval. For a function that runs many times (loop body, request handler, recursive call), an agent has two options: stop on every hit and re-eval (multiple round trips), or skip observation and guess. Logpoints are the standard third option: stop without stopping, get the formatted state in the response payload.

The Debug Adapter Protocol exposes this natively as logMessage on setBreakpoints, and debugpy supports it. Two adjacent agent-debugger projects ship the same capability:

Demo

logpoints demo

The demo runs a 3-iteration loop with two invocations:

  1. --log "loop_demo.py:5 | iter={i} value={value}" alone: prints three log lines and exits.
  2. --log ... --break loop_demo.py:6 --eval total: logs every iteration AND stops at line 6 to inspect the final state.

Output appears in a Logs: section above Stopped: (text mode) and a logs[] array alongside breakpoints/stopped/locals/evaluations (JSON mode).

Changes

  • cli.py: new _parse_logpoint parser for FILE:LINE | MESSAGE syntax, --log flag on debug-python, Logs: block in human output, and a file-grouping helper so multiple breakpoints in the same source go through a single setBreakpoints request (DAP setBreakpoints replaces all breakpoints for that source, so per-line calls would clobber).
  • session.py: set_breakpoints gains optional log_messages (plus conditions and hit_conditions for DAP parity, exposed via MCP only in this PR; CLI conditional/hit-count would be a follow-up). New drain_logpoints() filters DAP output events for matches by (source.path, line) when debugpy attributes them, with a template-regex fallback for outputs that arrive without source info.
  • mcp_server.py: debug_set_breakpoints gains an entries[] schema (alternative to lines) supporting logMessage/condition/hitCondition. debug_python_repro and debug_continue drain logpoints into the response.
  • README.md: documents the new flag in the Useful Options section.

Testing

22 tests pass (python -m unittest discover -s tests -v). New tests:

  • tests/test_cli.py::test_debug_python_logs_and_stops_at_breakpoint - end-to-end CLI run combining --log + --break + --eval
  • tests/test_cli.py::test_parse_logpoint_requires_separator - parser error case
  • tests/test_session.py (new file, 4 tests) - DAP request body shape, drain_logpoints happy path, template-regex fallback, ignoring unrelated program stdout
  • tests/test_mcp_server.py::test_debug_set_breakpoints_accepts_logpoint_entries - MCP entries[] shape

vibe-debug doctor and python tools/runtime_proof.py still pass.

Notes

This is a cold first PR. Happy to convert to a Discussion or close if the direction doesn't fit your roadmap. The scope creep on conditions/hit_conditions (MCP-only, no CLI exposure) was added because it sits along the same set_breakpoints seam; if you'd prefer to keep this PR strictly logpoints-only, I can strip those parameters and re-submit.

Logpoints emit a formatted message at a source line without pausing
execution. Useful for inspecting state inside hot loops and async
paths where pause-eval-continue is too disruptive.

CLI:
  vibe-debug debug-python script.py \
    --log 'script.py:7 | iter={i} value={value}' \
    --break script.py:18

Output (text and JSON) gains a 'logs' array containing the
formatted messages with file/line attribution. Combines naturally
with --break and --eval.

DAP plumbing:
  - DebugSession.set_breakpoints accepts log_messages (per-line)
  - DebugSession.drain_logpoints filters DAP output events for
    matches by (source.path, line) when debugpy attributes them
    or by template-regex fallback when source is empty
  - MCP debug_set_breakpoints gains an entries[] schema with
    optional logMessage / condition / hitCondition for DAP parity
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant