본문으로 건너뛰기
cccskills
무료GitHub에 공개한국어 소개

python-debugpy

Python 실행을 멈추고 변수와 실행 흐름을 살펴 오류 원인을 찾습니다. 상황에 따라 pdb와 debugpy를 사용하며, 실패한 테스트와 실행 중인 프로세스도 조사합니다.

원문원문 설명 보기

Debug Python: pdb REPL + debugpy remote (DAP).

AI 평가80점/ 100설치 방법 보기

이럴 때 유용합니다

  • 실패한 테스트의 변수를 확인합니다
  • 함수 안에서 컬렉션의 변화를 추적합니다
  • 예외 발생 지점의 변수를 확인합니다
  • 실행 중인 프로세스에 디버거를 연결합니다

한국어 소개

할 수 있는 일

Python 실행을 멈추고 변수 값과 함수 호출 흐름을 살펴 오류 원인을 찾습니다. 로컬에서는 breakpoint()나 python -m pdb를, 원격 환경이나 실행 중인 프로세스에서는 debugpy를 사용하는 절차를 안내합니다. 한 줄씩 실행하기, 조건에 따라 멈추기, 예외 발생 지점의 변수 확인, 자식 프로세스 조사도 다룹니다.

이럴 때 유용합니다

테스트 오류 메시지만으로 값이 잘못된 이유를 알 수 없거나, 함수 안에서 리스트와 딕셔너리가 어떻게 바뀌는지 추적할 때 유용합니다. 오래 실행되는 프로세스나 부모가 아닌 자식 프로세스에서 발생한 문제도 조사할 수 있습니다.

사용 예시

  • “이 테스트가 실패하는 지점에서 멈추고 변수와 호출 스택을 확인해 주세요.”
  • “실행 중인 Python 프로세스에 debugpy를 연결하는 절차를 정리해 주세요.”

주의 사항

Linux와 macOS를 지원합니다. 대상 환경에 debugpy를 미리 설치해야 합니다. Hermes에서는 운영 환경과 별도의 개발 및 테스트 환경을 준비합니다. 출력을 캡처하는 테스트 실행 환경에서는 대화형 조작이 불가능하며, 커밋 전에 실행을 멈추는 코드를 제거해야 합니다.

이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.

객관 평가

AI가 SKILL.md의 내용만을 근거로 4가지 관점에서 판정했습니다. 스타 수나 인기도는 판정에 넣지 않았습니다.

지시의 명확성언제 쓰고 무엇을 하는지 알 수 있는가
A양호실패한 테스트와 실행 중인 프로세스 등 상황별로 사용할 디버거를 제시합니다.
절차의 구체성절차·입출력·예시가 구체적으로 적혀 있는가
A양호pdb 명령 표와 중단점, 예외 조사, 프로세스 연결 코드 예시가 있습니다.
안전성전송·삭제·명령 실행 등을 명시하고 있는가
C확인 필요연결 실패 해결책으로 확인 절차 없이 sudo로 ptrace 제한을 해제하는 명령을 제시합니다.
도입의 용이성필요한 도구나 API 키가 적고 적혀 있는가
A양호지원 운영 체제와 debugpy를 포함한 독립 환경의 구성 및 확인 명령을 제시합니다.

총점은 각 항목을 A=25점, B=15점, C=5점으로 더한 값입니다. 2026년 10월 19일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.

평가가 다르다고 생각되면 재검토를 요청하기

어느 항목이 왜 다르다고 생각하는지 적어 주세요. 로그인은 필요 없습니다. SKILL.md와 대조해 평가를 다시 만들고 이곳에 반영합니다.

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

포함된 파일(1)

  • SKILL.md14.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Python Debugger (pdb + debugpy)

Overview

Three tools, picked by situation:

ToolWhen
breakpoint() + pdbLocal, interactive, simplest. Add breakpoint() in the source, run normally, get a REPL at that line.
python -m pdbLaunch an existing script under pdb with no source edits. Useful for quick poking.
debugpyRemote / headless / "attach to already-running process." Talks DAP, scriptable from terminal, works for long-lived processes (gateway, daemon, PTY children).

