Skip to content

Latest commit

 

History

History
317 lines (223 loc) · 44.6 KB

README.ko.md

File metadata and controls

317 lines (223 loc) · 44.6 KB

shunt

오프라인 자격 증명 가져오기: shunt import opencodex --dry-run으로 호환 API 키와 Cursor/Command Code 액세스 토큰을 미리 확인합니다. 기존 설정이나 갱신 토큰을 변경·복사하지 않고 새 비공개 스냅샷을 생성합니다. 가져오기 안내(영문)를 참고하세요.

CI CodSpeed Quality Gate Status codecov License Greptile: The War on Bugs

English · 한국어 · 日本語 · 简体中文

Claude Code를 어떤 모델로든 우회(shunt)하세요.

shunt는 스펙을 준수하는 Claude Code LLM 게이트웨이입니다. 매핑한 모델에 한해 추론을 추론 계층에서 다른 LLM 프로바이더로 우회시키는 투명 프록시입니다. 요청의 model id를 기준으로 라우팅하며, 그 외 모든 것은 변경 없이 Anthropic으로 그대로 전달됩니다(이것이 "shunt"이며, 폴백은 server.default_provider로 구성할 수 있습니다).

이름 자체가 동작 방식을 나타냅니다. 전기/철도의 shunt는 흐름의 일부를 선택해 병렬 경로로 우회시킵니다. 여기서는 매핑된 모델의 추론이 다른 프로바이더로 우회되는 동안 Claude Code의 도구와 스킬은 그대로 유지됩니다.

OpenAI, ChatGPT/Codex, xAI, Grok, Cursor, Kimi Code, Zhipu, MiniMax 중국, OpenCode Zen, Cheaper Inference, Gemini, Antigravity, Anthropic 패스스루가 기본 내장되어 있고, 이 가운데 여럿은 이미 결제 중인 구독을 그대로 재사용합니다. Anthropic Messages 호환 백엔드라면 무엇이든 구성 테이블 하나로 붙일 수 있으며, 코드 변경은 필요 없습니다. 프로바이더를 참고하세요.

Note

shunt는 활발히 개발 중인 1.0 미만(pre-1.0) 소프트웨어입니다. SemVer 관례에 따라 0.x 릴리스에는 설정 키, CLI, 동작에 대한 호환성이 깨지는 변경(breaking change)이 포함될 수 있으니, 업그레이드 전에 릴리스 노트를 확인하세요.

설치

# Homebrew (macOS / Linux)
brew install pleaseai/tap/shunt

# 설치 스크립트 (macOS / Linux) — GitHub 릴리스의 사전 빌드 바이너리
curl -fsSL https://shunt.sh/install.sh | sh

# Cargo — 소스 저장소에서 직접 설치
cargo install --git https://github.com/pleaseai/shunt

새 버전은 Homebrew와 각 GitHub 릴리스에 첨부된 사전 빌드 바이너리(macOS/Linux, arm64/x64)로 배포됩니다. crates.io 패키지는 마지막으로 게시된 버전에서 중단됩니다. 사전 빌드 바이너리 및 소스 빌드 안내는 설치를 참고하세요.

위의 cargo install은 관리자 대시보드 없이 빌드됩니다. 대시보드 번들에는 Node.js 22.12+가 필요하며 --features ui로만 임베드되는데, Homebrew와 릴리스 바이너리는 이미 이 플래그를 켜고 빌드합니다. 관리자 JSON API를 포함한 나머지는 어느 쪽이든 동일합니다. 소스 빌드 절차는 설치에 있습니다.

서비스로 실행하기 (macOS/Homebrew)

brew services start shunt

로그는 $(brew --prefix)/var/log/shunt.log에 남습니다. brew services stop은 SIGTERM을 보내고 shunt는 처리 중인 요청을 마친 뒤 종료합니다 — 최대 [server] shutdown_timeout_seconds(기본 30초, 이 값 변경은 재시작 필요)까지 기다리고, 그 시점이 지나면 더 기다리지 않고 종료하므로 조용한 SSE 스트림이 프로세스를 무한정 붙잡을 수 없습니다. Unix에서는 종료가 시작될 때 Antigravity 에이전트 턴이 함께 종료되므로, 격리된 프로세스 그룹이 드레인을 붙잡아 둘 수 없습니다. 이후 설정 파일을 수정해도 재시작이 필요 없습니다 — 자동으로 핫 리로드됩니다. 자세한 내용은 서비스로 실행하기를 참고하세요.

빠른 시작

# shunt.toml — gpt-* id를 ChatGPT 구독으로 라우팅
# [[routes]]는 정확한 id를 위한 레거시 방식입니다. [models.upstream_model]을 권장합니다.
[[routes]]
model = "gpt-5.6-sol"
provider = "codex"        # `codex login`을 재사용; OPENAI_API_KEY를 쓰려면 `openai` 사용
codex login                                        # 프로바이더 자격 증명
shunt run                                           # -> 127.0.0.1:3001 에서 리슨

export ANTHROPIC_BASE_URL=http://127.0.0.1:3001
export ANTHROPIC_CUSTOM_MODEL_OPTION="gpt-5.6-sol"
claude                                              # /model -> gpt-5.6-sol 선택

매핑되지 않은 모델(모든 claude-* id)은 이전과 완전히 동일하게 동작합니다. shunt가 사용자 본인의 자격 증명으로 Anthropic에 전달합니다. 전체 안내: 빠른 시작.

시작 구성

