Files
dotfiles/docs/specs/2026-07-15-proxy-client-design.md
T
ddadminandClaude Opus 5.5 e709c585fa docs(proxy-client): спецификация под упрощённый код, ссылка из README
Спецификация 603 → 220 строк: без описаний снятых защит и без пересказа
кода и README; остались задача, границы, решения с причинами и риски.
В README раздел «Изменение кода» ведёт к спецификации и тестам.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 09:36:56 -04:00

15 KiB
Raw Blame History

proxy-client для агентских CLI

Дата: 2026-07-15

Статус: реализовано; 2026-09-28 упрощено по принципу ниже

Точное поведение, форматы, сообщения и команды описаны в коде, proxy-client --help и proxy-client/README.md. Здесь — то, чего по коду не видно: задача, границы, выбор и его причины, риски.

Принцип: личный инструмент

proxy-client пользуются владелец и несколько друзей на своих машинах. Код защищается от реальных ошибок и опасностей:

  • скачанный Xray проверяется по SHA-256 и заменяется атомарно;
  • секреты профиля не попадают в вывод, служебные файлы закрыты правами 600/700;
  • локальный порт Xray слушает только loopback;
  • чужие файлы не перезаписываются;
  • сигнал уходит только процессам из state.json: Xray — если его /proc/PID/exe совпадает с запущенным файлом, супервизору — если Xray подтверждён и в командной строке супервизора есть proxy-client.

Пользователь и его собственные файлы — не противник. Сообщение об ошибке называет файл полным путём и подсказывает готовую команду.

Новая защита появляется вместе со сценарием, который реально случается у пользователя, и этот сценарий записывается рядом с ней. Так же проверяется и прежний код: в 2026-09-28 убраны защиты без такого сценария — повторное использование PID, подложный state.json, zip-бомба в проверенном архиве, гонка status с параллельным start.

Тесты проверяют поведение через команду proxy-client, разбор ссылки (parse_vless + build_xray_config), установку Xray с подставным скачивателем, функции Bash с поддельным PROXY_CLIENT_BIN и установщик пакета во временном HOME.

Проблема

На удалённых Linux-серверах нет GUI-клиента Hiddify. Перед запуском Claude Code или Codex приходится вручную запускать Xray и выставлять proxy-переменные. Переменные легко забыть, и агент стартует без прокси.

Нужны привычные команды pclaude и pcodex, которые не запускают агента, если явно настроенный прокси недоступен. Решение работает и в составе этого репозитория, и отдельно от остальных dotfiles.

Контекст

Прежний дизайн pclaude / pcodex задаёт договор: proxy-переменные видны только дочернему процессу, аргументы и код возврата сохраняются, недоступный прокси — отказ до запуска агента. Эта спецификация заменяет его Linux-часть; Windows-часть не меняется.

Xray принимает конфигурационные файлы, а не vless://-ссылки. Его SOCKS-вход принимает SOCKS и HTTP на одном порту, поэтому прежняя схема proxy-переменных подходит локальному Xray без второго порта. См. командную строку Xray и SOCKS-вход.

Цели

  • Управляемый пользовательский Xray на Linux-сервере без systemd и root.
  • Явные pclaude и pcodex, которые нельзя случайно запустить через другой прокси или без прокси.
  • Одна VLESS-ссылка Hiddify превращается в клиентский JSON Xray.
  • Внешний Hiddify работает, как раньше.
  • Машинный NO_PROXY настраивается без правки файлов репозитория.
  • Каталог proxy-client/ можно скопировать отдельно и поставить своим установщиком, без остальных dotfiles и без Stow.

Не входит в объём

  • Windows, PowerShell, Windows Codex launcher и VS Code Server.
  • systemd, автозапуск, sudo, firewall, TUN и системная маршрутизация.
  • Автоматический выбор между Xray и Hiddify или запасной прокси.
  • Несколько одновременных профилей у одного Unix-пользователя.
  • Импорт подписок или полного JSON-экспорта Hiddify.
  • Протоколы за пределами двух поддержанных семейств VLESS.
  • pip, venv и сторонние Python-библиотеки.
  • Сетевая изоляция голых claude и codex: намерение выражают команды с префиксом p.

Рассмотренные варианты

  • Только Bash. URL-кодирование, JSON, контрольные суммы и управление процессом делают Bash хрупким и плохо тестируемым.
  • Bash-контроллер и Python-преобразователь. Граница между двумя языками усложняет ошибки, тесты и единый источник настроек.
  • Один Python CLI и тонкий Bash-модуль. Выбран. Python отвечает за данные, установку Xray, процессы и запуск дочерних команд. Bash нужен только там, где меняется окружение текущей shell-сессии.
  • Без менеджера: готовые JSON и Xray вручную в tmux. Почти нет кода, но не решает главного — безопасного pclaude/pcodex из ссылки Hiddify.

Для отдельно скопированного пакета рассматривались: только инструкция для ручных ссылок (легко забыть шаги), копирование файлов в $HOME (сложно обновлять), обязательный Stow (лишняя зависимость на серверах) и свой установщик. Выбран свой установщик, который ставит прямые ссылки: один способ, нет второй копии файлов.