Start with breakpoint(). It's the cheapest thing that works.

When to Use

  • A test fails and the traceback doesn't reveal why a value is wrong
  • You need to step through a function and watch a collection mutate
  • A long-running process (hermes gateway, tui_gateway) misbehaves and you can't restart it
  • Post-mortem: an exception fired in prod-ish code and you want to inspect locals at the crash site
  • A subprocess / child (Python _SlashWorker, PTY bridge worker) is the actual bug site

Don't use for: things print() / logging.debug solve in under a minute, or things pytest -vv --tb=long --showlocals already reveals.

pdb Quick Reference

Inside any pdb prompt ((Pdb)):

CommandAction
h / h cmdhelp
nnext line (step over)
sstep into
rreturn from current function
ccontinue
unt Ncontinue until line N
j Njump to line N (same function only)
l / lllist source around current line / full function
wwhere (stack trace)
u / dmove up / down in the stack
aprint args of the current function
p expr / pp exprprint / pretty-print expression
display exprauto-print expr on every stop
b file:lineset breakpoint
b funcbreak on function entry
b file:line, condconditional breakpoint
cl Nclear breakpoint N
tbreak file:lineone-shot breakpoint
!stmtexecute arbitrary Python (assignments included)
interactdrop into full Python REPL in current scope (Ctrl+D to exit)
qquit

The interact command is the most powerful — you can import anything, inspect complex objects, even call methods that mutate state. Locals are read-only by default; use !x = 42 from the (Pdb) prompt to mutate.

Recipe 1: Local breakpoint

Easiest. Edit the file:

def compute(x, y):
    result = some_helper(x)
    breakpoint()           # <-- drops into pdb here
    return result + y

Run the code normally. You land at the breakpoint() line with full access to locals.

Don't forget to remove breakpoint() before committing. Use git diff or a pre-commit grep:

rg -n 'breakpoint\(\)' --type py

Recipe 2: Launch a script under pdb (no source edits)

python -m pdb path/to/script.py arg1 arg2
# Lands at first line of script
(Pdb) b path/to/script.py:42
(Pdb) c

Recipe 3: Debug a pytest test

Use terminal and the canonical runner for noninteractive diagnostics:

# Show locals in tracebacks without pdb:
scripts/run_tests.sh tests/path/to/test_file.py --showlocals --tb=long

scripts/run_tests.sh captures each file in a separate subprocess, so --pdb or --trace cannot provide an interactive prompt there. For an interactive debugger only, use the independent development/test interpreter prepared in Recipe 5 (never a production generation):

.venv/bin/python -m pytest tests/foo_test.py::test_bar --pdb

This bypasses the hermetic-env guarantees — fine for debugging, but re-run under the wrapper to confirm before pushing.

Recipe 4: Post-mortem on any exception

import pdb, sys
try:
    run_the_thing()
except Exception:
    pdb.post_mortem(sys.exc_info()[2])

Or wrap a whole script:

python -m pdb -c continue script.py
# When it crashes, pdb catches it and you're in the frame of the exception

Or set a global hook in a repl/jupyter:

import sys
def excepthook(etype, value, tb):
    import pdb; pdb.post_mortem(tb)
sys.excepthook = excepthook

Recipe 5: Remote debug with debugpy (attach to running process)

For long-lived processes: Hermes gateway, tui_gateway, a daemon, a process that's already misbehaving and can't be restarted clean.

Setup

For Hermes, use a separate development checkout and data home, not a live production generation. Follow the PM developer workflow and activate that checkout — PowerShell: . .\activate.ps1. The declared dev extra includes debugpy, which PM activation does not sync (all excludes it). Through terminal, build a fresh, caller-owned debug/test environment with the prepared checkout's Python:

source ./activate
python -m pm.build_env --source . --out .venv --group dev --group test
.venv/bin/python -c "import debugpy; print(debugpy.__file__)"