shunt init은 기존 디렉터리에 주석이 포함된 shunt.toml을 생성합니다. 기본 passthrough starter를 그대로 사용하거나, 매핑되지 않은 모델의 fallback을 바꾸지 않고 순서가 있는 upstream preset을 scaffold할 수 있습니다.

shunt init
shunt init --upstream codex --upstream kimi

에이전트 중심 설정 blueprint

shunt add는 코딩 에이전트용 내장 Markdown 구현 가이드를 가져옵니다. shunt add upstream으로 사용 가능한 upstream blueprint를 확인하거나 에이전트에 바로 파이프하세요.

shunt add upstream kimi --print | claude
shunt add upstream https://provider.example/docs --print | claude

이 명령은 오프라인이고 읽기 전용입니다. 안내만 출력하며 파일을 수정하거나 설치하거나 네트워크에 접근하지 않습니다. 완전히 새로운 provider protocol 지원에 기여하려면 shunt add provider <absolute-url>을 사용하세요.

프로바이더

프로바이더는 순서가 있는 [[upstreams]] 항목 또는 레거시 [providers.<name>] TOML 테이블입니다(YAML에서는 각각 해당 sequence 또는 mapping의 항목). 두 가지 어댑터 종류가 대부분의 업스트림을 커버합니다. kind = "anthropic"(업스트림이 Anthropic Messages를 사용하며, 필요하면 다른 키로 패스스루)와 kind = "responses"(업스트림이 OpenAI Responses API를 사용하며, shunt가 Anthropic Messages ⇄ Responses를 스트리밍 포함하여 변환하고, Responses API에는 stop 파라미터가 없으므로 stop_sequences를 게이트웨이 측에서 에뮬레이션)입니다. 세 번째 네이티브 종류인 kind = "cursor"는 Cursor의 ConnectRPC/protobuf AgentService를 브리지하여 Cursor 구독을 동일한 Anthropic-Messages 인터페이스로 사용할 수 있게 합니다.

순서가 있는 업스트림은 프로바이더 간 페일오버를 지원합니다. 선언 순서가 시도 순서이며, 모델의 upstream_model 맵은 참여할 항목을 선택하고 공개 id를 각 백엔드 id에 매핑합니다.

[server]
default_provider = "anthropic-primary"

[[upstreams]]
name = "anthropic-primary"
provider = "anthropic" # preset: kind, base_url, and default auth
auth = { mode = "claude_oauth", account = "primary" }

[[upstreams]]
name = "codex-fallback"
provider = "codex" # defaults to chatgpt_oauth

[[models]]
id = "claude-opus-4-8"
[models.upstream_model]
anthropic-primary = "claude-opus-4-8"
codex-fallback = "gpt-5.6-sol"

이 체인은 anthropic-primary를 먼저 시도한 다음 codex-fallback을 시도합니다. auth는 mode 문자열 또는 맵을 받으며, claude_oauth와 chatgpt_oauth 맵은 account = "name" 또는 accounts = [...]로 자격 증명 범위를 좁힐 수 있습니다. 레거시 [providers.<name>]는 계속 지원되며 이름순의 암시적 업스트림이 됩니다. 구성 파일에서 두 형식을 함께 선언하지 마세요. [[upstreams]]와 [providers.*]를 혼합하면 구성 오류입니다. preset, 실패 클래스, 마이그레이션 세부 사항은 구성 레퍼런스를 참고하세요.

기본 내장

다음 프로바이더는 기본으로 시드되어 있어, 직접 작성한 [providers.*] 테이블 없이 provider = "<이름>"만으로 라우팅됩니다 — 단 [[upstreams]]를 선언하지 않은 경우에만 해당합니다. 순서가 있는 [[upstreams]] 목록은 프로바이더 맵을 통째로 대체하므로, 그 형식에서는 프리셋을 포함해 라우팅 대상 프로바이더를 모두 거기에 선언해야 합니다.

이름 종류 인증 백엔드
anthropic anthropic passthrough 또는 Claude OAuth 계정 풀 api.anthropic.com — 기본적으로 호출자 본인의 자격 증명을 전달하며, auth = "claude_oauth"를 쓰면 풀링된 구독 자격 증명을 사용합니다
openai responses OPENAI_API_KEY api.openai.com/v1
codex responses ChatGPT OAuth chatgpt.com/backend-api — ~/.codex/auth.json(codex login)을 재사용
xai responses XAI_API_KEY api.x.ai/v1 — 개발자 API, 토큰당 과금
grok responses xAI OAuth cli-chat-proxy.grok.com/v1 — Grok CLI 프록시, ~/.shunt/xai-auth.json을 재사용(SuperGrok / X Premium+ 구독으로 shunt login xai), 또는 ~/.shunt/accounts/xai 아래 이름 있는 계정을 페일오버와 함께 풀로 묶음(shunt login xai --name <이름>). 레거시 파일은 이 풀이 비어 있을 때만 사용되므로 첫 이름 있는 계정을 추가하면 자격 증명이 전환됩니다
cursor cursor Cursor OAuth api2.cursor.sh — ~/.shunt/cursor-auth.json(shunt login cursor)을 재사용
gemini gemini Google OAuth cloudcode-pa.googleapis.com — Google Code Assist 백엔드, ~/.gemini/oauth_creds.json을 재사용
antigravity antigravity Antigravity OAuth daily-cloudcode-pa.googleapis.com — HTTP로 통신하는 Google Antigravity 백엔드, ~/.shunt/antigravity-auth.json(shunt login antigravity)을 사용(또는 shunt login antigravity --name으로 ~/.shunt/accounts/antigravity 아래 이름 지정 계정을 만들어 accounts = [...]로 선택)
antigravity-cli antigravity_cli 없음(로컬 CLI) Deprecated. 로컬 agy 바이너리 — 서브프로세스로 동일한 백엔드를 사용하며, 위의 antigravity로 대체되었습니다

