From python-remote-debug-skill
Debug running Python processes using Python 3.14+ sys.remote_exec(). Inject debugging scripts to get stack traces from stuck processes, including gevent-based Celery workers with greenlet introspection.
How this skill is triggered — by the user, by Claude, or both
Slash command
/python-remote-debug-skill:debug-remoteThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill helps you debug running Python processes by injecting debugging scripts using `sys.remote_exec()`. This is especially useful for diagnosing stuck or misbehaving processes without stopping them.
This skill helps you debug running Python processes by injecting debugging scripts using sys.remote_exec(). This is especially useful for diagnosing stuck or misbehaving processes without stopping them.
com.apple.system-task-ports)# Find by name pattern
pgrep -f "python.*my_script"
# More detailed view
ps aux | grep python
The skill includes ready-to-use scripts in skills/debug-remote/scripts/:
debug_threads.py - For standard Python processesdebug_gevent.py - For gevent-based processes (Celery with -P gevent)sudo python3.14 -c "import sys; sys.remote_exec(<PID>, '/path/to/debug_threads.py')"
Output files are named with the target PID to avoid overwrites when debugging multiple processes:
cat /tmp/debug_threads_<PID>.txt
Celery workers using the gevent pool (-P gevent) require special handling because they use greenlets (cooperative threads) instead of OS threads.
The Problem: sys._current_frames() only shows OS threads, not gevent greenlets. A gevent worker typically shows just one OS thread (the hub) even when many greenlets are active.
Use the provided debug_gevent.py script which:
gc.get_objects()Output is written to /tmp/debug_gevent_<PID>.txt.
When using watchmedo for auto-restart, multiple processes exist:
ps -p $(pgrep -f "celery.*worker" | tr '\n' ',') -o pid,ppid,command
Typical output:
PID PPID COMMAND
79130 72223 .../watchmedo auto-restart ... # Parent watcher - NOT this one
79136 79130 .../celery -A myapp.celery worker ... # Actual worker - USE THIS
79147 72223 tail -f celery-worker.log # Log tailer
One-liner to debug a stuck Celery worker:
PID=$(pgrep -f "celery.*worker" | head -1) && \
echo "Attaching to PID $PID" && \
sudo python3.14 -c "import sys; sys.remote_exec($PID, 'debug_gevent.py')" && \
sleep 1 && cat /tmp/debug_gevent_$PID.txt
If you need to kill a stuck worker (not the watchmedo parent):
kill -9 $(ps -p $(pgrep -f "celery.*worker") -o pid,command | grep -v watchmedo | awk 'NR>1 {print $1}')
yfinance/multi.py:158 → _time.sleep)concurrent.futures.ThreadPoolExecutor which can conflict with geventUse /python-remote-debug-skill:debug-remote when:
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub promptromp/python-remote-debug-skill --plugin python-remote-debug-skill