The output must not already exist. Stop its processes and intentionally remove only that disposable environment before rebuilding. Keep the same isolated HERMES_HOME for the debug target. .venv/bin/python is this explicitly built debug environment, not a guessed application venv, and the patterns below run through it. Do not add debugpy to a running production environment; reproduce there only with an already-prepared debug target or arrange a restart in the development environment.

Pattern A: Source-edit — process waits for debugger at launch

Add near the top of the entry point (or inside the function you want to debug):

import debugpy
debugpy.listen(("127.0.0.1", 5678))
print("debugpy listening on 5678, waiting for client...", flush=True)
debugpy.wait_for_client()
debugpy.breakpoint()       # optional: pause immediately once attached

Start the process; it blocks on wait_for_client().

Pattern B: No source edit — launch with -m debugpy

.venv/bin/python -m debugpy --listen 127.0.0.1:5678 --wait-for-client your_script.py arg1

Equivalent for module entry:

.venv/bin/python -m debugpy --listen 127.0.0.1:5678 --wait-for-client -m your.module

Pattern C: Attach to an already-running process

Needs the PID and debugpy preinstalled in the target's environment:

.venv/bin/python -m debugpy --listen 127.0.0.1:5678 --pid <pid>
# debugpy injects itself into the process. Then attach a client as below.

Some kernels/security configs block the ptrace-based injection (/proc/sys/kernel/yama/ptrace_scope). Fix with:

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

Connecting a client from the terminal

The easiest terminal-side DAP client is VS Code CLI or a small script. From inside Hermes you have two practical options:

Option 1: debugpy's own CLI REPL — not an official feature, but a tiny DAP client script:

# ~/.hermes/cache/scratch/dap_client.py
import socket, json, itertools, time, sys

HOST, PORT = "127.0.0.1", 5678
s = socket.create_connection((HOST, PORT))
seq = itertools.count(1)

def send(msg):
    msg["seq"] = next(seq)
    body = json.dumps(msg).encode()
    s.sendall(f"Content-Length: {len(body)}\r\n\r\n".encode() + body)

def recv():
    header = b""
    while b"\r\n\r\n" not in header:
        header += s.recv(1)
    length = int(header.decode().split("Content-Length:")[1].split("\r\n")[0].strip())
    body = b""
    while len(body) < length:
        body += s.recv(length - len(body))
    return json.loads(body)

send({"type": "request", "command": "initialize", "arguments": {"adapterID": "python"}})
print(recv())
send({"type": "request", "command": "attach", "arguments": {}})
print(recv())
send({"type": "request", "command": "setBreakpoints",
      "arguments": {"source": {"path": sys.argv[1]},
                    "breakpoints": [{"line": int(sys.argv[2])}]}})
print(recv())
send({"type": "request", "command": "configurationDone"})
# ... loop reading events and sending continue/stepIn/etc.

This is fine for one-off automation but painful as an interactive UX.

Option 2: Attach from VS Code / Cursor / Zed — if the user has one open, they can add a launch.json:

{
  "name": "Attach to Hermes",
  "type": "debugpy",
  "request": "attach",
  "connect": { "host": "127.0.0.1", "port": 5678 },
  "justMyCode": false,
  "pathMappings": [
    { "localRoot": "${workspaceFolder}", "remoteRoot": "<hermes-agent-repo>" }
  ]
}

Option 3: Ditch DAP, use remote-pdb — usually what you actually want from a terminal agent:

For an independently owned Python project, declare remote-pdb in that project's development dependencies and prepare its debug environment through the project's package manager. This is not a Hermes SDK install recipe. For Hermes, prefer the declared debugpy dependency; the remote-pdb examples below require a separately declared, freshly built debug environment, never an in-place pip install into the selected application generation.

In your code:

from remote_pdb import set_trace
set_trace(host="127.0.0.1", port=4444)   # blocks until connection

Then from the terminal:

nc 127.0.0.1 4444
# You get a (Pdb) prompt exactly as if debugging locally.

remote-pdb is the cleanest agent-friendly choice when debugpy's DAP protocol is overkill. Use debugpy only when you actually need IDE integration.

Debugging Hermes-specific Processes

Tests

See Recipe 3. The wrapper captures subprocess output, so run pytest directly for interactive pdb.

run_agent.py / CLI — one-shot

In the prepared debug checkout, add breakpoint() near the suspect line, then run python hermes. Control returns to your terminal at the pause point.

tui_gateway subprocess (spawned by hermes --tui)

The gateway runs as a child of the Node TUI. Options:

A. Source-edit the gateway:

# tui_gateway/server.py near the top of serve()
import debugpy
debugpy.listen(("127.0.0.1", 5678))
debugpy.wait_for_client()

Start python hermes --tui from the prepared debug checkout. The TUI will appear frozen (its backend is waiting). Attach a client; execution resumes when you continue. Check the child's interpreter and imports before assuming it inherited the debug environment.

B. Use remote-pdb at a specific handler:

from remote_pdb import set_trace
set_trace(host="127.0.0.1", port=4444)   # in the RPC handler you want to trap

Trigger the matching slash command from the TUI, then nc 127.0.0.1 4444 in another terminal.

_SlashWorker subprocess

Same pattern — remote-pdb with set_trace() inside the worker's exec path. The worker is persistent across slash commands, so the first trigger blocks until you connect; subsequent slash commands pass through normally unless you re-arm.

Gateway (gateway/run.py)

Long-lived. Use remote-pdb at a handler, or debugpy with --wait-for-client if you're restarting the gateway anyway.

Common Pitfalls

  1. pdb under a parallel/output-capturing runner silently does nothing. You won't see the prompt, the test just hangs (true of pytest-xdist and of scripts/run_tests.sh's captured per-file subprocesses). Run pytest directly on a single file for interactive debugging.

  2. breakpoint() in CI / non-TTY contexts hangs the process. Safe locally; never commit it. Add a pre-commit grep as a safety net.

  3. PYTHONBREAKPOINT=0 disables all breakpoint() calls. Check the env if your breakpoint isn't hitting:

    echo $PYTHONBREAKPOINT
    
  4. debugpy.listen blocks only if you also call wait_for_client(). Without it, execution continues and your first breakpoint may fire before the client is attached.

  5. Attach to PID fails on hardened kernels. ptrace_scope=1 (Ubuntu default) allows only same-user ptrace of child processes. Workaround: echo 0 > /proc/sys/kernel/yama/ptrace_scope (needs root) or launch under debugpy from the start.

  6. Threads. pdb only debugs the current thread. For multithreaded code, use debugpy (thread-aware DAP) or set threading.settrace() per thread.

  7. asyncio. pdb works in coroutines but await inside pdb requires Python 3.13+ or await from interact mode on older versions. For 3.11/3.12, use asyncio.run_coroutine_threadsafe tricks or !stmt-based awaits via asyncio.ensure_future.

  8. scripts/run_tests.sh strips credentials and sets HOME=<tmpdir>. If your bug depends on user config or real API keys, it won't reproduce under the wrapper. Debug with raw pytest first to repro, then re-confirm under the wrapper.

  9. Forking / multiprocessing. pdb does not follow forks. Each child needs its own breakpoint() or set_trace(). For Hermes subagents, debug one process at a time.

Verification Checklist

  • In the independently built debug environment, confirm: .venv/bin/python -c "import debugpy; print(debugpy.__version__); print(debugpy.__file__)"
  • For remote debug, confirm the port is actually listening: ss -tlnp | grep 5678
  • First breakpoint actually hits (if it doesn't, you likely have PYTHONBREAKPOINT=0, you're under a parallel/capturing runner, or execution finished before attach)
  • where / w shows the expected call stack
  • Post-debug cleanup: no stray breakpoint() / set_trace() in committed code
    rg -n 'breakpoint\(\)|set_trace\(|debugpy\.listen' --type py
    