순서가 있는 [[upstreams]] 항목은 여기에 더해 kimi, kimi-code, zhipu, minimax-cn, opencode, cheaperinference, chatgpt-plan 프리셋도 받으며, 각 백엔드의 kind, base_url, 기본 인증을 채워 넣습니다.

ChatGPT 플랜(Sign in with ChatGPT). chatgpt-plan 프리셋은 api.openai.com/v1/responses에서 OpenAI의 "Sign in with ChatGPT" 토큰 공유 프리뷰를 통해 ChatGPT 플랜을 사용하며, 위의 codex 프로바이더와는 별개입니다. shunt login chatgpt-plan --name <account>로 로그인하고(127.0.0.1:1455로의 브라우저 콜백, 또는 원격 호스트에서는 콜백 URL 붙여넣기), provider = "chatgpt-plan"인 순서 있는 [[upstreams]] 항목을 추가하고(프리셋이 kind, base_url, auth = "chatgpt_plan_oauth"를 채웁니다) 아래처럼 모델을 연결합니다. 이름 있는 여러 계정은 풀을 이루어 한 계정이 플랜 사용량 한도에 닿으면 순환하며, shunt logout chatgpt-plan --name <account>는 계정 하나를 폐기하고 지웁니다. 프리뷰는 일부 요청 파라미터를 거부하고, 출력이 시작된 뒤 사용량 한도에 닿으면 순환하지 않고 스트림이 끝납니다. ChatGPT 플랜 가이드를 참고하세요.

[[upstreams]]
name = "anthropic"
provider = "anthropic" # preset: Claude models pass through to Anthropic

[[upstreams]]
name = "chatgpt-plan"
provider = "chatgpt-plan" # preset: kind, base_url, and auth = "chatgpt_plan_oauth"

[[models]]
id = "gpt-6.1-sol"
[models.upstream_model]
chatgpt-plan = "gpt-6.1-sol"

프로바이더별 설정과 모델 id, 주의 사항은 프로바이더에 정리되어 있습니다. xAI의 OAuth 등급 제한(xAI / Grok), Cursor의 에이전트 모드 프리픽스(Cursor), Antigravity의 두 가지 전송 방식과 kind = "antigravity" 마이그레이션(Antigravity)도 그곳에 있습니다.

Warning

antigravity-cli는 더 이상 권장되지 않으며 임의 코드 실행입니다. 로컬 agy 바이너리를 --dangerously-skip-permissions와 함께 에이전트 모드로, shunt를 실행한 사용자 권한으로 구동합니다. sandbox 설정을 켠 채로 두고 바인드는 루프백에 두세요. 이런 것이 전혀 필요 없는 위의 antigravity 프로바이더를 권장합니다. 더 이상 사용되지 않는 전송 방식을 참고하세요.

Anthropic 호환 백엔드

테이블 하나면 되고, 코드 변경은 필요 없습니다.

프로바이더 base_url 예시 모델 ID
Kimi (Moonshot) https://api.moonshot.ai/anthropic kimi-k3[1m], kimi-k2.7-code
Kimi Code (구독, OAuth) https://api.kimi.com/coding 구독에서 제공하는 ID 사용
DeepSeek https://api.deepseek.com/anthropic deepseek-v4-pro, deepseek-v4-flash
Z.ai (GLM) https://api.z.ai/api/anthropic glm-5.2, glm-4.7
Zhipu (GLM 중국) https://open.bigmodel.cn/api/anthropic glm-5.3, glm-5.3-flash
MiniMax https://api.minimax.io/anthropic MiniMax 문서 참고
MiniMax 중국 https://api.minimax.cn/anthropic MiniMax-M3
OpenCode Zen https://opencode.ai/zen claude-fable-5-1, gpt-6-astra — 큐레이션된 크로스 벤더 카탈로그; x-api-key 읽음
Cheaper Inference https://api.cheaperinference.com gpt-5.4, deepseek-v4-flash, glm-5.3 — Messages 엔드포인트를 제공하는 OpenAI 호환 게이트웨이
OpenRouter https://openrouter.ai/api anthropic/claude-opus-4.8
Vercel AI Gateway https://ai-gateway.vercel.sh anthropic/claude-opus-4.8
[providers.kimi]
kind = "anthropic"
base_url = "https://api.moonshot.ai/anthropic"
auth = "api_key"
api_key_env = "MOONSHOT_API_KEY"

[[routes]]
model = "kimi-k3[1m]"
provider = "kimi"

위 표의 행은 대부분 auth = "api_key"를 사용합니다. Kimi Code만 예외입니다. 종량 과금인 Moonshot API와는 별개인 구독 기반 서비스로, 호스트가 다르고 API 키 대신 OAuth를 쓰며, 내장 kimi-code 프리셋이 있습니다. 이 프리셋은 순서가 있는 [[upstreams]] 항목 안에서만 해석되므로(시드된 프로바이더 맵에는 없습니다) 거기에 선언한 뒤 로그인하세요. Kimi Code를 참고하세요.

구독 재사용

