Getting started

Debug Delphi by talking to your AI agent.

Install the plugin in Claude Code, describe your bug in English, and your agent drives the debugger — sets breakpoints, launches the app, walks the stack, inspects objects, captures screenshots, even reads + edits the source to fix it. Three slash commands away.

Install the plugin Show alternatives

Install in 2 steps

Two prerequisites: a Windows host with an interactive RDP desktop (so the daemon can talk to GDI / DirectDraw), and an AI agent that can drive the rdbg wire — the plugin shipped today targets Claude Code, but the underlying MCP bridge speaks an open protocol. The plugin bundles all five rdbg binaries — no separate download or compile step. Free for Delphi 12 Community Edition targets; see the licensing tiers below for other Delphi versions.

Install the plugin in Claude Code

Two slash commands inside Claude Code — the first registers the marketplace, the second installs the rdbg-debugger plugin from a static-file git mirror (no GitHub account or auth needed). This is the only shipped install path today; other MCP-capable agents can wire the bridge in directly via their own MCP config (see the plugin's .mcp.json for the shape).

/plugin marketplace add https://sundaymorning.app/rdbg/.claude-plugin/marketplace.json
/plugin install rdbg-debugger@rdbg

The plugin ships all five binaries bundled in its bin/rdbgd64.exe + rdbgd32.exe (Win64 / Win32 daemons), rdbgc.exe (CLI), rdbgui.exe (GUI), and rdbg-mcp.exe (the MCP bridge that auto-finds itself). Five skills register (delphi-debugging-workflow, exception-triage, gui-bug-reproduction, delphi-rtti-inspection, vcl-self-discovery), three slash commands (/rdbg:status, /rdbg:start-daemon, /rdbg:install-help), and the delphi-bug-hunter autonomous subagent.

Want the standalone bin zip (e.g. for the GUI, for CI scripts, or for wiring the MCP bridge into your own AI tooling)? Grab rdbg-0.19.31-delphi12ce-bin.zip from the downloads page — same binaries, no plugin wrapper.

Verify with /rdbg:status

Run it from any Claude Code session (the slash command is a Claude Code feature). A healthy response looks like:

Daemon connection: rdbgd64 v0.19.31 (protocol 1) · active sessions: 0
Current sessions: none
Diagnostics: ok

If the daemon isn't running, /rdbg:status tells you so — and the bridge will auto-spawn it on the next real tool call from the bundled binaries. RDBG_AUTO_START=1 is the default. The daemon refuses to spawn from Session 0 (no GDI) — if you're SSH'd in, run your agent's host from inside your interactive RDP desktop.

Need the manual daemon-start instructions? Run /rdbg:start-daemon from Claude Code at any time, or read the printed-out instructions for any other launch path.

Just ask your agent

Five things you can say once the plugin is installed. Each example is real chat — the user's prompt, the agent's plan, the MCP tool calls under the hood.

You: Set a breakpoint at TForm1.btnComputeClick in MainForm.pas, launch bin\myapp.exe, and stop when it hits.

Agent: Setting the BP, launching, then waiting for the loader BP and the click handler.

tool: set_breakpoint(source="MainForm.pas", line=128)

{"ok":true, "bp_id":1, "resolved":"TForm1.btnComputeClick+0x0"}

tool: launch(exe="bin\\myapp.exe")

tool: continue()  (past the loader BP)

…you click the Compute button…

tool: events(timeout=30)

{"event":"breakpoint_hit", "bp_id":1, "tid":7892, ...}

Agent: Hit. Paused in MainForm.pas:128. Want me to step into it, inspect Self, or just continue?

You: What are the locals here?

Agent: Reading the params + stack-locals from the TD32 section.

tool: inspect_locals()

{"ok":true, "function_symbol":"MainForm.TForm1.btnComputeClick", "auto_walked_frames":0, "locals":[{"name":"Self","location":"reg","reg_id":0,...}, {"name":"Sender","location":"reg","reg_id":1,...}], "version_warning":null}

Agent: Self in RCX (this is a TForm1 method), Sender in RDX (the button object). Want me to chase Sender.Caption via evaluate?

If the target wasn't built with -V ("Place debug information in EXE" in the Project Options), the response carries error.message:"no_debug_section" with a fallback_hint; pivot to get_self + inspect_object for what you can still see.

You: Run myapp.exe and tell me about every exception that fires — even first-chance ones.

Agent: Setting a catch-all on kernelbase!RaiseException, enabling first-chance reporting, then launching.

tool: set_breakpoint(kind="symbol", symbol="kernelbase!RaiseException")

tool: set_exception_filter(first_chance=true)

tool: launch(exe="bin\\myapp.exe") & continue()

tool: events(timeout=60, filter="exception")

{"event":"exception", "class":"EConvertError", "message":"\"abc\" is not a valid integer", ...}

   Frames: SysUtils.pas:18432 ConvertErrorFmt+0x4f → MainForm.pas:201 TForm1.OnEditChange+0x12

Agent: First-chance EConvertError from OnEditChange — the user typed non-numeric text into the value field. Want me to inspect the exception object or the form's state?

You: Launch myapp.exe, wait for the main form to paint, screenshot it and describe what you see.

Agent: Launching, then capturing once the message pump's flushed a paint cycle.

tool: launch(exe="bin\\myapp.exe") & continue()

tool: get_main_form()

{"hwnd":"0x3fe00d6", "class":"TFormMain", "title":"My App"}

tool: capture_window(hwnd="0x3fe00d6")

→ PNG, 800×600, 47 KB

Agent: The main form is up. Top-left has a menu bar (File / Edit / View / Help). Beneath: a toolbar with New, Open, Save, Compute buttons. Centre is split — left pane is a tree of "Projects" with one root node "MyProject", right pane is empty with placeholder text "Select a project to begin". Status bar at the bottom reads "Ready · 0 items". No modal dialogs visible.

You: I'll demo the bug myself. Start recording my clicks and keys; I'll reproduce, then tell me which control received what.

Agent: Starting the spy. Reproduce the bug now — I'm listening.

tool: spy(action="start")

…you reproduce the bug, then say "done"…

tool: spy(action="stop")

→ 7 events captured

Agent: Here's what you did:

1. click Form1.PageControl1.tabExport.btnRunExport (left, 142,38)
2. key  Form1.PageControl1.tabExport.edtPath: "C:\\reports\\test.csv"
3. click Form1.PageControl1.tabExport.cboFormat (drop-down)
4. click [TListBoxItem 'CSV']
5. click Form1.PageControl1.tabExport.chkOverwrite
6. click Form1.PageControl1.tabExport.btnRunExport
7. crash — daemon emitted exception event

Agent: The crash fires after the second click on btnRunExport with overwrite enabled. I'll set a BP on the export handler and re-run from your trace — want me to do that now?

You: Launch the app, click Quit, then make sure the process is actually gone.

Agent: Launching, clicking Quit, polling until the PID disappears.

tool: launch(exe="bin\\myapp.exe") & continue()

tool: find_vcl_for_hwnd(name="btnQuit")

Form1.pnlBottom.btnQuit at hwnd 0x4002a8

tool: click_at(hwnd="0x4002a8", button="left")

tool: events(timeout=10, filter="exit_process")

{"event":"exit_process", "exit_code":0}

tool: list_processes(filter="myapp.exe")

[]

Agent: Clean exit, code 0, no orphaned process. Done.

Closed-loop bugfix

The full payoff: your agent reads the source, hypothesises the bug, sets BPs, drives the UI, inspects state at the BP, edits the file, and re-runs to confirm. No human in the loop after the initial prompt.

Scenario — "Compute returns wrong totals for negative inputs"

You: "There's a bug in MyApp where clicking Compute sometimes shows the wrong result — specifically when one of the inputs is negative. Find it and fix it."

Your agent's plan: read the relevant Pascal first, hypothesise, then verify at a breakpoint before patching. Cheaper than guessing.

Agent (1/6): Let me see how Compute wires up.

tool: Read(MainForm.pas)btnComputeClick calls FCalc.Sum(StrToInt(edtFrom.Text), StrToInt(edtTo.Text)).

tool: Read(Calculator.pas)TCalculator.Sum(A, B: Integer): Integer; var I: Integer; begin Result := 0; for I := A to B do Result := Result + I; end;

Agent: Hypothesis: when A > B (e.g. Sum(5, -3) after the user enters them in the wrong order), the for I := A to B do loop runs zero times because Delphi's for doesn't iterate when the start is past the end. Result stays at 0 instead of summing -3..5. I'll set a BP on Sum's entry and confirm.

Agent (2/6): Setting the BP and launching.

tool: set_breakpoint(source="Calculator.pas", line=42)  (line of Result := 0)

tool: launch(exe="bin\\myapp.exe") & continue()

Agent (3/6): Driving the UI to reproduce. Entering 5 and -3 (deliberately backwards), then clicking Compute.

tool: find_vcl_for_hwnd(name="edtFrom")Form1.edtFrom

tool: set_text_field(target="Form1.edtFrom", text="5")

tool: set_text_field(target="Form1.edtTo", text="-3")

tool: click_at(target="Form1.btnCompute")

tool: events(timeout=10)

{"event":"breakpoint_hit", "bp_id":1, ...}

Agent (4/6): At the BP. Reading the args from the registers + Self.

tool: get_registers()RCX = Self (TCalculator), RDX = 5 (A), R8 = -3 (B)

tool: step_over() through the for loop to its end.

tool: get_self() + inspect_object(addr, max_depth=1)

TCalculator { FLastResult: 0 } (Result variable holds 0 at function exit)

Agent: Confirmed. Sum(5, -3) returns 0 because the for I := 5 to -3 do loop body never executes. The bug is that Sum doesn't normalise its bounds. Fix: swap A and B if A > B before the loop.

Agent (5/6): Detaching, then patching Calculator.pas.

tool: detach()

tool: Edit(Calculator.pas)

@@ -38,7 +38,11 @@ function TCalculator.Sum(A, B: Integer): Integer;
 var
   I: Integer;
+  T: Integer;
 begin
+  if A > B then begin
+    T := A; A := B; B := T;   // normalise bounds (fixes negative-range bug)
+  end;
   Result := 0;
   for I := A to B do
     Result := Result + I;

Agent: Rebuild and re-test.

Agent (6/6): Re-launching to confirm.

tool: Bash(cd C:\\src\\myapp && dcc64 -B myapp.dpr)

tool: launch(exe="bin\\myapp.exe") & continue()

tool: set_text_field ×2 + click_at(btnCompute) (same inputs)

tool: events(timeout=10) → BP hit, step_over, get_self

TCalculator { FLastResult: 9 }  (-3 + -2 + -1 + 0 + 1 + 2 + 3 + 4 + 5 = 9)

tool: kill_session()

Agent: Fixed. Calculator.pas:38Sum now normalises its bounds before iterating; verified the (5, -3) case returns 9 instead of 0. Want me to add a unit test before committing?

For multi-step investigations like this, ask your agent to invoke the bundled bug-hunter subagent — it's purpose-built for the read → hypothesise → reproduce → inspect → fix loop, and keeps the conversation trail concise.

Other ways to drive rdbg

The plugin is the recommended path, but the underlying wire is open.

Prefer a GUI?

Run bin\rdbgui.exe from the same zip. Open a .dproj, hit Go — project tree, source tabs with gutter BPs, object explorer, stack walk. Local / SSH / attach connection modes.

Get the bin zip →

Prefer scripts, CI, or your own client?

The wire is line-delimited JSON over TCP. rdbgc.exe ships canonical CLI verbs (repl, debug, inspect, launch --spy, etc.); the agent guide walks the pause-loop semantics any client needs.

Read the agent guide →

Licensing & support

rdbg's binaries for Delphi 12 Community Edition are free under the MIT license. Other Delphi versions, source-code access, and integration work are available with a 12-month support contract.

Free

No contract · MIT license

  • Pre-built rdbgd64.exe + rdbgd32.exe for Delphi 12 Community Edition targets
  • rdbgc.exe CLI + rdbgui.exe GUI
  • The rdbg-debugger plugin for Claude Code — ships the MCP bridge, all five skills, and the bug-hunter subagent
  • Full wire-protocol documentation

For: hobbyists, evaluators, OSS Delphi devs, anyone using Delphi 12 CE.

Just download it.

Pro

12-month support contract · per-org

  • Everything in Free
  • Pre-built daemon binaries for any Delphi version — 11.3 (Alexandria), 13.x, future releases as Embarcadero ships them
  • Email support for the contract term — bug reports, integration questions, "does rdbg work with X?" sanity checks
  • Priority on roadmap items that block your team

For: teams shipping production Delphi apps on a non-CE Delphi.

Contact: damian@sundaymorning.app

Enterprise

12-month support contract · per-org

  • Everything in Pro
  • Full daemon source code with build instructions — audit it, extend it, ship a fork inside your org
  • Dedicated support hours — pair-debug a hard reproduction, prototype a custom wire method, integrate with your CI
  • Private channel for security disclosures

For: teams that need to extend rdbg, audit it for compliance, or run it on infrastructure that won't accept opaque binaries.

Contact: damian@sundaymorning.app

Embarcadero

One-off engagement · for IDE / RAD Studio integration

  • Everything in Enterprise
  • Source ownership transfer — rdbg becomes part of the upstream Delphi toolchain
  • A part-time junior developer engaged for the integration work — landing rdbg into the IDE / RAD Studio shell, wiring up the project group, the debugger UI, and the build pipeline
  • Ongoing collaboration through the integration milestone

For: Embarcadero itself, or a foundation acquiring rdbg as upstream.

Contact: damian@sundaymorning.app

All tiers carry the MIT license on the public bits. The contract covers binaries, source access, support, and (for Embarcadero) integration work — not a license-fee restriction on what you can do with what you've already received.

Troubleshooting

Common first-run issues.

/rdbg:status says daemon unreachable

Either the daemon hasn't been started or you're in Session 0 (a non-interactive Windows session). Run /rdbg:start-daemon from Claude Code for the manual start instructions; if you're SSH'd in headless, launch your agent's host from inside an interactive RDP desktop instead.

Plugin install fails with "marketplace not found"

Run the marketplace add command first, then the install. Both lines from step 2, in order. If it still fails, run /rdbg:install-help — the slash command prints the full standalone instructions.

Breakpoint won't resolve

The .map file is missing or doesn't have an address for that source line. Confirm myapp.map sits next to myapp.exe, and the line you picked has executable code (not a blank line, comment, begin/end token). Build with dcc64 -GD myapp.dpr for Win64 or dcc32 -GD myapp.dpr for Win32.

capture_window returns blank

The daemon must run on a host with an interactive desktop. Headless servers (Session 0, no display device) return blank PNGs. Direct2D / Direct3D / Chromium-embedded controls bypass the GDI compositor and capture as black even with a display; VCL native controls capture correctly.

Ready to debug?

Three slash commands and a bug report away. The plugin install takes about 30 seconds; the closed-loop bugfix flow above is what you do with it.

Install the plugin Browse all features