Zettelkasten

Claude 구독을 서드파티 도구에 붙이려면 토큰 추출이 아니라 claude CLI subprocess 프록시를 거친다

·수정 3

요약

  • Anthropic은 구독 OAuth 토큰의 서드파티 사용을 ToS로 금지하고 서버단 차단했다. 우회는 토큰 추출이 아니라 claude CLI/SDK를 subprocess로 감싸 OpenAI/Anthropic 호환 엔드포인트로 노출하는 로컬 프록시(예: Meridian)다.
  • 막히는 진짜 지점은 모델·컨텍스트 크기도 스트리밍도 아니라 macOS keychain 접근 컨텍스트 하나였다. 격리 환경의 단일 실패를 다른 원인으로 오귀인하기 쉽다.

본문

구도: 서드파티 에이전트(OpenAI 호환 클라이언트) → 로컬 프록시 :PORT/v1 → 번들 claude CLI subprocess → 구독 인증. 프록시는 토큰을 추출/전달하지 않고 CLI가 자체 인증을 처리한다. 스크립트·파이프·cron과 동일한 "프로그래밍 사용" 패턴이라 토큰 추출(ToS 위반)과 구분된다. 단 구독 자동화 연결 자체는 회색지대로 계정 제한 리스크가 있다.

실제 아키텍처 — Hermes + Meridian + Claude Code Hermes(Nous의 CLI 에이전트)를 Claude 구독으로 돌린 구성:

Hermes gateway (호스트)
  └─ model.provider=custom, base_url=http://127.0.0.1:3456/v1
        │  (OpenAI 호환 chat_completions)
        ▼
  Meridian 프록시 :3456   ← @rynfar/meridian, .zshrc 로그인 기동
        │  query() (Claude Agent SDK)
        ▼
  번들 claude CLI subprocess
        │  macOS keychain의 Claude Code-credentials 읽음
        ▼
  Anthropic API (구독 풀로 청구)

Hermes 쪽 설정(~/.hermes/config.yaml):

model:
  default: claude-opus-4-7   # opus[1m]까지 구독 커버
  provider: custom           # OpenAI 호환. anthropic provider는 아래 "provider 모드" 참조
  base_url: http://127.0.0.1:3456/v1
  api_key: x                 # placeholder, Meridian이 무시(localhost 무인증)

Meridian은 모델명을 자동 매핑한다(opus → opus[1m], 1M 컨텍스트). Hermes 자체는 docker terminal backend를 쓰지만 그건 코드 실행 샌드박스일 뿐, gateway는 호스트에서 돌아 localhost:3456에 닿는다. 인증 주체는 어디까지나 호스트의 claude CLI다.

오귀인 주의 — 스트리밍은 범인이 아니었다 디버깅 초기에 stream=true 호출에서 httpx RemoteProtocolError로 빈 응답이 떠서 "프록시 SSE와 httpx 비호환"으로 의심하고 non-streaming 강제 패치를 넣었다. 하지만 클린 재현(keychain 정상 + 순정 stream=true + tools 다수)에서 3/3 성공 → 스트리밍은 버그가 아니었다. 초기 실패는 keychain 깨진 환경 + 고부하 transient의 합작이었고, 패치는 불필요해 원복했다. 교훈: 여러 변수를 동시에 바꾼 상태에서 본 실패를 한 변수 탓으로 단정하지 말 것. 한 번에 한 변수만 격리해 재현해야 진짜 원인이 남는다.

진짜 원인 — keychain 접근 컨텍스트 400 You're out of extra usage가 떠도 모델·1M 컨텍스트 문제가 아니다. Claude Code 구독 토큰은 macOS keychain(Claude Code-credentials)에만 저장되고 파일(~/.claude/.credentials.json)이 없을 수 있다. 이때:

  • 로그인 GUI 셸 세션(터미널, .zshrc 자동기동)에서 프록시를 띄우면 keychain이 unlock 컨텍스트로 접근돼 정상 통과. Opus 1M까지 다 된다 (Claude Code에서 opus 잘 되는 것과 동일).
  • launchd 백그라운드 데몬 / env -i 최소환경 / docker 컨테이너는 keychain 접근 컨텍스트가 달라 토큰이 refresh돼도 요청이 extra-usage 풀로 라우팅돼 400. docker는 리눅스라 macOS keychain을 아예 못 본다.
  • 즉 "자동실행 수단"의 문제가 아니라 "실행 보안 컨텍스트"의 문제. 부팅 자동실행이 필요하면 launchd가 아니라 .zshrc 로그인 기동이 답이다.

provider 모드 선택 OpenAI 호환(custom, /v1/chat/completions) 경로를 써야 한다. native Anthropic(/v1/messages) 경로는 클라이언트가 Claude Code beta 헤더를 붙여("Custom betas are only available for API key users") 요청이 extra-usage 풀로 빠진다. 프록시의 beta 필터 정책(allow-safe)이 billable beta를 걸러주지만, 애초에 betas가 덜 붙는 OpenAI 호환 경로가 안전하다.

디버깅 교훈: 격리 환경(launchd)에서 한 번 400을 보고 "모델/플랜이 안 된다"고 일반화하면 틀린다. 성공(전체 셸 env)/실패(최소 env) 환경을 나란히 두고 차이를 좁혀야 진짜 변수(keychain 컨텍스트)가 드러난다.

관련 노트

참고