OpenAI의 Thibault Sottiaux는 다른 코딩 하네스를 통해 Codex를 실행하는 것을 공개적으로 환영했습니다.

Share the recipe. People want to know how to use GPT-5.6 Sol in CC. We don't discriminate on the harness. (출처)

그는 후속 글에서 Claude Code("당신의 주황색 게")를 GPT-5.6 Sol에 직접 연결하는 과정을 설명했습니다. shunt가 수행하는 추론 계층 교체와 정확히 같으며, 별도의 앱이 필요 없습니다.

다만, 비공식 클라이언트에서 ChatGPT/Codex나 SuperGrok 구독(또는 Kimi, Cursor 등 다른 백엔드)을 재사용하는 것은 본인의 판단입니다. 공개적인 환영이 향후 정책이나 계정 제재가 없음을 보장하지는 않습니다. 사용에 따른 책임은 본인에게 있습니다.

Antigravity는 약관이 이를 명시한 예외입니다. Google의 Antigravity 약관은 "서드파티 소프트웨어, 도구, 서비스로 서비스에 접근하는 것(예: OpenClaw를 Antigravity OAuth와 함께 사용)은 본 계약 위반"이며, 그러한 위반은 "Antigravity 및/또는 Gemini CLI 계정의 정지 또는 해지 사유가 될 수 있다"고 명시합니다. shunt의 antigravity 프로바이더가 바로 그것 — Antigravity OAuth를 사용하는 서드파티 소프트웨어 — 이므로, 이 프로바이더로 라우팅하는 것은 그 조항에 그대로 해당합니다. shunt login antigravity를 실행하기 전에 이를 감안해 결정하세요.

선택 기능

행에 별도 표기가 없으면 기본 비활성입니다. 해당 구성 테이블이 없으면 라우트도 등록되지 않고 백그라운드 작업도 시작되지 않습니다.

