Debugging
Last updated on July 28, 2026
You can attach a debugger such as VS Code to your Python phase code and set breakpoints, step through execution, and inspect variables.
Phases run inside a worker process, so debugging uses debugpy over a socket rather than an interactive terminal. Uncaught exceptions and tracebacks already appear in the logs; a debugger is for stepping through code interactively.
Debug Mode
Add debugpy to your project dependencies:
uv add debugpyRun with --debug:
tofupilot run --debugThe worker starts a debugpy listener and waits for a debugger to attach before running any phase. Debug mode also forces a single worker and disables phase timeouts, so a breakpoint pause is not interrupted.
Attach from VS Code with an "attach" configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to TofuPilot",
"type": "debugpy",
"request": "attach",
"connect": { "host": "localhost", "port": 5678 }
}
]
}Set breakpoints in your phase files, run tofupilot run --debug, then start the attach configuration. Use --debug-port to change the port from the default 5678.
Debug mode runs a single worker, so parallel slots run sequentially while debugging. Remove --debug for normal parallel execution.
Manual Attach
You can also start debugpy yourself from inside a phase, without debug mode. This works on any version but you manage the listener, single-worker execution, and timeouts yourself.
import debugpy
# Start the listener once and wait for the IDE to attach
if not debugpy.is_client_connected():
debugpy.listen(("localhost", 5678))
debugpy.wait_for_client()
def check_voltage(measurements, multimeter):
debugpy.breakpoint()
measurements.voltage = multimeter.measure_dc_voltage()When running manually, set execution.workers to 1 so the fixed port doesn't collide across workers, and remove any timeout on the phases you are debugging so a breakpoint pause isn't treated as a hung phase.
Do not combine a manual debugpy.listen() with --debug. Debug mode starts its own listener, and a second listen() on the same port raises an error.
How is this guide?