ocx start 한 번으로 내 컴퓨터 localhost:10100에 작은 프록시 서버를 띄운다. 그러면 OpenAI의 코딩 도구 Codex(CLI·앱·SDK)와 Anthropic의 Claude Code가, 자기는 OpenAI/Anthropic 서버와 대화하는 줄 알면서도 사실은 이 프록시를 거쳐 Claude·Gemini·Grok·DeepSeek·GLM·Ollama 등 아무 LLM에나 연결된다.
핵심은 "번역"이다. Codex가 쓰는 OpenAI Responses API 요청을 상대 제공자(provider)가 알아듣는 포맷으로 바꾸고, 응답 스트림을 다시 Codex가 알아듣는 포맷으로 되돌린다 — 스트리밍·툴 호출·추론(thinking) 토큰·이미지까지 양방향으로. 여기에 ChatGPT 계정 여러 개를 묶어 쿼터를 돌려쓰는 계정 풀까지 얹혀 있다.
lidge-jun/opencodex · npm 배포명 @bitkyc08/opencodex · v2.7.31 · Bun + TypeScript 약 7만 줄 · 제공자 레지스트리 56종·어댑터 7종 · MIT · 최신 커밋 2026-07-22, 클론 소스 직접 분석)
npm install -g @bitkyc08/opencodex 후 ocx start를 치면 localhost:10100에 데몬이 뜬다. 그다음 ocx가 Codex의 설정 파일에 "OpenAI 주소를 이 프록시로" 한 줄만 심는다. 이제 Codex는 평소처럼 동작하지만, 실제 요청은 전부 프록시를 거쳐 내가 고른 제공자(Claude·Gemini·Grok·Ollama…)로 흘러간다.
같은 데몬이 /v1/messages(Anthropic Messages API)도 서빙하기 때문에, ocx claude 한 번이면 Claude Code도 똑같이 아무 백엔드에나 붙는다. 즉 "Codex는 GPT만, Claude Code는 Claude만"이라는 벤더 잠금을 프록시 하나가 풀어버린다.
이 프로젝트가 푸는 문제는 단순하다. Codex CLI는 OpenAI의 Responses API라는 독특한 형식으로만 말하고, Claude Code는 Anthropic의 Messages API로만 말한다. 두 도구 모두 "다른 회사 모델을 쓰고 싶어도 프로토콜이 안 맞아서" 갈아끼우기 어렵다. opencodex는 이 두 입력 포맷을 받아, 56종 제공자가 각자 쓰는 포맷으로 번역해 던지고, 돌아온 응답을 원래 도구가 알아듣는 포맷으로 되돌린다. README의 표현을 그대로 옮기면 "Codex의 Responses API를 당신의 제공자가 쓰는 언어로 번역하는 가벼운 로컬 프록시. 스트리밍·툴 호출·추론 토큰·이미지 — 전부, 양방향으로 동작한다."
POST /v1/responses로 OpenAI 형식 요청을 보내면, opencodex는 그걸 뜯어 Anthropic /v1/messages 형식(또는 Gemini·OpenAI-chat 형식)으로 다시 조립해 실제 제공자에게 보낸다. 응답이 스트리밍으로 오면 다시 Codex가 기대하는 response.output_text.delta 같은 이벤트로 되돌린다 — 통역사가 양쪽 말을 실시간으로 옮기는 것과 같다.TrendShift·GitHub의 저장소 주소는 lidge-jun/opencodex지만, 실제 설치 명령은 npm install -g @bitkyc08/opencodex이고 커밋 작성자도 bitkyc08-arch다. package.json의 homepage는 lidge-jun.github.io/opencodex. 즉 lidge-jun과 bitkyc08은 같은 관리자의 다른 핸들로 보인다. 설치할 때는 npm 스코프(@bitkyc08)를, 저장소를 가리킬 때는 lidge-jun/opencodex를 쓰면 된다. 명령어는 둘 다 opencodex 또는 짧은 별칭 ocx로 실행된다.
저장소는 순수 Bun + TypeScript 프로젝트로 약 7만 줄, 테스트 파일만 283개다. Docker도 파이썬도 없다 — npm으로 전역 설치해 OS 서비스(macOS launchd / Linux systemd / Windows 작업 스케줄러)로 등록하는 방식이다. 대시보드(관리 UI)는 React 19 + Vite 8로 짠 별도 패키지가 빌드 시 함께 묶인다.
"아무 LLM에나 붙는 게이트웨이/프록시"는 이미 붐비는 카테고리다. 같은 날 TrendShift 상위권에도 OmniRoute(diegosouzapw, "231+ 제공자 통합 게이트웨이")·opencodex가 나란히 올라 있고, claude-code-router·LiteLLM·OpenRouter 같은 선배들도 있다. 이 무리에서 opencodex가 눈에 띄는 지점은 "제공자를 많이 지원한다"가 아니라 "Codex라는 다루기 까다로운 클라이언트를, 그 클라이언트를 포크하지 않고, 양방향으로 통역한다"는 접근이다.
| 축 | 일반 LLM 게이트웨이(LiteLLM·OpenRouter 등) | opencodex |
|---|---|---|
| 대상 클라이언트 | 주로 Chat Completions API를 쓰는 앱 전반 | OpenAI Codex(Responses API)와 Claude Code(Messages API)에 특화 |
| 연결 방식 | 내 앱 코드에서 base URL을 게이트웨이로 바꿔 호출 | 클라이언트를 포크하지 않고 Codex 설정 파일에 base URL 한 줄만 주입 → 되돌리기도 깔끔 |
| 번역 난이도 | Chat Completions는 사실상 업계 표준이라 상대적으로 단순 | Responses API는 reasoning·encrypted_content·custom tool 등 특수 필드가 많아 양방향 번역이 훨씬 까다로움 |
| 인증(auth) | 보통 제공자 API 키 하나 | ChatGPT 계정 풀(5시간/주간/30일 쿼터 창을 여러 계정으로 돌려쓰고 쿨다운·페일오버) + OAuth(Claude Pro/Max, xAI, Kimi, Copilot, Cursor) |
| 추론/캐시 | 대개 그대로 전달 | 모델별 reasoning-effort→budget 변환, Anthropic prompt cache 브레이크포인트 자동 배치 등 제공자별 최적화 |
| 부가 기능 | 라우팅·로깅 위주 | 텍스트 전용 모델용 비전 사이드카(이미지 묘사), 웹서치 사이드카, 이미지 생성 프록시, 관리 대시보드까지 내장 |
일반 게이트웨이가 "여러 나라 콘센트를 꽂게 해주는 멀티 어댑터"라면, opencodex는 "특정 고급 가전(Codex)을 위한 전담 통역·변압 스테이션"이다. 멀티 어댑터는 웬만한 기기를 두루 받지만, Codex처럼 전압(Responses API)·플러그 모양(추론 토큰·암호화된 reasoning)이 유별난 기기는 그냥 꽂으면 400 에러가 난다. opencodex는 그 유별난 규격을 하나하나 맞춰주는 대신, 대상 기기를 Codex·Claude Code로 좁혀 그 둘만큼은 완벽하게 통역한다.
① 클라이언트를 포크하지 않는다. Codex를 개조하거나 별도 빌드를 배포하는 대신, Codex가 이미 갖고 있는 내장 openai 제공자의 base URL만 localhost:10100으로 돌린다(src/codex/inject.ts). Codex는 자기가 OpenAI와 대화하는 줄 안다. ocx stop이면 설정이 원상복구된다 — 업스트림 Codex가 업데이트돼도 깨질 여지가 적은, 유지보수 관점에서 영리한 선택이다.
② Responses API 양방향 번역이 진짜 어렵다. Chat Completions만 지원하는 프록시는 많아도, Codex의 Responses API를 제대로 통역하는 도구는 드물다. 스트리밍 이벤트(response.output_text.delta·response.reasoning_summary_text.delta·response.function_call_arguments.delta), 암호화된 추론 봉투(encrypted_content), custom tool 호출까지 왕복시켜야 한다. opencodex는 이걸 어댑터 계약 하나로 추상화해 6개 제공자 계열에 재사용한다.
③ ChatGPT 계정 풀이라는 실전 기능. ChatGPT/Codex 로그인 기반 사용은 시간·주·월 단위 쿼터가 걸린다. opencodex는 계정 여러 개를 풀로 묶어, 요청을 특정 계정에 고정(affinity)하되 쿼터가 차면 다른 계정으로 페일오버하고 쿨다운을 관리한다. "무료/저렴한 경로를 최대한 오래 쓰기"라는 현실적 수요를 정면으로 겨냥했다.
④ 완전한 MIT 오픈소스 + 활발한 개발. 코어·어댑터·대시보드 전부 MIT이고, 최신 커밋이 클론 당일(2026-07-22)일 만큼 개발이 빠르다. 40개 이상을 표방하지만 실제 레지스트리에는 56개 제공자가 등록돼 있고, 한국어를 포함해 4개 언어 README를 갖췄다.
/v1/chat/completions)는 업계 표준처럼 널리 복제된 단순한 "메시지 배열 → 답변" 형식이다. Responses API(/v1/responses)는 더 새롭고 에이전트 지향적이어서, 추론 과정(reasoning)·툴 호출·이미지 생성·암호화된 사고 흔적 같은 요소를 1급 시민으로 다룬다. Codex는 이 Responses API를 쓴다. 그래서 "아무 모델이나 Codex에 붙이려면" 이 복잡한 형식을 상대 모델 언어로 번역할 수 있어야 하고, 그게 opencodex의 핵심 난이도이자 차별점이다.이 프로젝트의 기술 선택은 "의존성을 최대한 줄이고, 제공자별 통신은 SDK 대신 직접 HTTP로 짠다"로 요약된다. 런타임 의존성이 단 네 개뿐이라는 사실이 그 철학을 잘 보여준다.
| 레이어 | 선택 | 비고 |
|---|---|---|
| 런타임 | Bun 1.3.14(의존성으로 번들됨) | HTTP 서버는 Bun.serve. Express·Fastify 같은 웹 프레임워크를 안 쓴다. 빠른 시작·네이티브 TS 실행 |
| Node 역할 | bin/ocx.mjs 런처 하나 | 사용자는 Node ≥18만 있으면 됨. Node는 번들된 Bun을 src/cli/index.ts로 실행하는 얇은 껍데기 |
| 요청 검증 | zod 4.4.3 | 들어오는 Responses API 요청을 스키마로 엄격 검증 — 이게 신뢰 경계(trust boundary) |
| MCP 지원 | @modelcontextprotocol/sdk ^1 | MCP 툴이 프록시를 왕복. 툴 이름은 namespace__name으로 평탄화 후 복원 |
| 바이너리 전송 | @bufbuild/protobuf ^2.12.0 | Cursor 어댑터가 protobuf/HTTP-2 바이너리 프로토콜로 말하기 때문 |
| 타입/빌드 | TypeScript 5.9.3, @types/bun | tsconfig: ESNext, moduleResolution: bundler, strict: true |
| 테스트 | Bun test, 283개 *.test.ts | CI에서 ubuntu·macos·windows 3면 + typecheck + privacy 스캔 게이트 |
package.json의 dependencies에 bun을 넣어, npm 설치 시 Bun 런타임까지 함께 내려받게 했다. 덕분에 사용자는 흔한 Node만 있으면 되고(bin/ocx.mjs가 번들된 Bun을 찾아 실행), Bun의 빠른 시작·네이티브 TypeScript 실행 이점은 그대로 누린다. "런타임을 앱에 끼워 배포한다"는 요즘 방식의 사례다.opencodex는 LLM 벤더 SDK를 하나도 쓰지 않는다. Anthropic SDK, OpenAI SDK, Google SDK … 전부 안 쓰고, 각 제공자를 직접 HTTP로 말하는 어댑터를 손으로 구현했다. 이유는 명확하다 — SDK에 묶이면 버전 업데이트마다 끌려다니고, Responses API ↔ 각 포맷의 미묘한 변환을 SDK가 대신 해주지 못하기 때문이다. 어댑터는 7종이다.
| 어댑터 | 담당 | 특이점 |
|---|---|---|
| openai-chat | Chat Completions 계열 (제일 많음, 42개 제공자) | OpenAI 호환 엔드포인트라면 대부분 이걸로 커버. /v1/models로 모델 자동 발견 |
| openai-responses | Responses API 계열 | OpenAI 자기 자신 등 |
| anthropic | Claude(/v1/messages) | reasoning budget 변환·prompt cache·oauth 지문까지 처리 (4장 참고) |
| Gemini(AI Studio·Vertex·Antigravity) | 3개 제공자 | |
| azure-openai | Azure OpenAI | Azure 배포 규격 |
| kiro | AWS Kiro(CodeWhisperer) | AWS 계열 인증 |
| cursor | Cursor | protobuf/HTTP-2 바이너리 프로토콜(실험적). 15k줄 생성 코드 |
| 항목 | 선택 |
|---|---|
| UI 프레임워크 | React 19.2.7 + react-dom 19.2.7 |
| 가상 스크롤 | @tanstack/react-virtual(대량 로그/요청 목록용) |
| 번들러 | Vite 8.1.0, TypeScript 6, ESLint 10 |
| 빌드 | gui/는 완전히 분리된 패키지 → 배포 시 gui/dist로 번들되어 서버가 /api/*와 함께 서빙 |
코어 프록시 외에 사이드카(sidecar) 두 개가 딸려 있다. 비전 사이드카는 텍스트 전용 모델에 이미지를 보낼 때, 이미지를 대신 "묘사"해 텍스트로 끼워 넣는다(src/vision/). 웹서치 사이드카는 합성 툴을 만들어 에이전트 루프로 검색을 수행한다(src/web-search/). 여기에 이미지 생성 프록시(/v1/images/generations·/edits), 히스토리 압축(/v1/responses/compact), 관리 API(/api/*)까지 한 데몬 안에 들어 있다.
이 저장소를 이해하는 핵심은 두 가지다. 하나는 번역 파이프라인(하나의 요청이 파서→라우터→어댑터→제공자→브릿지를 지나는 흐름), 다른 하나는 가로채기 방식(Codex를 포크하지 않고 어떻게 요청을 낚아채는가)이다.
단계별로 뜯어보면 이렇다.
src/responses/parser.ts) — 들어온 요청을 zod 스키마로 검증한 뒤, 내부 표현 OcxParsedRequest로 낮춘다. 메시지·추론 블록·툴 호출/결과·툴 정의를 정규화하고, 이미지는 base64 텍스트로 인라인하지 않고 진짜 콘텐츠 파트(data-URL 또는 https)로 보존한다.src/router.ts의 routeModel) — "이 요청을 어느 제공자/모델로 보낼지" 고정된 우선순위로 결정(아래 표).src/adapters/*) — 내부 표현을 제공자가 알아듣는 실제 HTTP 요청으로 바꾸고(buildRequest), 돌아온 스트림을 내부 이벤트로 파싱한다(parseStream).src/bridge.ts의 bridgeToResponsesSSE) — 어댑터가 뱉은 내부 이벤트를 다시 Codex 형식의 Responses SSE로 되돌린다.src/adapters/base.ts가 모든 제공자가 지켜야 할 "통역 계약"을 정의한다. 핵심 메서드는 buildRequest(내부표현) → 제공자 요청(보내는 쪽 번역)과 parseStream(제공자응답) → AsyncGenerator<AdapterEvent>(받는 쪽 번역) 둘이다. 즉 새 제공자를 추가하려면 이 두 방향의 번역만 구현하면 되고, 나머지 파이프라인(파서·라우터·브릿지)은 그대로 재사용된다. 인터페이스 하나로 56개 제공자를 규격화한 셈이다.routeModel은 아래 순서로 "어디로 보낼지"를 정한다. 위에서 걸리면 거기서 확정된다.
| 순서 | 규칙 | 예시 |
|---|---|---|
| 1 | 명시적 제공자/모델 네임스페이스 | anthropic/claude-opus-4-8 → anthropic 제공자로 |
| 2 | OpenAI 계열 맨모델 | gpt-* → Codex 로그인 openai 제공자 |
| 3 | 제공자의 defaultModel | 제공자만 지정하면 그 기본 모델 |
| 4 | 내장 접두사 패턴 | claude-*→anthropic, llama-/mixtral-/gemma-*→groq |
| 5 | 제공자의 models[] 목록 | 설정에 나열된 모델이면 그 제공자 |
| 6 | defaultProvider 폴백 | 다 안 걸리면 기본 제공자로 |
opencodex는 Codex를 포크하거나 개조하지 않는다. Codex가 이미 갖고 있는 내장 openai 제공자의 openai_base_url 한 줄만 Codex의 config.toml에 심어(src/codex/inject.ts) localhost:10100을 가리키게 한다. Codex는 자기가 OpenAI Responses API와 대화하는 줄 알지만, 모든 요청은 프록시로 떨어진다. ocx stop/restore면 설정이 원래대로 돌아오고, 실행 중 Codex 히스토리도 복원된다.
클라이언트를 포크하는 프록시들은 업스트림(Codex)이 새 버전을 내면 따라서 갈아엎어야 한다. opencodex는 "설정 파일에 한 줄 주입 + 되돌리기"만 하기 때문에 Codex가 업데이트돼도 대체로 그대로 동작한다. 게다가 codex 명령이 호출될 때마다 ocx ensure를 돌리는 codex-shim(src/codex/shim.ts)을 둬서, 프록시가 꺼져 있으면 자동으로 되살린다. "가로채되 흔적을 남기지 않는다"는 원칙이 곳곳에 배어 있다.
어댑터 번역이 왜 어려운지는 anthropic 어댑터(src/adapters/anthropic.ts)의 buildRequest가 잘 보여준다. Codex는 추론 예산과 최대 출력 토큰에 같은 값을 넣어 보내는데, Anthropic은 max_tokens가 thinking budget보다 커야 하므로 그대로 넘기면 400 에러가 난다. 어댑터는 이 지점을 이렇게 푼다.
즉 단순히 필드 이름만 바꾸는 게 아니라, 제공자별 제약과 과금 최적화까지 어댑터가 떠안는다. 반대 방향(parseStream)에서는 Anthropic SSE의 content_block_delta를 읽어 내부 AdapterEvent로 바꾸고, 브릿지가 그걸 다시 Codex의 Responses SSE로 되돌린다.
| 내부 AdapterEvent | Codex Responses SSE로 변환 |
|---|---|
text_delta | response.output_text.delta → done |
thinking_delta | response.reasoning_summary_text.delta |
tool_call_start | response.output_item.added(function_call/custom_tool_call) |
tool_call_delta | response.function_call_arguments.delta |
thinking_signature/redacted_thinking | encrypted_content reasoning 봉투로 보존 |
opencodex가 프로토콜을 통역해준다고 해서 모든 조합이 Codex 순정만큼 잘 동작한다는 보장은 아니다. Codex는 원래 OpenAI 모델에 맞춰 튜닝된 프롬프트·툴 사용 패턴을 갖고 있어서, 다른 제공자로 돌리면 툴 호출 형식·추론 토큰 처리에서 미묘한 차이가 생길 수 있다. 어댑터가 그 간극을 메우려 애쓰지만(위의 reasoning budget·cache 처리가 그 예다), 실사용 전에는 자신이 쓸 제공자 조합에서 실제로 툴 호출·스트리밍이 잘 되는지 직접 확인하는 게 좋다. 무료·저가 경로일수록 편차가 크다.
① src/cli/index.ts(ocx가 어떤 명령을 갖는지 전체 지도) → ② src/server/index.ts(Bun.serve가 노출하는 엔드포인트 목록 = 이 프로젝트의 표면) → ③ src/responses/parser.ts(요청이 내부 표현으로 바뀌는 곳, 신뢰 경계) → ④ src/router.ts + src/adapters/base.ts(라우팅 규칙과 어댑터 계약) → ⑤ src/adapters/anthropic.ts(가장 복잡한 실제 번역) → ⑥ src/bridge.ts(역번역) → ⑦ src/codex/inject.ts + shim.ts(가로채기 메커니즘). 이 순서면 "요청이 들어와 나가기까지"를 코드로 완주할 수 있다. structure/*.md와 docs-site는 관리자가 직접 쓴 고신뢰 배경 자료다.
server/responses.ts(90KB)가 담당한다. 컨트롤 플레인은 그 통로를 설정·감시하는 관리 계층 — server/management-api.ts(86KB)와 React 대시보드가 담당한다. 파일 크기가 둘 다 비슷하게 큰 걸 보면, opencodex가 "번역"만큼이나 "운영 관리(계정·쿼터·로그 관찰)"에도 무게를 뒀음을 알 수 있다.56개 제공자가 각자 다른 API를 쓰지만, opencodex는 ProviderAdapter 인터페이스(buildRequest=보내는 번역, parseStream=받는 번역) 하나로 전부 감쌌다. 새 제공자 추가 = 이 두 메서드 구현. 파서·라우터·브릿지는 손대지 않는다. "이질적인 외부 시스템 N개를 하나의 좁은 인터페이스로 어댑팅한다"는 어댑터 패턴의 교과서적 실전 사례로, 결제 게이트웨이·알림 채널·스토리지 백엔드 등 어디에나 옮겨 쓸 수 있다.
Codex를 개조하는 대신 config.toml에 base URL 한 줄을 주입하고, ocx stop이면 원복한다. 업스트림이 업데이트돼도 안 깨진다. 남의 도구 동작을 바꾸고 싶을 때 "포크해서 유지보수 지옥에 빠지는" 대신 "설정·환경변수·프록시로 얇게 개입하고 흔적을 남기지 않는" 접근은 거의 항상 더 오래간다. codex-shim으로 자동 복구까지 얹은 건 덤이다.
외부(Codex/Claude Code)에서 들어오는 Responses 요청을 zod 스키마로 검증한 뒤에야 내부 표현으로 낮춘다. "신뢰할 수 없는 입력이 시스템에 들어오는 첫 지점에서 형태를 강제한다"는 원칙. 이렇게 하면 이후 파이프라인(라우터·어댑터)은 항상 잘 정형화된 데이터만 다루므로 방어 코드가 줄고, 잘못된 요청은 경계에서 명확한 에러로 튕겨난다.
bun을 dependency로 번들해, 흔한 Node 환경만 있으면 설치되지만 실행은 빠른 Bun 위에서 이뤄지도록 했다. "우리 앱이 원하는 런타임을 사용자에게 강요하지 않고, 앱과 함께 배포한다"는 전략은 배포 마찰을 크게 줄인다. Node 런처(ocx.mjs)를 얇게 두고 실제 로직은 전부 Bun/TS로 둔 계층 분리도 참고할 만하다.
ChatGPT 계정 풀은 요청을 특정 계정에 고정(캐시 적중·일관성)하되, 쿼터가 차면 다른 계정으로 넘기고 소진된 계정엔 쿨다운을 건다. 이 "고정 우선 + 한계 시 페일오버 + 회복 대기"는 DB 커넥션 풀, API 키 로테이션, 다중 리전 트래픽 분산 등 제한된 자원을 여러 주체가 나눠 쓰는 모든 문제의 정석 패턴이다.
이미지를 못 받는 텍스트 모델에는 비전 사이드카가 이미지를 묘사해 끼워 넣고, 검색이 필요하면 웹서치 사이드카가 합성 툴로 대신 검색한다. "본체 능력이 부족한 대상에게, 본체를 고치지 않고 옆에서 능력을 보강한다"는 사이드카 사고는 레거시 시스템 확장·기능 폴리필에 두루 통한다. 능력 차이를 어댑터 바깥의 별도 컴포넌트로 흡수한 관심사 분리가 깔끔하다.
opencodex 자체는 요청을 받아 번역해 넘기는 가벼운 로컬 데몬이라, 평범한 노트북이면 충분하다. 무거운 연산(추론)은 전부 원격 제공자(또는 로컬 Ollama)가 하고, 프록시는 그 사이에서 통역만 한다.
| 항목 | 요구/권장 |
|---|---|
| Node.js | ≥ 18 (engines.node). npm 전역 설치용 런처만 Node로 돎 |
| 런타임(내장) | Bun 1.3.14 — 패키지에 번들되므로 별도 설치 불필요 |
| 설치 | npm install -g @bitkyc08/opencodex → ocx start |
| 포트 | 기본 localhost:10100. 0.0.0.0로 열려면 OPENCODEX_API_AUTH_TOKEN 필수(외부 노출 방어) |
| 서비스 등록 | macOS launchd · Linux systemd 유저 유닛 · Windows 작업 스케줄러/WinSW |
| 설정 파일 | ~/.opencodex/config.json (ocx init 또는 대시보드가 생성) |
| GPU | 불필요(로컬 추론을 Ollama/vLLM로 돌릴 때만 해당 백엔드 사양이 필요) |
| 제공자 인증 | 제공자별로 API 키 또는 OAuth. ChatGPT 경로는 계정 풀(codexAccounts[]) |
| 대시보드 | 브라우저 하나 — ocx gui로 관리 UI 접속 |
opencodex는 Codex/Claude Code의 모든 요청·응답과 여러 제공자의 API 키·OAuth 토큰을 로컬에서 다룬다. 그래서 기본 바인딩이 localhost이고, 외부(0.0.0.0) 노출 시엔 인증 토큰을 강제한다. 신뢰할 수 없는 네트워크에 포트를 열지 말고, 설정 파일(~/.opencodex/config.json)에 담기는 키 관리에 주의할 것. 코드가 MIT 오픈소스라 직접 감사할 수 있다는 점은 이런 "모든 걸 거쳐 가는" 도구에서 큰 장점이다.
npm i -g @bitkyc08/opencodex 후 ocx start로 데몬을 띄우고, ocx init(또는 ocx gui 대시보드)로 anthropic 제공자를 defaultProvider로 설정한다. 그다음 평소처럼 codex를 실행해, 실제로 Claude가 응답하는지 확인한다. ocx stop 후 Codex 설정이 원복되는지도 함께 관찰하라 — "포크 없는 주입"의 실체를 눈으로 확인하는 과제다.
Ollama를 설치해 모델 하나를 받고(ollama pull ...), config에 ollama 제공자(adapter: openai-chat, baseUrl: http://localhost:11434/v1)를 추가한다. Codex 요청이 인터넷 없이 로컬 모델로만 처리되는지, 툴 호출·스트리밍이 어디까지 동작하는지 한계를 직접 체감해본다.
ocx claude로 Claude Code를 프록시에 연결하고, /v1/messages 인바운드를 Gemini나 GLM 같은 비-Anthropic 모델로 라우팅해본다. Messages API → 다른 제공자 포맷 번역이 실제로 어떻게 동작하는지, 그리고 어디서 어색해지는지 로그(src/usage/ JSONL)로 추적한다.
src/usage/의 요청 로그를 켜고, 한 번의 Codex 요청이 parser → router → adapter → provider → parseStream → bridge를 지나는 동안 각 단계의 입출력을 추적한다. 특히 anthropic 어댑터에서 reasoning effort → thinking budget → max_tokens가 어떻게 재계산되는지, cache_control 브레이크포인트가 어디에 찍히는지 src/adapters/anthropic.ts와 대조하며 확인한다.
src/adapters/base.ts의 ProviderAdapter 인터페이스를 구현해, 아직 레지스트리에 없는 OpenAI 호환 엔드포인트(또는 사내 게이트웨이)를 붙여본다. buildRequest/parseStream 두 방향만 채우고 src/providers/registry.ts에 등록하면 되는지, 정말 파이프라인 나머지를 안 건드리고 새 제공자가 붙는지 직접 검증하라 — 어댑터 패턴의 확장성을 몸으로 확인하는 과제다.
OpenAI Chat Completions, OpenAI Responses API, Anthropic Messages API 세 가지 요청/응답 스키마를 공식 문서로 나란히 놓고 비교한다. 특히 스트리밍 이벤트(SSE) 형식, 툴 호출 표현, 추론(reasoning/thinking) 필드가 서로 어떻게 다른지 정리하면, opencodex 어댑터가 무엇을 번역하는지가 한눈에 들어온다. src/responses/schema.ts(zod)와 대조하면 좋다.
src/adapters/base.ts의 인터페이스를 출발점으로, 어댑터 패턴과 전략 패턴을 코드로 익힌다. 리버스 프록시가 요청을 가로채 변형·전달하는 일반 원리(예: Envoy·nginx의 요청 변환)와 opencodex의 애플리케이션 레벨 프로토콜 번역이 어떻게 닮고 다른지 비교해본다.
Bun의 Bun.serve·테스트 러너·번들링을 직접 써보고, "런타임을 dependency로 번들해 배포"하는 방식의 장단점을 정리한다. 이어 src/service.ts를 교재로 launchd·systemd·Windows 작업 스케줄러에 백그라운드 서비스를 등록하는 크로스플랫폼 방법을 실습한다.
OAuth(src/oauth/)와 계정 풀·쿼터 관리(src/codex/)를 읽으며 "제한된 자원을 풀로 돌려쓰는" 설계를 정리한다. 마지막으로 @modelcontextprotocol/sdk로 MCP 툴이 프록시를 어떻게 왕복하는지 확인하고, Model Context Protocol 스펙과 대조하며 에이전트 도구화의 큰 그림을 완성한다.
ocx는 짧은 실행 별칭. 저장소는 lidge-jun/opencodex, npm 배포명은 @bitkyc08/opencodex./v1/responses). 추론·툴 호출·이미지·암호화된 사고 흔적을 1급으로 다룬다. Codex가 쓰는 형식이며 opencodex 번역의 핵심 대상./v1/messages). Claude Code가 쓴다. opencodex는 같은 데몬에서 이 엔드포인트도 서빙해 Claude Code를 다른 백엔드에 붙인다.buildRequest(내부표현→제공자요청)와 parseStream(제공자응답→내부이벤트) 두 방향으로 구성. 새 제공자는 이 둘만 구현.text_delta·thinking_delta·tool_call_start 등). 브릿지가 이걸 Codex Responses SSE로 되돌린다.bridgeToResponsesSSE. 내부 AdapterEvent 스트림을 Codex가 알아듣는 Responses SSE 이벤트로 역번역하는 마지막 단계.config.toml에 base URL 한 줄만 심어 가로채는 방식(src/codex/inject.ts). ocx stop이면 원복, codex-shim이 자동 복구.max_tokens > budget이 항상 성립하도록 재계산하는 anthropic 어댑터의 핵심 로직.cache_control 마커를 최대 4곳(tools·system·직전/마지막 user)에 배치하는 최적화.Bun.serve로 프레임워크 없이 구현.@modelcontextprotocol/sdk로 MCP 툴이 프록시를 왕복하게 하고, 이름을 namespace__name으로 평탄화·복원한다.npm i -g @bitkyc08/opencodex)README.ko.md — 한국어 README(용어 대조용)