기능 활성화 키 문서
Anthropic 멀티 계정 풀링 — 세션을 계정에 할당하고 그 계정이 요청을 처리할 수 없거나 60초 동안 쿼터에 근접해 있을 때 옮기는 세션 바인딩([server.pool] assignment로 배치 방식 선택, 기본값 spread, 대안 soonest_weekly_reset), 쿼터 인식 로테이션, 예측 회피, 풀이 캡으로 모두 막히면 계정을 제외하고 다음 업스트림으로 페일오버하는 윈도우별 하드 캡(max_utilization*) 계정 2개 이상인 auth = "claude_oauth"; [server.pool]은 선택적 튜닝 가이드
Codex 멀티 계정 풀링 — 같은 세션-계정 바인딩, x-codex-* 윈도우 추적, 슬로우 스타트 램프, 재프로브, 풀이 캡으로 모두 막히면 계정을 제외하고 다음 업스트림으로 페일오버하는 윈도우별 하드 캡(max_utilization*) 계정 2개 이상인 auth = "chatgpt_oauth"; [server.pool]은 선택적 튜닝 가이드
학습형 프리필 라우팅 (type = "prefill_router") 컴파일 타임 옵트인 — cargo build --release --features prefill-router (기본 꺼짐 — 릴리스 바이너리와 Homebrew 포뮬러는 --features ui로 빌드되므로 들어 있지 않습니다). 여기에 type = "prefill_router"를 지정한 [models.router] 테이블, 디스크에 놓인 라우터 체크포인트, torch와 transformers가 설치된 Python 환경이 필요합니다 레퍼런스
인바운드 Codex 엔드포인트 — Codex CLI를 HTTP/SSE나 WebSocket으로 shunt에 연결해 같은 풀에 태우고, 모델별 라우팅도 선택할 수 있음 [server.codex_endpoint] 가이드
LLM 판정 라우팅 (type = "llm_classifier", type = "composite") — 판정 모델이 classify_trigger에 따라 턴마다 목적지를 고르며, 그 답은 클라이언트에게 제공되지 않습니다 type = "llm_classifier"(mode = "capability" 또는 "custom")나 type = "composite"를 지정한 [models.router] 테이블, 또는 classifier 형태의 [models.subagents] 오버레이 레퍼런스
완성된 턴을 판정하는 라우팅 (mode = "escalation", type = "advisor") — 답을 먼저 만들어 붙잡아 두고, 판정 모델이나 리뷰어가 완성된 턴을 판정한 뒤에만 보냅니다. 스트리밍 호출자는 판정이 끝난 뒤 그 턴을 재생받습니다 type = "llm_classifier"와 mode = "escalation", 또는 type = "advisor"를 지정한 [models.router] 테이블 레퍼런스
검증 전용 인바운드 JWT — 자체 ID 공급자가 발급한 JWT를 해당 JWKS로 검증해 수락하며, shunt는 아무것도 발급하지 않으므로 클라이언트는 퍼스트파티 모드를 유지 하나 이상의 [[server.auth.jwt]] 항목(각각 issuer, audience, 그리고 email_domains 또는 allowed_emails — GitHub Actions 같은 워크로드 ID는 대신 require / subject_prefix와 identity_claim)을 갖춘 [server.auth]. 인바운드 Codex 엔드포인트([server.codex_endpoint])에서는 jwt_header / jwt_cookie가 Codex CLI gateway_oauth의 토큰을 전달 레퍼런스
Claude 앱 게이트웨이 로그인 — OAuth device flow, managed settings, 사용자별 정책, Claude Desktop bootstrap(GET /user/bootstrap) public_url, 32바이트 이상 JWT 시크릿, 정적 사용자 또는 [server.gateway.oidc]를 갖춘 [server.gateway]. Desktop bootstrap에는 template 경로를 지정한 [server.gateway.desktop_bootstrap]도 필요 가이드
게이트웨이 텔레메트리 인제스트 — 관리 클라이언트의 OTLP를 그대로 릴레이 구성된 [server.gateway]와 forward_to가 비어 있지 않은 [server.gateway.telemetry] 레퍼런스
관리자 웹 화면 — 계정·사용량 대시보드, 브라우저 프로비저닝 [server.admin]에 관리자 자격 증명(tokens_env, tokens_file, 또는 write_keys 항목)을 직접 작성하거나(read_keys 항목만 있어도 대시보드는 읽기 전용으로 뜹니다 — 로그인과 모든 조회는 되지만 프로비저닝에는 write가 필요합니다), 또는 shunt dashboard setup으로 테이블 작성과 토큰 발급을 한 번에 처리합니다. 단 테이블 작성과 토큰 발급은 [server.admin]이 없을 때만 일어납니다 — 이미 있으면 기존 자격 증명을 그대로 두고 빠진 [server.oauth_usage]만 추가합니다. 대시보드 자체는 --features ui 빌드만 임베드하는 번들에서 제공됩니다 — 사전 빌드 릴리스 바이너리와 Homebrew 포뮬러에는 포함되어 있고, 그냥 cargo build/cargo install로 빌드하면 포함되지 않습니다 가이드
풀 계정 제어 — 계정을 일시정지하거나, 사용 가능한 계정을 가장 빨리 쿼터가 리셋되는 순으로 정렬 — 대시보드나 admin API에서 런타임에, shunt.toml 편집이나 재시작 없이 [server.admin] write 자격 증명; sort_by_reset은 대응하는 [server.pool] 설정 키도 있음 가이드
지출 한도 — Admin API로 저장하는 조직·사용자 단위 상한을 게이트웨이가 비용을 내는 /v1/messages 요청에 적용 — passthrough 또는 noop 라우트만으로 이루어진 체인은 제한도 계측도 하지 않음(429 billing_error, 주체별 anthropic-ratelimit-* 헤더, GET /v1/organizations/spend_limits/effective) — 인바운드 Codex 엔드포인트(HTTP와 WebSocket)에도 적용하며, 상한을 넘은 턴은 429 usage_limit_reached를 받고 같은 상한에 합산됨. [server.spend.pricing]에서 지출 측정기가 요청 비용을 계산할 때 쓰는 배수와 업스트림·모델별 요금 재정의를 설정(GPT/Codex 모델에는 기본 요금표가 없으므로 재정의 행을 추가하지 않으면 알 수 없는 모델 요율로 청구됨) [server.admin](관리자 자격 증명 필요: tokens_env, tokens_file, 또는 write_keys/read_keys 항목 — read 등급은 GET만 처리) + [server.spend] 레퍼런스
클라이언트 사용량 엔드포인트 — GET /usage가 정제·집계된 풀 여유를 반환 [server.usage], 그리고 [server.auth](클라이언트 토큰은 tokens_env(기본값 SHUNT_CLIENT_TOKENS) 또는 [[server.auth.jwt]]로 제공) 또는 [server.gateway](게이트웨이 로그인) 필요 레퍼런스
Claude Code CLI 네이티브 사용량 막대 — GET /api/oauth/usage 제공 [server.oauth_usage], 루프백이 아닌 bind에서는 [server.auth](클라이언트 토큰은 tokens_env(기본값 SHUNT_CLIENT_TOKENS) 또는 [[server.auth.jwt]]로 제공) 또는 [server.gateway] 추가 필요 레퍼런스(영문)
업스트림 상태 폴링 — Statuspage 지표를 메트릭으로, 그리고 --features ui 빌드에서는 대시보드에도 노출 [[server.status.sources]] 항목이 하나 이상 있는 [server.status] 레퍼런스
제한된 업스트림 재시도 — 기본 활성, 보수적이며 스트림 도중에는 재시도하지 않음 [providers.<name>.retry] 레퍼런스(영문)
공유 배포 제한 — 기본 활성(동시 1024, 본문 32 MiB, TTFB 120초, device-flow 레이트 리밋), CIDR·헤더·URL 제한은 선택 [server] max_concurrent_requests, [server.access_control], [server.limits], [server.timeouts], [server.rate_limits] 가이드
시크릿 참조 — 모든 문자열 값에 ${VAR} 또는 ${file:/abs/path}, 핫 리로드마다 다시 확인([sentry]·[otel] 제외 — 기동 시 1회 구성이라 재시작 필요) 구성의 모든 문자열(항상 활성) 레퍼런스
선택적 저장소 — 풀 쿼터, 게이트웨이 refresh token, 지출 한도·감사 기록을 JSON 스냅샷 대신 SQLite 또는 PostgreSQL에 보관하며, 기존 스냅샷은 한 번만 가져옵니다. 저장소당 shunt 프로세스는 하나입니다. 저장소에는 refresh token 해시가 들어 있으므로 데이터베이스 접근과 백업을 제한하세요 backend와 url이 있는 [store]; backend = "postgres"는 store-postgres 빌드가 필요합니다(사전 빌드된 릴리스 바이너리에는 포함, cargo build에는 미포함) 레퍼런스
OpenTelemetry 메트릭과 트레이스 endpoint가 비어 있지 않은 [otel] 가이드

문서

사용자 문서는 모두 **shunt.sh**에 있습니다.

