session-relay — 세션 자동 인계 파이프라인 (handoff)
C:\dev\tools\session-relay= 컨텍스트가 차기 전에 지금 세션이 직접 인계 지시문을 써서 새 Claude Code 세션(VS Code 확장)을 열고, 지시문을 넣고, 제출까지 하는 도구. 매뉴얼 전문 =C:\dev\tools\session-relay\README.md.
NOW
- ✅2026-07-30 한도 자동보정 스케줄러(
calibrate.py+ 예약작업SessionRelay-Calibrate, 매주 목 10:00pythonw)./usage대조 → 10% 넘는 차이만 보정·텔레그램 보고, 실패는 실패대로 보고. 리셋 시각도 매번 재동기화. 실측 dry-run = 추정 362,145,694 vs 기존 358,000,000(차이 1.2% → 유지). 자체검사test_calibrate.py15항목 ALL PASS. - ✅2026-07-30 안전장치 신설(
guard.py+state.json) — 체인 상한(12h/5회) · 매 릴레이 텔레그램 보고(답장중단으로 다음 릴레이 차단) · 주간 사용량 70% 게이트. 자체검사test_guard.py17항목 ALL PASS. ✅한도 확정 =weekly_token_budget 358,000,000—claude -p "/usage"(MSYS_NO_PATHCONV=1) 실측 주간 19% 와 같은 창 로컬 토큰 68,109,289 로 역산. 코디 계산 19.0% = /usage 19% 일치 검증. 주간 창은 리셋 기준(week_reset_iso8/3 22:00 KST). - ✅2026-07-30 첫 실전 릴레이 성공 — code-qa P0 잔여 5파트 인계문으로 새 세션
d0f91f22개통(브릿지 v1.6이 Enter 전송, 페페 재로드 후). 실측 확인 = 새 transcript 에 인계문이 첫 user 메시지로 들어갔고model=claude-opus-5. ⚠검증 거짓양성 발견·수정: 인계문 문자열이 릴레이를 돌린 세션 transcript 에도 있어find_transcript가 자기 자신을 새 세션으로 잡았다 → 실행 전 파일 스냅샷을exclude로 넘기게 수정(커밋8763458). - ✅2026-07-30 Enter 까지 자동화 완료(페페 승인). 주체 = 브릿지 확장 v1.6 —
/newsession {prompt, submit}가 프리필 후relay.py --enter-only --window-title <워크스페이스>를 띄운다. 확장은 VS Code 프로세스 안(Session 1)이라 자식의 SendInput 이 먹는다. 창 전면화도 자동(페페 지시).relay.py --submit auto=bridge. 확장 설치본(~/.vscode/extensions/delix0731.cody-bridge-1.3.0/)에 복사 완료. ⏳적용은 창 Reload 후(확장 재로드 필요). - 🔴2026-07-30 사고·교훈: 07-29 기록 "코디 Bash 는
GetForegroundWindow()=0이라 SendInput 무효"를 믿고--enter-only를 코디 Bash 에서 테스트했더니 Enter 가 실제로 나갔다(전면 창 Chrome 이 받음). → 키 전송은 대상 창 특정 → 전면화 → 전면 재확인 후에만(enter_into_vscode). 창을 못 찾으면 미전송. - ✅2026-07-30 실사용 환경 = 페페의 사용자 VS Code 인스턴스로 확정. 이전 미결 "릴레이용 창을 CDP로 띄울지"는
안 띄움으로 종결(CDP 격리 인스턴스 = 개발·검증 전용). auto 가 CDP 를 자동 탐색하지 않는 이유 =
프리필한 창과 CDP 포트가 다른 창일 수 있어 오발송.
자체검사
test_relay.py6항목(resolve_submit_mode·t_window_guard추가) ALL PASS. - ✅2026-07-29 신규 구축 + 상/중/하 3난이도 검증 전부 PASS(격리 VS Code 인스턴스, 기존 창 무간섭).
- ⏳페페 몫 = 다른 VS Code 창에도 v1.6 을 반영하려면 창마다
Developer: Reload Window1회(이 창은 반영됨).
불변 핵심 (실측 2026-07-29, 확장 anthropic.claude-code 2.1.220)
- 새 세션 + 프리필 =
claude-vscode.editor.open(sessionId, initialPrompt, viewColumn). URI 핸들러vscode://anthropic.claude-code/open?session=&prompt=도 실재하며 내부에서primaryEditor.open(session, prompt)를 부른다. 단code --open-url은 무반응이었고 URI는 어느 창으로 갈지 호출자가 못 정한다 → 오발송 위험 때문에 채택하지 않았다. - webview는 initialPrompt를
setInputText로 채우기만 하고 제출하지 않는다 → Enter는 밖에서. - 제출 = 브릿지 확장 v1.6 이 한다(2026-07-30 최종). 확장이
relay.py --enter-only --window-title <ws>를 자식으로 띄우고, 헬퍼가 Code.exe 창 특정 → 전면화 → 전면 재확인 후에만 Enter 를 보낸다. ⚠07-29 의 "코디 Bash 는GetForegroundWindow()=0이라 SendInput 무효" 전제는 틀렸다 — 실제로 키가 나가 전면의 Chrome 이 받았다. 그래서 창 확인 없는 전송을 코드로 금지했다. - 모델·노력도·thinking =
<workspace>\.claude\settings.local.json의model/effortLevel(low|medium|high|xhigh) /alwaysThinkingEnabled. 새 세션이 시작할 때 읽는다(이미 떠 있는 세션은 안 바뀐다). 실측 확증 =--model sonnet→ transcriptclaude-sonnet-5. - 도달 검증 = transcript
~/.claude/projects/<slug>/<session-id>.jsonl. slug 규칙 = 경로 소문자화 + 영숫자·-외 전부-(C:\dev\_relaytest→c--dev--relaytest). - 브릿지 = cody-bridge 확장 v1.6(
POST /newsession {prompt, submit})./send와 달리 focused 검사를 하지 않는다 — 릴레이는 포트로 창을 명시 지정하기 때문.submit(기본 true)이면 확장이 Enter 까지 넣는다.
검증 (2026-07-29, 격리 인스턴스 CDP 9340)
| 난이도 | 내용 | 결과 |
|---|---|---|
| 하 | 파일 읽고 첫 줄 보고 | PASS RELAY_LOW_OK:... |
| 중 | 스크립트 생성 + 실행 검증 + 옵션 주입 | PASS, transcript model=claude-sonnet-5 |
| 상 | 인계문으로 이어작업(규약 승계·하위호환·자체검사·수정금지 준수) | PASS, README mtime 불변 |
- 자체검사 test_relay.py 4항목 ALL PASS(slug·창선택·옵션병합·transcript 판정). |
||
| - 무간섭 확인: 페페 창 브릿지는 v1.4 그대로, 격리 창만 v1.5. |
함정 (재발 방지)
ELECTRON_RUN_AS_NODE=1상속 →Code.exe가 GUI 없이 node로 뜬다. 실행 전 반드시 제거.- CDP websocket에 Origin 헤더가 붙으면 403 →
suppress_origin=True. - Claude webview는 실행 컨텍스트가 2개(껍데기 +
fake.html자식). 내용이 있는 쪽을 골라야 DOM이 보인다. - x64
sizeof(INPUT)는 40이어야 한다. union에ki만 넣으면 32가 되고 SendInput이 0 반환 후 조용히 실패. - 탭이 여러 개일 때 "마지막 webview 타깃 = 새 탭"이 아니다 → 열기 전 타깃 집합을 빼고 골라야 오발송이 없다.