One-Shot Recipes

"Why is this dict missing a key?"

# add above the KeyError site
breakpoint()
# then in pdb:
(Pdb) pp d
(Pdb) pp list(d.keys())
(Pdb) w                # how did we get here

"This test passes in isolation but fails in the suite."

scripts/run_tests.sh tests/the_test.py   # confirm it fails under the isolated runner first
# For interactive debugging, or if it only fails WITH other tests, use the
# independent development/test interpreter prepared in Recipe 5:
.venv/bin/python -m pytest tests/ -x --pdb
# Now it pdb-traps at the exact failing test after state accumulated.

"My async handler deadlocks."

# Add at handler entry
import remote_pdb; remote_pdb.set_trace(host="127.0.0.1", port=4444)

Trigger the handler. nc 127.0.0.1 4444, then w to see the suspended frame, !import asyncio; asyncio.all_tasks() to see what else is pending.

"Post-mortem on a crash in an Ink child process / subprocess."

PYTHONFAULTHANDLER=1 python -m pdb -c continue path/to/entrypoint.py
# On crash, pdb lands at the frame of the exception with full locals

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

1password

무료요약 있음AI 평가 100점

1Password에 저장한 비밀번호와 API 키를 명령과 설정 템플릿에 사용합니다. CLI 설치와 인증부터 비밀 값 조회 및 환경 변수 전달까지 안내합니다.

  • 1Password CLI 설치와 설정
  • 저장된 API 키로 명령 실행
  • 설정 템플릿에 비밀 값 삽입
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

3-statement-model

무료요약 있음AI 평가 90점

손익계산서·재무상태표·현금흐름표를 수식으로 연결한 Excel 모델을 만듭니다. 실적과 예측 가정을 입력하고 시나리오를 비교하며 세 재무제표의 일관성을 단계별로 확인합니다.

  • 재무 템플릿에 실적 입력
  • 세 재무제표가 연동되는 예측 작성
  • 기본·상향·하향 시나리오 비교
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

accelerate

무료요약 있음AI 평가 80점

기존 PyTorch 학습 코드를 적은 수정으로 여러 GPU나 컴퓨터에 맞게 구성합니다. 혼합 정밀도, 메모리 절약 설정과 학습 실행 방법을 안내합니다.

  • 단일 GPU 학습을 여러 GPU로 옮깁니다
  • 혼합 정밀도 학습을 설정합니다
  • DeepSpeed나 FSDP로 메모리를 절약합니다
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

Configure Hermes to run AI models through Actual Computer on your own hardware. Set up either the hosted relay or a local connection, select models, verify responses, and troubleshoot request errors or empty output.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Connecting Hermes with an Actual inference key
  • Running models through a local Actual daemon
  • Downloading and loading local models
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

adversarial-ux-test

무료요약 있음AI 평가 80점

기술에 익숙하지 않고 쉽게 불만을 느끼는 사용자로 앱을 시험합니다. 혼란스러운 조작과 이탈 원인을 찾고, 개선 과제와 개인적 불만을 나눠 수정안을 정리합니다.

  • 출시나 시연 전에 사용성을 확인합니다
  • 신규 사용자의 경험을 점검합니다
  • 가입과 결제 과정의 어려움을 찾습니다
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

agent-merge-conflict-arbiter

무료요약 있음AI 평가 100점

두 에이전트가 각각 수정한 브랜치의 Git 충돌을 양쪽 변경 내용과 의도에 따라 중립적으로 해결합니다. 충돌별 판단 이유를 기록하고 빌드나 테스트로 통합 결과를 확인합니다.

  • 두 에이전트의 브랜치 충돌 해결
  • 병렬 worktree의 변경 내용 통합
  • 충돌하는 설계 판단의 이유 확인
NousResearch/hermes-agent25.5만2026년 10월 19일 업데이트

NousResearch의 스킬 모두 보기

이 스킬의 문제 신고