기여자를 위한 설계 노트와 마일스톤 스펙은 docs/에 있습니다. docs/implementation-plan.md부터 보세요.

왜

Claude Code는 모든 턴을 Anthropic API로 보냅니다. shunt는 그 앞(ANTHROPIC_BASE_URL을 통해)에 위치하여, 매핑한 모델에 한해 추론을 다른 프로바이더(OpenAI, Codex/ChatGPT 등)로 우회시킵니다. 라우팅이 HTTP/추론 계층에서 일어나며 작업을 다른 CLI로 넘기는 것이 아니기 때문에, 세션은 계속 Claude Code의 하네스 안에서 실행됩니다. 동일한 도구 루프, 동일하게 프리로드된 스킬, 동일한 번들 스크립트 경로 해석이 유지됩니다. 오직 토큰 생성만 외주됩니다.

이는 대안적 접근(작업을 subagent_type으로 Codex CLI 같은 다른 런타임에 넘기는 방식)과 대조됩니다. 그 방식은 스택의 더 위쪽을 끊어내어 페르소나와 프리로드된 스킬을 잃습니다.

에이전트별이 아닌 모델별 — 그리고 전역 교체가 아님

선택성은 각 요청의 model id로 결정되며, Claude Code는 이미 이를 컨텍스트별로 선택할 수 있게 해줍니다. 메인 세션은 /model 선택기, 서브에이전트 정의는 model: 프론트매터, 모든 서브에이전트는 CLAUDE_CODE_SUBAGENT_MODEL, 선택기에 커스텀 항목을 추가하려면 ANTHROPIC_CUSTOM_MODEL_OPTION을 사용합니다. 따라서 "이 에이전트만 / 이 세션만 우회"는 Claude Code에서 결정되고, shunt는 받은 model id만 그대로 존중합니다. 취약한 에이전트별 시스템 프롬프트 지문 인식은 없습니다. 전역 모델 교체 프록시와 달리, 메인 세션은 Claude에 그대로 두고 지정한 모델만 우회할 수 있습니다.

model id 하나를 스스로 판단하게 만들 수도 있습니다. [models.router] 항목은 type 키로 라우팅 알고리즘을 지정합니다. stage_router는 강한 티어와 효율 티어를 지정하고 대화의 최근 tool-result 메타데이터(tool_use.name과 tool_result.is_error, 프롬프트 텍스트가 아닙니다)로 턴마다 둘 중 하나를 고르며, auto는 같은 라우터를 업스트림 프리셋으로 돌리고, random은 가중치를 둔 타깃들로 트래픽을 나누되 한 세션은 같은 갈래에 머무르게 하고, noop은 빈 메시지로 답해 연결 점검에 쓰고, prefill_router는 가장 최근 사용자 턴을 읽는 학습형 분류기로 기본 꺼짐인 prefill-router 카고 피처를 켜고 빌드한 바이너리에서만 쓸 수 있습니다. 판단을 LLM 판정 모델에 맡기는 타입도 둘 있습니다. llm_classifier는 판정 결과대로 라우팅하는데, mode = "capability"는 판정 모델이 매긴 해결 확률로 강한 타깃과 약한 타깃 중 하나를 고르고, mode = "custom"은 직접 작성한 프롬프트와 JSON 스키마가 지목한 모델 그룹을 고릅니다. composite는 stage_router의 신호 채점은 그대로 둔 채, 신호가 결론을 내지 못했을 때 떨어질 티어만 판정 모델이 정하게 합니다. 클라이언트가 보기 전에 완성된 턴을 판정하는 타입도 둘 있습니다. mode = "escalation"인 llm_classifier는 약한 타깃의 턴을 내보내다가 판정 모델이 곤경에 빠졌다고 거듭 판단하면 세션을 강한 타깃에 고정하고, advisor는 더 강한 리뷰어가 실행 모델의 마무리 턴을 승인하거나 작업을 다시 하도록 돌려보냅니다. 이런 턴은 판정이 나올 때까지 붙잡아 두었다가 재생하므로, 첫 바이트는 턴 전체가 끝난 뒤에 도착합니다. stage_router에는 판정 모델을 지정하는 [models.router.classifier] 테이블을 선택적으로 더할 수 있습니다. 이 판정 모델은 신호가 결론을 내지 못한 턴에서만 호출되고 클라이언트에게는 제공되지 않습니다. 언제 판정 모델을 부를지는 classify_trigger 키가 정하고(every_request, user_turn, new_session), judge_*/gated_*/max_judge_calls 여섯 개 키가 내부 호출마다 한도를 겁니다. 타깃은 모두 평범한 공개 model id라서 각자의 페일오버 체인과 풀, 어댑터를 그대로 유지합니다(라우팅 개요). 또 어떤 항목이든 [models.subagents] 오버레이를 함께 실을 수 있습니다. 이 오버레이는 위임된 작업(Task 서브에이전트, 훅 에이전트, 워크플로 서브에이전트)을 다른 타깃으로 보내며, 원하면 에이전트 타입별로 갈라 보낼 수도 있습니다(by_type = { Explore = "claude-haiku-4-5" }). 부모 세션은 자기 목적지를 그대로 유지하고, main과 컴팩션, 보조 턴은 이 오버레이를 절대 타지 않습니다. 이 오버레이에는 두 번째 형태인 type = "llm_classifier", mode = "custom"도 있습니다. 판정 모델이 위임된 작업을 읽고 (세션, 에이전트) 쌍마다 한 번씩 자식의 타깃을 골라 주며, 부모는 판정 대상이 되지 않습니다. 라우터도 subagents 오버레이도 설정하지 않으면 동작은 그대로입니다.