Решение

Компоненты

proxy-client — один исполняемый файл на Python 3.8+ без внешних библиотек: установка Xray, запуск и остановка, проверка доступности, разбор VLESS, запуск дочерней команды через прокси. Команды: install, start, stop, status, env, run. Без подкоманды ничего не делается.

shell.bash — единственный владелец proxy_on, proxy_off, pclaude, pcodex и myip; в bash/.bash_functions их нет, чтобы не зависеть от порядка source. Модуль сам конфиг не читает:

  • pclaude и pcodex вызывают proxy-client run -- COMMAND ARG...;
  • proxy_on берёт готовые переменные из proxy-client env и применяет их, только если команда завершилась успешно; eval не используется;
  • proxy_off очищает переменные в обоих регистрах.

proxy_on/proxy_off больше не запрашивают внешний IP: это замедляло переключение. Для проверки есть myip и proxy-client status.

Настройки

Два файла в ~/.config/proxy-client/:

  • config — несекретный машинный INI: тип xray или external, имя, адрес, порт, добавка к NO_PROXY. Если файла нет, используется прежний Hiddify на hproxy.local:12334.
  • default.url — секретная VLESS-ссылка с правами 600; start -f берёт другой файл.

Они разделены, потому что первый описывает политику машины, а второй — секрет, который меняется независимо. Выбран INI, а не TOML: tomllib появился только в Python 3.11.

Явный тип прокси

xray значит: нужен Xray, запущенный через proxy-client start. Если его нет, агент не запускается. external значит: проверяется только доступность адреса и порта. Ни один тип не переходит на другой сам — предсказуемость канала важнее удобства.

start работает только при type=xray и loopback-адресе в конфиге. Поэтому нельзя поднять локальный Xray, оставив pclaude направленным во внешний Hiddify. stop от типа не зависит: после переключения на external старый Xray всё равно можно остановить.

Один порт на HTTP и SOCKS, по умолчанию 12334; порт настраивается, чтобы разные пользователи одной машины не мешали друг другу.

VLESS-ссылки

Поддержаны две семьи: TCP/RAW с REALITY и XHTTP с TLS. Неизвестный или повторный query-параметр — отказ: он может менять смысл соединения, и его нужно добавить в разбор явно. Остальное проверяет xray run -test.

Hiddify Manager добавляет allowInsecure/insecure даже к профилям с нормальным сертификатом (Hiddify-Manager#5438), а Xray 26.2.6 эту опцию удалил. Поэтому поля принимаются и игнорируются с предупреждением; TLS-проверку задают pcs и vcn.

Сводка перед запуском не показывает UUID, ключи REALITY и содержимое XHTTP path (там бывает токен). Ссылка не передаётся аргументом командной строки.

Установка Xray

proxy-client install ставит в ~/.local/bin/xray официальный архив одного зафиксированного релиза (сейчас 26.3.27), проверяет SHA-256 по .dgst и заменяет файл атомарно. Официальный установщик Xray не подходит: он требует root и создаёт systemd-службы. start принимает только ту же версию и никогда ничего не скачивает.

Жизненный цикл

start остаётся на переднем плане как небольшой Python-супервизор с одним дочерним Xray; ожидаемое место — панель tmux. Отдельный журнал и команда logs не нужны: хватает истории tmux. Второй start отсекает блокировка flock. state.json хранит PID супервизора и Xray, чтобы stop работал из любого терминала и мог добить Xray, если супервизор убит.

Перед запуском обязательны разбор ссылки, xray run -test и открытый порт после старта. Проверка внешнего IP — только диагностика: её сбой даёт предупреждение.

run никогда не запускает Xray, поэтому у pclaude и pcodex нет скрытого автозапуска.

Доставка

Каталог proxy-client/ раскладывается в $HOME ссылками: CLI в ~/.local/bin/, shell.bash и examples/ в ~/.config/proxy-client/. Машинный config и default.url пользователь создаёт сам; в Git они не входят.

  • Отдельно: proxy-client/install.sh ставит эти три ссылки и по умолчанию дописывает блок в ~/.bashrc. Чужие файлы не трогает. Режим прокси, Xray и сеть не настраивает — это делают отдельные команды по README.
  • В составе dotfiles: корневой install.sh подключает тот же пакет через Stow, а .bash_custom загружает shell.bash.

Риски

  • Формат ссылок Hiddify расширяется. Строгий отказ на неизвестном параметре лучше частично неверного JSON, но новые ссылки могут потребовать правки разбора.
  • Открытый порт не доказывает, что маршрут работает. Проверка внешнего IP отделена от обязательных проверок.
  • Loopback без аутентификации открыт другим пользователям того же узла. Пользователи машины считаются доверенными.
  • NO_PROXY программы понимают по-разному, особенно CIDR. README советует точные IP и домены.
  • Ссылки установки зависят от пути исходного каталога: переносить его нельзя.
  • Поддержка РЕД ОС, Astra Linux и Alt Linux заявляется только после проверки версии Python и прогона tests/test_proxy_client_full.sh на них.
  • Шаблоны в examples/ содержат только вымышленные значения; настоящие ссылки, UUID и ключи в репозиторий не попадают.