Я хотел запускать Claude Code через подписку ChatGPT/Codex. Без OpenAI API key и без потери привычных вещей: инструментов, скриншотов, /compact, длинных сессий и нормальных ошибок.
На бумаге это выглядит как простой локальный прокси. На практике пришлось переводить не только JSON, но и поведение Anthropic API: потоковые события, вызовы инструментов, лимиты контекста, файлы, картинки и типы ошибок.
Так появился мой open source fork Claudex.

Коротко: Claudex делает вид, что он Anthropic-compatible endpoint для Claude Code, а внутри переводит запросы в OpenAI Responses API и ходит в ChatGPT/Codex через OAuth.
Содержание
→ Статус на сейчас
→ ✅ Готово для обычной работы в Claude Code
→ ⚠️ Зависит от аккаунта и провайдера
→ ℹ️ Вне scope по дизайну
→ Быстрый старт
→ Чего я хотел
→ Где ломались простые прокси
→ Что пришлось чинить
→ 1. Разделить запуск и настройку
→ 2. Использовать ChatGPT/Codex OAuth вместо OpenAI API key
→ 3. Перевести Anthropic Messages в OpenAI Responses
→ 4. Картинки: сохранить текущие, не таскать бесконечно старые
→ 5. Сохранить/compactи восстановление после лимита контекста
→ 6. Контекст на 1M без самообмана
→ 7. Потоковые ответы — это отдельная машина состояний
→ 8. Ошибки нельзя сваливать в один 502
→ 9.config doctor
→ 10. Установщик тоже пришлось допиливать
→ Что получилось
→ Что я оставил за бортом
→ Вывод
Статус на сейчас
✅ Готово для обычной работы в Claude Code
-
ChatGPT/Codex OAuth без OpenAI API key;
-
текстовые диалоги, инструменты и потоковые вызовы инструментов;
-
изображения, файлы и документы в тех форматах, которые можно переложить в Responses API;
-
/compact, автосжатие и восстановление после переполнения контекста; -
большие GPT-контексты вроде 1M там, где это проверено на практике;
-
перевод ошибок OpenAI/Codex в типы ошибок, понятные Claude Code;
-
claudex-config config doctorдля проверки настройки, авторизации и запущенного прокси; -
локальный установщик с проверкой версии и SHA256.
⚠️ Зависит от аккаунта и провайдера
-
доступные модели и их mini/pro-варианты;
-
web search и похожие возможности;
-
соответствие слотов
haiku,sonnet,opusреальным моделям аккаунта; -
поведение OpenAI-compatible провайдеров вне основного ChatGPT/Codex сценария.
ℹ️ Вне scope по дизайну
-
серверные инструменты Anthropic не проксируются как инструменты OpenAI;
-
скрытое reasoning у Codex не превращается в thinking blocks Claude Code.
Быстрый старт
Если хочется просто попробовать, установка на macOS/Linux выглядит так:
curl -fL --progress-bar https://raw.githubusercontent.com/pilc80/claudex/main/install.sh | bashclaudex-config auth login chatgpt --profile codex-subclaudex
На Windows используется PowerShell-установщик:
irm https://raw.githubusercontent.com/pilc80/claudex/main/install.ps1 | iex
Установщик ставит две команды: claudex для запуска Claude Code и claudex-config для настройки профилей, OAuth и проверки окружения.
Чего я хотел
Я не хотел делать еще один прокси к OpenAI.
Идея была проще: чтобы claudex запускался почти как claude, только запросы шли не в Anthropic API, а в ChatGPT/Codex через OAuth-профиль.
claudex
То есть пользователь остается в Claude Code, но модель и способ авторизации меняются под капотом.
Общий путь запроса выглядит так:
+-------------+ +----------------------+ +----------------+| Claude Code | -----> | claudex local proxy | -----> | ChatGPT/Codex |+-------------+ +----------------------+ +----------------+ | | | | Anthropic Messages | OpenAI Responses | | tools, SSE, errors | OAuth profile | v v v привычный UX перевод протоколов модель из подписки
Главная сложность не в самом HTTP-прокси. Claude Code ожидает не просто JSON-ответ, а поведение Anthropic API: вызовы инструментов, потоковые события, учет токенов, причины остановки, ошибки и сигналы о переполненном контексте. Если потерять эти детали, интерфейс вроде бы запускается, но привычный рабочий процесс начинает сыпаться.
Снаружи это должно выглядеть как обычный Claude Code. Внутри — совсем другой протокол и другой способ авторизации.
Где ломались простые прокси
Простой прокси обычно держится, пока сценарий похож на обычный чат:
-
пользователь пишет текст;
-
модель отвечает текстом;
-
история короткая;
-
инструменты почти не участвуют;
-
картинок нет;
-
/compactне нужен; -
ошибки можно показать как «сбой на стороне провайдера».
В реальной работе Claude Code быстро выходит за эти рамки.
У меня постоянно всплывали другие случаи: Claude читает скриншот из результата инструмента, в истории остаются старые изображения в base64, сессия упирается в лимит контекста, OpenAI Responses отдает потоковые события в другой форме, провайдер возвращает ошибку, которую Claude Code должен распознать как invalid_request_error, rate_limit_error или authentication_error.
Если на все это отвечать «502 Bad Gateway», Claude Code теряет смысл ошибки. Он не запускает восстановление, не предлагает /compact там, где должен, неверно считает использование токенов и иногда просто роняет сессию.
Что пришлось чинить
1. Разделить запуск и настройку
В fork я разделил две команды:
claudex запускает Claude Code и прокидывает ему все аргументыclaudex-config управляет авторизацией, профилями, прокси и проверкой настройки
Это маленькая деталь, но она сильно влияет на ощущение от инструмента. Если claudex должен быть заменой claude, он не может забирать себе флаги Claude Code.
Например, такие команды должны вести себя как в обычном Claude Code:
claudex --resume <session-id>CLAUDEX_MODEL=gpt-5.5 claudexCLAUDEX_PROFILE=codex-sub claudex
Поэтому управление профилями, авторизацией и прокси вынесено в claudex-config, а claudex остался тонким слоем запуска.
В src/process/launch.rs он выставляет переменные окружения ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_MODEL, настраивает model slots и запускает настоящий бинарник claude.
2. Использовать ChatGPT/Codex OAuth вместо OpenAI API key
Я специально не хотел завязываться на OpenAI API key. Вся идея была в том, чтобы использовать подписку ChatGPT Plus/Pro или Codex.
Профиль выглядит примерно так:
[[profiles]]name = "codex-sub"provider_type = "OpenAIResponses"base_url = "https://chatgpt.com/backend-api/codex"default_model = "gpt-5.5"auth_type = "oauth"oauth_provider = "openai"enabled = true[profiles.models]haiku = "gpt-5.5"sonnet = "gpt-5.5"opus = "gpt-5.5"
Токены хранятся локально в системном хранилище учетных данных: Keychain на macOS или аналогах на других системах. Для пользователя процесс короткий:
claudex-config auth login chatgpt --profile codex-subclaudex
Для серверов и удаленных машин есть вход через device code.
3. Перевести Anthropic Messages в OpenAI Responses
Самая большая часть работы — слой перевода.
Anthropic Messages API и OpenAI Responses API похожи только издалека. В деталях приходится переводить почти все:
Anthropic Messages OpenAI Responses------------------ ----------------system -> instructionsmessages -> input[]tool_use -> function_calltool_result -> function_call_outputimage block -> input_imagedocument/file block -> input_file / file datausage <- usage в формате Claude Codestop_reason <- причина остановки в формате Claude Code
Эта часть живет в src/proxy/translate/responses.rs.
Например, Anthropic tool_result нельзя просто отправить как пользовательский текст. Для Responses API это отдельный function_call_output. Если внутри результата инструмента есть изображение, его нужно вынести отдельным пользовательским сообщением с input_image.
Иначе ломается обычный сценарий: Claude прочитал файл или скриншот через инструмент и продолжает работать по результату.
4. Картинки: сохранить текущие, не таскать бесконечно старые
С изображениями был неприятный баг.
Claude Code может хранить в истории картинки в base64. Если прокси каждый раз честно пересылает всю историю, запрос быстро разрастается. Потом сервер отказывает из-за лимита размера тела запроса, и пользователь видит странную ошибку вместо ответа.
В fork я сделал более прагматичную логику:
текущий запрос ├─ новые изображения -> сохранить ├─ изображения из результата tool -> сохранить └─ старые тяжелые дубликаты в истории -> заменить короткой ссылкой на первый вывод
В responses.rs за это отвечают extract_tool_result_images, convert_image_block и дедупликация больших повторяющихся function_call_output.
Это не идеальная с теоретической точки зрения история сообщений. Зато текущая задача не ломается, а прокси не гоняет один и тот же огромный кусок base64 по кругу.
5. Сохранить /compact и восстановление после лимита контекста
Для Claude Code /compact — не украшение интерфейса. В длинных сессиях это нормальный способ продолжить работу, когда контекст закончился.
Проблема в том, что OpenAI/Codex сообщает о переполненном контексте не так, как Anthropic. Если вернуть ошибку сервера как есть, Claude Code не всегда понимает: это именно «prompt is too long», пора предложить /compact или /clear.
Поэтому переполнение контекста переводится в ошибку Anthropic-формата:
{ "type": "error", "error": { "type": "invalid_request_error", "message": "prompt is too long" }}
После этого Claude Code идет по своему обычному пути восстановления.
Codex: context window exceeded | vclaudex: invalid_request_error / "prompt is too long" | vClaude Code: предлагает /compact или /clear
Я намеренно не стал изобретать собственное автоматическое сжатие истории между разными протоколами. Если Codex говорит, что окно заполнено, claudex возвращает Claude Code ожидаемый сигнал. Дальше решает Claude Code и пользователь.
6. Контекст на 1M без самообмана
Еще одна практическая деталь — размер контекста.
Для проверенных больших GPT-моделей claudex показывает Claude Code модель с суффиксом [1m]:
gpt-5.5-pro[1m]
Claude Code видит большое окно. Перед отправкой в OpenAI/Codex суффикс убирается:
gpt-5.5-pro[1m] -> gpt-5.5-pro
А для обычного gpt-5.5 fork оставляет более осторожное окно автосжатия около 272k. Причина простая: среда выполнения может отклонять большие запросы, даже если в описании модели фигурирует 1M context.
Формально поддерживает и стабильно работает — не одно и то же.
7. Потоковые ответы — это отдельная машина состояний
Потоковый ответ нельзя просто прокинуть байтами.
Claude Code ожидает события Anthropic SSE:
message_startcontent_block_startcontent_block_deltacontent_block_stopmessage_deltamessage_stop
OpenAI Responses отдает другие события:
response.createdresponse.output_text.deltaresponse.function_call_arguments.deltaresponse.failedresponse.incomplete...
Пришлось держать состояние:
-
началось ли сообщение;
-
открыт ли блок содержимого;
-
идет ли вызов инструмента;
-
приходили ли части аргументов;
-
сколько пришло входных и выходных токенов;
-
были ли закэшированные токены;
-
что делать, если сервер оборвал соединение посреди ответа.
В упрощенном виде это выглядит так:
OpenAI stream event | v+-------------------------+| ResponsesStreamState || - current block || - current tool call || - token usage || - cached tokens |+-------------------------+ | vAnthropic SSE event для Claude Code
Эта логика в src/proxy/translate/responses_stream.rs.
Отдельно я добавил более понятные ошибки для случаев, когда сервер вернул 200 OK, начал потоковый ответ, а потом замолчал или оборвал соединение. Без этого такие баги выглядят как мистика: HTTP вроде успешный, но Claude Code не получил нормальный конец сообщения.
8. Ошибки нельзя сваливать в один 502
В агентном сценарии ошибка — это не просто текст для пользователя. По ней Claude Code выбирает поведение.
Разные случаи требуют разных реакций:
-
ошибка авторизации;
-
лимит запросов;
-
проблема с оплатой или квотой;
-
неверный запрос;
-
слишком длинный prompt;
-
перегрузка провайдера;
-
таймаут;
-
слишком большой запрос.
Если все завернуть в общий api_error, диагностика становится хуже, а резервные маршруты и circuit breaker начинают принимать неверные решения.
В src/proxy/error_translation.rs ошибки переводятся в типы Anthropic:
authentication_errorbilling_errorinvalid_request_errorrate_limit_erroroverloaded_errortimeout_errorrequest_too_large...
Плюс есть разделение между ошибками аккаунта/запроса и реальными сбоями провайдера. Если модель недоступна для аккаунта, это надо показать напрямую. Это не повод ломать circuit breaker.
9. config doctor
После нескольких итераций стало ясно: многие проблемы будут не в слое перевода, а в настройке.
Типичные случаи:
-
не тот бинарник в
PATH; -
старый прокси все еще запущен;
-
OAuth-токен истек;
-
профиль выключен;
-
модель не поддерживается аккаунтом;
-
конфиг не найден;
-
symlink указывает не туда.
Поэтому появился:
claudex-config config doctor
Он проверяет конфиг, авторизацию, состояние прокси, профили, версию и печатает конкретные следующие действия.
Claudex doctorConfig: path: ~/.config/claudex/config.toml version: 0.9.32Profiles: codex-sub (enabled, OpenAIResponses, gpt-5.5)Checks: OK: setup looks usable
Это скучная часть проекта. Но без нее open source инструмент быстро превращается в «у меня не работает», где непонятно, сломан прокси или локальное окружение.
10. Установщик тоже пришлось допиливать
Для macOS/Linux есть install.sh, для Windows — install.ps1.
Установщик скачивает release assets, проверяет SHA256, ставит claudex и claudex-config, проверяет версию в PATH, может предложить OAuth-настройку, умеет --dry-run и при необходимости ставит проект из исходников через cargo install.
Еще он предупреждает про старый запущенный прокси. Это отдельный класс неприятных багов: пользователь обновил бинарник, symlink уже новый, а фоновый процесс все еще старый. Потом начинается охота на призраков.
Что получилось
Сейчас fork закрывает те сценарии, ради которых я его делал:
-
Claude Code запускается через ChatGPT/Codex OAuth без OpenAI API key;
-
текстовые диалоги и инструменты работают через Responses API;
-
потоковые вызовы инструментов переводятся в Anthropic SSE;
-
обычные изображения и изображения из результатов инструментов не теряются;
-
файлы и документы маппятся там, где Responses API может их представить;
-
/compact, автосжатие и восстановление после лимита контекста сохраняются; -
использование закэшированных токенов возвращается в формате Claude Code;
-
ошибки OpenAI/Codex становятся понятными ошибками для Claude Code;
-
есть установщик и
config doctor; -
CI гоняет
cargo fmt --check,cargo clippy -- -D warnings,cargo build,cargo test.
Стек обычный: Rust 2021, Axum для локального прокси, Tokio, reqwest, keyring, tracing, serde/toml. Версия в Cargo.toml на момент написания — 0.9.32.
В кодовой базе больше 400 тестовых функций/кейсов. Основная масса вокруг OAuth, перевода протоколов, потоковых ответов, ошибок, конфига и проверок установщика. Для такого прокси тесты важны: баг часто выглядит как маленькое отличие JSON, а на выходе ломает целый сценарий в Claude Code.
Что я оставил за бортом
Я сознательно не пытаюсь покрыть все.
Например:
-
серверные инструменты Anthropic не проксируются как инструменты OpenAI. Claudex сохраняет локальный путь инструментов Claude Code;
-
скрытое reasoning у Codex не превращается в thinking blocks Claude Code;
-
web search и похожие возможности зависят от провайдера и аккаунта;
-
не все OpenAI-compatible провайдеры ведут себя одинаково;
-
соответствие model slots (
haiku,sonnet,opus) приходится настраивать под реальные модели аккаунта.
Мне кажется, это нормальная граница. Иначе прокси быстро становится слоем магии, который якобы знает поведение всех backend-ов сразу. Обычно такие слои потом очень больно чинить.
Вывод
Я недооценивал, насколько Claude Code зависит не только от модели, но и от протокола вокруг нее.
Для текстового прокси достаточно переложить запрос и ответ. Для реальной агентной работы нужно сохранить гораздо больше:
-
жизненный цикл вызова инструментов;
-
состояние потокового ответа;
-
семантику изображений и файлов;
-
сигнал о переполненном контексте;
-
восстановление через
/compact; -
учет токенов;
-
типы ошибок;
-
диагностику настройки.
Вот эти скучные детали и решают, будет инструмент «иногда отвечать» или им можно пользоваться каждый день.
Claudex fork получился не универсальным шлюзом ко всем моделям, а практическим слоем совместимости между Claude Code и подпиской ChatGPT/Codex. Я хотел сохранить привычный рабочий процесс Claude Code и при этом использовать доступ к Codex через OAuth. В итоге большая часть работы оказалась не в подключении API-адреса, а в том, чтобы не потерять поведение, на которое Claude Code молча рассчитывает.
Код открыт под MIT:
https://github.com/pilc80/claudex
Если у вас похожая связка Claude Code и Codex, попробуйте и напишите issue, где сломается. Мне особенно интересны длинные сессии, картинки, /compact и потоковые ответы. Буду рад, если мой прокси кому-то еще будет полезен 🙂
ссылка на оригинал статьи https://habr.com/ru/articles/1037520/