Claude Code 통합(공식 표면)

Claude Code는 ANTHROPIC_BASE_URL 뒤에 1급 게이트웨이 계약을 공개합니다. shunt는 이전 Claude Code 프록시들이 기대던 "서브에이전트 시스템 프롬프트 해싱"이라는 취약한 휴리스틱 대신 이 계약을 구현합니다.

  • LLM Gateway Protocol — 엔드포인트, 전달할 헤더·본문 필드와 소비할 필드, 기능 패스스루, 어트리뷰션을 규정한 API 계약입니다. 실행 중인 게이트웨이는 GET /protocol에서 기계가 읽을 수 있는 스펙을 제공합니다. Claude Code는 클라이언트 버전과 대화 지문을 시스템 프롬프트 앞에 붙이는데, 이를 없앨지는 CLAUDE_CODE_ATTRIBUTION_HEADER=0으로 개발자가 정할 몫이므로 shunt는 그 어트리뷰션 블록을 그대로 전달합니다. 블록을 없앤 경우 shunt는 구독 OAuth 토큰으로 Anthropic 라우트에 보내는, 마커 없는 Claude Code 요청에 Claude Code identity를 복원하여(count_tokens 제외) 사이드 쿼리가 헤더 없는 client-shape 429로 거부되는 일을 막습니다.

  • 모델 디스커버리 — Claude Code는 시작 시 GET /v1/models?limit=1000을 조회해(CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1로 옵트인) 반환된 모델을 /model 선택기에 추가합니다. shunt는 큐레이션된 [[models]] 항목에 더해, auto_include_builtin_models가 true인 동안에는 호출자의 라이브 카탈로그로 응답합니다 — 이 조회는 server.default_provider가 Anthropic 종류일 때만 이뤄지며, 그렇지 않거나 크리덴셜이 없거나 조회가 실패하면 내장 스냅샷으로 대체됩니다. 제약: id가 claude/anthropic으로 시작하지 않는 항목은 무시되므로, Claude 계열이 아닌 모델은 별칭을 만들거나 수동으로 추가해야 합니다. 모델 디스커버리를 참고하세요.

  • 게이트웨이 힌트 헤더(CLAUDE_CODE_GATEWAY_HINT_HEADERS=1) — 최근 Claude Code는 매 요청을 x-claude-code-* 헤더로 설명합니다. shunt는 그중 다섯 개를 라우팅 컨텍스트로 읽어 들입니다 — 세션 id, 위임된 에이전트 id, 요청 종류(main, subagent, workflow, compaction, auxiliary), 에이전트 타입, 그리고 컨텍스트 컴팩션 직후 첫 턴에만 한 번 실리는 플래그입니다. GET /protocol은 이들을 소비 헤더로 명시합니다. 에이전트 id 헤더는 이 변수의 게이트를 받지 않으므로, 기본 배포에서도 Task 서브에이전트는 클라이언트를 바꾸지 않은 채 부모 세션과 분리된 자체 스테이지 라우터 티어 핀을 갖습니다(부모의 dwell과 승급이 오염되지 않습니다). 클라이언트에서 CLAUDE_CODE_GATEWAY_HINT_HEADERS=1을 설정하면 나머지 네 개도 전송되어, 요청 종류가 에이전트 id 폴백보다 우선하게 되고 컴팩션 이후의 턴들을 강한 티어에 유지할 수 있습니다.

  • 커스텀 모델 옵션 추가 — ANTHROPIC_CUSTOM_MODEL_OPTION은 내장 별칭을 대체하지 않으면서 게이트웨이로 라우팅되는 항목을 /model 선택기에 추가합니다. ID는 검증을 거치지 않으므로 게이트웨이가 받아들이는 문자열이면 무엇이든 됩니다. 위의 디스커버리 제약 때문에 Claude 계열이 아닌 모델을 고르는 주된 방법입니다(예: gpt-5.6-sol).

  • 도구 검색(ENABLE_TOOL_SEARCH) — Claude Code는 MCP/LSP 도구 스키마를 지연시켰다가 필요할 때 드러내어 컨텍스트를 회수합니다. shunt는 Anthropic 1급 호스트가 아니므로 직접 옵트인하지 않는 한 이 기능은 꺼진 상태입니다. 옵트인 후 지연이 유지되는지는 설정이 아니라 업스트림이 결정합니다. claude*와 anthropic/* id는 프로토콜을 바이트 단위로 유지하고, 그 외 id는 해당 호스트가 거부하므로 defer_loading 표식이 제거되며, Responses 경로에는 자체적인 3-상태 tool_search 설정이 있습니다. 도구 검색을 참고하세요.

  • auto mode의 서버측 분류기(dangerous-tool-use-*) — auto mode는 각 도구 사용의 분류를 무과금으로 API에 맡깁니다. Anthropic 라우트에서는 shunt가 요청과 판정을 중계합니다. 업스트림이 답할 수 없는 경우 — 번역 라우트이거나, 이 필드를 받아들이는 것으로 확인된 곳이 없는 Anthropic 프로토콜 서드파티인 경우 — shunt는 아무것도 돌려주지 않는 대신 동작마다 "평가 불가"로 답합니다. 그러면 클라이언트는 그 동작 하나만 로컬에서 분류하고 다음 턴에 다시 서버에 요청하므로, 세션 내내 이 기능을 포기하지 않습니다. 문제 해결을 참고하세요.

설계 원칙: 스펙을 준수하는 Anthropic-Messages 게이트웨이가 되고(/v1/messages, /v1/models, 올바른 헤더·어트리뷰션 패스스루), 요청의 model id로 라우팅하며, 매핑된 모델에 대해 Anthropic Messages ⇄ OpenAI Responses API를 번역합니다. Claude Code 프롬프트가 바뀔 때마다 깨지는 프롬프트 형태 휴리스틱은 쓰지 않습니다.

관련 작업 / 선행 사례

Claude Code 전용 라우터 및 프록시

  • musistudio/claude-code-router — 이 분야에서 가장 큰 프로젝트로, Claude Code를 기반으로 요청이 서로 다른 모델/프로바이더에 도달하는 방식을 결정합니다.
  • 1rgs/claude-code-proxy — Claude Code를 OpenAI 모델에서 실행합니다.
  • fuergaosi233/claude-code-proxy — Claude Code → OpenAI API 프록시.
  • seifghazi/claude-code-proxy — 진행 중인 Claude Code 요청을 캡처/시각화하며, 다른 프로바이더로의 선택적 에이전트별 라우팅을 지원합니다(shunt의 서브에이전트 라우팅 아이디어에 직접적인 영감을 준 프로젝트).
  • luohy15/y-router — Claude Code가 OpenRouter와 함께 작동하도록 하는 간단한 프록시입니다.
  • tingxifa/claude_proxy — Claude API 요청을 OpenAI 형식으로 변환하는 Cloudflare Workers 프록시(Gemini, Groq, Ollama).
  • badlogic/claude-bridge — Claude Code에서 어떤 모델 프로바이더든 사용합니다.
  • jimmc414/claude_n_codex_api_proxy — 런타임 간 라우터: Anthropic 또는 OpenAI API 호출을 로컬 Claude Code 또는 Codex CLI로 프록시합니다(API 키가 모두 9인 경우 로컬 CLI로, 아니면 실제 클라우드 API로 라우팅). 방향이 반대라는 점에 유의하세요. Claude Code 에이전트를 클라우드 프로바이더로 내보내는 것이 아니라 클라우드 API 호출을 로컬 CLI로 라우팅합니다.
  • insightflo/chatgpt-codex-proxy — Claude Code 추론을 ChatGPT Codex 백엔드에서 제공하는 Anthropic 호환 /v1/messages 프록시입니다(API 키 대신 ChatGPT Plus/Pro 구독 사용). shunt와 동일한 추론 계층 교체로, Claude Code의 UI와 MCP 도구를 유지하면서 Codex/GPT 구독 백엔드를 대상으로 합니다.

범용 AI 게이트웨이(인접 인프라 — 백엔드가 될 수 있음)

  • BerriAI/litellm — 100개 이상의 LLM API를 OpenAI 형식으로 호출하는 SDK + 프록시/AI 게이트웨이로, 비용 추적, 가드레일, 로드 밸런싱을 제공합니다.
  • Portkey-AI/gateway — 통합 가드레일과 함께 1,600개 이상의 LLM으로 라우팅하는 빠른 AI 게이트웨이입니다.
  • maximhq/bifrost — 적응형 로드 밸런싱과 1000개 이상 모델 지원을 갖춘 고성능 AI 게이트웨이입니다.
  • mazori-ai/modelgate — 오픈소스 LLM 게이트웨이 + MCP 서버(Go): RBAC/정책 시행, 멀티 프로바이더(OpenAI, Anthropic, Gemini, Bedrock, Azure, 로컬 Ollama), 시맨틱 도구 검색을 갖춘 MCP 게이트웨이, 시맨틱 응답 캐싱을 제공합니다.

shunt는 어떻게 다른가

위의 대부분의 Claude Code 프록시는 모든 트래픽을 하나의 대체 프로바이더로 라우팅합니다(전역 모델 교체). shunt의 초점은 요청의 model id로 결정되는 선택적, 모델별 우회입니다. 메인 세션은 Claude에 두고, 지정한 모델만 다른 프로바이더로 우회합니다. 스위치보드/패치베이 활용 사례입니다. Claude Code는 이미 컨텍스트별로 모델을 바인딩할 수 있게 해주므로(메인 세션, 서브에이전트 model: 프론트매터, CLAUDE_CODE_SUBAGENT_MODEL), 그 동일한 선택성이 shunt가 호출자가 누구인지 조사하지 않고도 개별 에이전트까지 도달합니다.

기여

이슈와 PR을 환영합니다. 빌드/테스트 명령과 컨벤션은 CONTRIBUTING.md와 AGENTS.md를, 취약점 보고는 SECURITY.md를 참고하세요.

코드 리뷰

shunt의 풀 리퀘스트는 두 개의 AI 코드 리뷰어 도구가 검토하며, 둘 다 오픈소스 프로젝트에 무료로 제공됩니다.

  • Greptile — OSS 프로그램에 따라 비상업적 MIT/Apache 프로젝트에 무료.
  • cubic — 공개 저장소에 무료.

라이선스

Apache License, Version 2.0 또는 MIT license 중 하나를 선택하여 사용할 수 있습니다. 명시적으로 달리 명시하지 않는 한, Apache-2.0 라이선스에 정의된 대로 귀하가 이 크레이트에 포함하기 위해 의도적으로 제출한 모든 기여는 추가 조건 없이 위와 같이 이중 라이선스가 부여됩니다.


Made with Orca 🐋