session-relay — 세션 자동 인계 파이프라인 (handoff)
C:\dev\tools\session-relay= 컨텍스트가 차기 전에 지금 세션이 직접 인계 지시문을 써서 새 Claude Code 세션(VS Code 확장)을 열고, 지시문을 넣고, 제출까지 하는 도구. 매뉴얼 전문 =C:\dev\tools\session-relay\README.md.
NOW
- ✅26.10.17(토) 17:25 KST [코디] AI 폴백·트레이 기본 공급자 GLM → 알리바바 Qwen 교체([페페] 「glm 자동전환을 보관하고 qwen 자동 전환으로 대체」「클로드 코드 버금가는 코딩 성능 모델로」) —
fallback.pyPROVIDERS 에qwen(https://dashscope-intl.aliyuncs.com/apps/anthropic·DASHSCOPE_API_KEY·qwen3.8-max/ smallqwen3.8-flash· 꼬리표[QWEN/…]) +DEFAULT_PROVIDER=qwen· zai·or = 보관(--provider로만) ·tray_wants_fallback()(effective qwen|glm, 옛 이름tray_wants_glm별칭). 트레이 = 클로드/Qwen/자동 · 아이콘 Q · 상태값qwen(옛glm은 load 때 이행·저장,--set glm별칭) · 뮤텍스 이름 유지. 리모컨·notify.provider_tag()(dashscope→QWEN) 같이. 검증:test_fallback.py12항목 OK ·tray.py --check12항목 OK ·remote_tray.py --checkOK(미니PC·사무실PC) · qwen3.8-flash 직접 호출 200(content = thinking+text「FLASH-OK」) · 진짜claude -p(cwd %TEMP%) 「QWEN-OK」 rc0 · modelUsage = qwen3.8-max·qwen3.8-flash(경고unrecognized_model은 무해) · 진짜 settings 해시 불변. 트레이 재기동: 미니PC PID 14716 → 3856(Session1 · auto · effective claude 유지 · W218 일회성 작업 생성→실행→삭제) · 사무실PC 리모컨 파일 교체 후 PID 23388 → 34248(Session1 · W220 동일). tools 커밋a45212a(README 남의 미커밋 hunk 2개는 제외하고 내 절만 스테이징). devplanC:\dev\devplan\ai-fallback.html갱신(GLM = 보관 표기). ⏳노트북 리모컨 = 오프라인 그대로(켜지면 remote_tray.py 복사·재기동). - ✅26.10.17(토) [코디] 리모컨 트레이
C:\dev\tools\ai-tray\remote_tray.py([페페] 나머지 기기 = 리모컨) — 키·시크릿 없이ssh poin-mini로 미니PC state.json 읽기·tray.py --set· 60초 갱신 · 연결 실패 = 회색 「?」. 사무실PC(poinimos01) 설치·상주 완료(Run AiTrayRemote · W217 · PID 23388 Session1 · Session1 실측 get 0.4s). ⚠Session 0(ssh 안)에서 python→ssh 는 시작 직후 멈춘다(-n·DEVNULL·NO_WINDOW 다 무효) — 검증은 schtasks /IT 로 Session1 에서. ⏳노트북(poin-lap) = 오프라인(ssh timeout) → 켜지면 같은 절차. tools 커밋53160ef. Z.ai 크레딧 환산 실측: claude -p 1회(입력 52,866·캐시읽기 192) + 소형 8회 = 18크레딧 → ≈3,000 입력토큰 = 1크레딧(⚠정정: 첫 호출이라 캐시가 없었던 것 — 같은 세션 2·3턴은 cache_read 51.7k·input 127~153 으로 Z.ai 캐시 작동 실측 · 캐시 토큰 가중치 실측 = 3턴 시험 전후 18→45크레딧(+27) · 1턴 새입력 ~5.2만 ≈17크레딧 → 캐시읽기 10.3만 ≈ 10크레딧 → 캐시 ≈ 새 입력의 약 0.25배(제목생성 호출 포함이라 상한값) → 10만 컨텍스트 세션 1턴 ≈ 8크레딧 → 5시간 ≈ 250턴 · 주간 ≈ 1,200턴). 우리 실사용 대비(usage.db 최근 7일: 호출 27,799 · cache_read 58.9억 · cache_write 1.54억 · output 2,347만 = opus 환산 $2,415(캐시읽기 제외 $1,238)) → GLM 환산 ≈ 55만 크레딧/주 → Lite 1주 = 우리 1주의 약 1.8%(≈3시간) · Pro 11% · Max 25%. Lite 한 달 ≈ opus API $190어치 ≈ 우리 API 크레딧 월 $200 과 비슷한 양. ∴ GLM = «잠깐 잇는 비상용», 소진 기간 전체 대체는 불가. [페페] 「보조로 너무 적다, 대안」 → [코디] 판단: 우리 비용 원천 = 캐시읽기(58.9억/주) → «호출 수 기준» 플랜이 유리(문맥 크기 무관). 후보 = MiniMax Max $50(5h 4,500호출 참고치 · 우리 평균 ≈2,300/5h) · Ultra $120(15,000) · Kimi Code(K3, 5h 300~1,200요청, ¥199~699) · 종량 DeepSeek Flash 공식가로 우리 1주 100% ≈ $55(비혼잡)~$110(혼잡 = KST 평일 10~13·15~19시). 실측 비교 [페페] 결정 대기. → 5시간 2,000 ≈ 600만 토큰 · 주간 10,000 ≈ 3,000만 토큰. 실작업 측정은 [페페] 진행 예정. - ✅26.10.17(토) [코디] Z.ai GLM 실연결 성공 — 원인 = Standard 탭 키(1113) → Personal Coding Plan 탭 키로 교체 후 HTTP·진짜
claude -p(cwd %TEMP%) 모두 OK(「GLM-OK」 · model=glm-5.3 · 단순 1회 input 52,866토큰 = 훅·시스템프롬프트 무게). 미니PC 트레이 = 자동 모드(주간 71.8% → 클로드 유지). ⏳사무실PC·노트북 = 확인해 보니 poinimos01 엔C:\dev\tools\session-relay·secrets 없음, 페페가 Remote-SSH 로 미니PC 세션을 쓰면 전환은 이미 전 기기 공통 → 원격 표시용 트레이 여부 [페페] 결정 대기. - 🔻26.10.17(토) [코디] AI 전환 트레이 신설
C:\dev\tools\ai-tray\tray.py([페페] 모드 3개·아이콘 표시·자동=클로드 소진→GLM·전 기기 설치) — 미니PC 상주(HKCU Run AiTray · winledger W213 · 기본 수동 클로드) ·--check11항목 · fallback 원자쓰기·잠금·go() 원복규칙(트레이 GLM 유지) · pythonw import 크래시 버그 수정(Stop 훅 go 가 한 번도 안 돌았을 것) · tools 커밋97721f4. cody-agent API 런은--setting-sources ""+env 허용목록이라 전역 폴백 env 안 샘. 🔴Z.ai 실측 = 키 인증 OK 인데 전 모델·엔드포인트·진짜 claude -p 모두 429/1113(잔액·패키지 없음) — 플랜 Valid(Lite·갱신 26.11.17)·등급 무관 → 키↔플랜 연결 문제, 페페 콘솔 확인 대기. ⏳사무실PC·노트북 설치 = GLM 확인 뒤(절차 = tray.py docstring). - 🔻26.10.17(토) [페페] 폴백 공급자 = Z.ai 직접(GLM Coding Plan Lite 월 $18) 기본 · OpenRouter 옵션 — [코디]
fallback.py공급자 표(PROVIDERSzai·or) +provider_env()순수함수 +--provider· notifyprovider_tag()ZAI 인식 · tools 커밋3cff9b7·test_fallback.py8항목 OK · settings.json 해시 불변. 결정 = 가입이력 없음(신규 → Anthropic 엔드포인트 OK) · GLM 세션 데이터 차단 안 함 · 자동화(Q3) = 크레딧 하한 미달 시 GLM 종량 API(정액은 지원도구 한정 약관). ⏳페페 = z.ai 국제판 가입·ZAI_API_KEY등록 → 코디 실측. ⏳코디 다음 = 예약작업·cody_ask경로에 GLM 종량 폴백(provider_env 재사용 · Z.ai 종량 엔드포인트 확인 필요). devplanai-fallback.html🆕 절. - ⏸26.10.8(목) [코디]
fallback.py«구독 한도 시 크레딧 Sonnet 1순위» 보류 — 폴백은 새 대화형 VS Code 세션을 여는데 크레딧은 IDE·대화형에 안 먹는다(cody-agent F2, 400) + 전역ANTHROPIC_API_KEY노출 금지. 코드 변경 0. 선택지·추천 =C:\dev\seedchain\projects\cody-agent\handoff.md미결 3. - ✅26.10.1(목) [코디] 사용량 통계 주별 실측 보정(총괄 지시 · 통계 정확도) — 단일 중앙값 한도($1,339)를 모든 주에 쓰던 것을 구간별 한도로 변경: 실측 있으면 그 실측 역산(주별 실측 보정 · 15% 미만 = 신뢰도 낮음 · 3% 미만 역산 안 함) / 없으면 14일 안 인접 실측(인접 주 보정) / 없으면 중앙값. 역산 한도 실측 9.10 $1,274 · 9.14 $1,490 · 9.17 $1,089 · 9.24 $1,288 · 10.1 $1,390. 결과 9.7주 84→75%(실측 73%) · 9.14주 88→108% = 「추정 불가·실측 확인」(가중지표 한계, 9.20 22:37 이후도 사용 계속) · 9.21주 40→42%.
test_usage_stats.py72/72 · tools 커밋3fb4331. - ✅26.10.1(목) [코디] 사용량 통계에 «프로모션·보상 사용량 리셋» 반영(페페 승인 추천안) — 기록
C:\dev\tools\claude-usage\resets.json(과거 11건 · applies true 9 / false 2 · 스키마 =usage_stats.pydocstring). 주간 추정·도달 예측·한도 역산 = max(정기 주 시작, 그 주 마지막 반영 리셋) 이후만 · 같은 정기 주 안 실측 3%p+ 하락 = 자동감지(resets.json auto + 텔레그램). 화면 = 리셋 주 「리셋 전/후」 두 줄 · 리셋 후 기준 표기 · 일별 점선 · 하단 리셋 기록 표. 자체검사test_usage_stats.py58/58 ·test_calibrate.py30 OK. - ✅26.10.1(목) [코디]
\SessionRelay-Calibrate매주 목 → 매일 10:00calibrate.py --daily— 측정 줄은 매일(15% 미만도), 한도 보정은 정기 주 1회(주 시작+2.5일 이후 첫 실행 ·state.json calibrate_week_done). 리셋 이후 토큰만 세고 day 정밀도 리셋이면 보정 보류. 9/3 7% 이상치 = 9/2 리셋 때문이었다(역산 $4,119 → 리셋 후 $1,630). - ✅26.10.1(목) [코디] 클로드 사용량 통계 신설(페페 승인 26.9.29 「전체 추천대로」) —
C:\dev\tools\claude-usage\usage_stats.py(scan·build·run · SQLiteusage.db· 자체검사test_usage_stats.py31/31) + 예약작업\Cody\claude-usage(1시간 · wscript→pythonw · 창 0) → devplanclaude-usage.html.cleanupPeriodDays 3650설정(transcript 보존). 주간 추정 = 실측 /usage 로 역산한 $ 한도 대비(10/1 추정 27% vs 실측 26%). ⚠guard 의 중복 줄 부풀림 =rules.md🆕. 세션문서session-2026-10-01-claude-usage.md. - 🔻26.9.23(수) [페페] AI 폴백 신설 — 클로드 한도가 차면 OpenRouter 로 갈아타 작업을 잇는다.
도구 =
C:\dev\tools\session-relay\fallback.py(check/on/off/status/go/--hook) · 자체검사test_fallback.py7항목 ALL PASS. Stop 훅 1줄(~/.claude/settings.json)로 자동 발동. 알림 태그는tools/notify.py provider_tag(). 착수 전 그릴링 10문항 확정 = 모델만 교체 · 자동전환+사후통보 · 구독+OpenRouter 소액 · VS Code 새 탭 · 주간 95%+한도에러 ·z-ai/glm-5.3-flash· 기존 게이트 유지하되 이력에 공급자·모델 표기 · 자동복귀 · 미니PC 먼저. ⏳[페페] 1건 = OpenRouter 가입 + $10 충전 + 키를C:\dev\.secrets\.env의OPENROUTER_API_KEY에 — 그 전까지 폴백은 «켜지기를 거부»한다(키 없이 켜면 모든 새 세션이 인증실패로 죽으므로 의도적 차단). 함정·실측 전문 =rules.md🆕 맨 위 · devplanai-fallback.html. - ✅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 타깃 = 새 탭"이 아니다 → 열기 전 타깃 집합을 빼고 골라야 오발송이 없다.