Skip to content
Apothem
Блог

Внутри устройства мультиокруженческого адаптера

Технический разбор протокола HarnessAdapter в Apothem и трёх классов адаптеров, которые материализуют один профиль в семнадцать окружений.

Apothem материализует один общий профиль в семнадцать нативных для окружения конфигураций. Семнадцать целей, семнадцать форматов поставщиков, семнадцать мест установки — и один однородный интерфейс, на который опираются и оператор, и CLI. Этот пост объясняет, как слой адаптеров удерживает этот контракт вместе.

Протокол HarnessAdapter

Каждый адаптер окружения реализует структурный протокол HarnessAdapter. Протокол — это шов между CLI и деталями, специфичными для поставщика. Он объявляет операции, которые вызывает CLI, и метаданные, которые CLI читает:

  • name — зарегистрированный идентификатор адаптера.
  • output_path — куда на диск приземляется материализованная конфигурация.
  • install — отрендерить и записать нативную для окружения конфигурацию.
  • uninstall — удалить материализованную конфигурацию, оставив общий профиль нетронутым.
  • is_installed — сообщить, присутствует ли конфигурация окружения.
  • verify — обнаружить расхождение между профилем и конфигурацией на диске.

Поскольку контракт — это typing.Protocol, адаптер удовлетворяет ему по форме, а не по наследованию. CLI загружает адаптеры динамически через importlib.metadata из таблицы [project.entry-points."apothem.harnesses"] в pyproject.toml. Добавить окружение означает опубликовать подпакет, который раскрывает протокол — без правки центрального диспетчера.

Один подпакет на адаптер

Каждый адаптер живёт в собственном подпакете под src/apothem/harnesses/<name>/:

  • __init__.py — класс <Name>Adapter, который реализует протокол и делегирует соседним модулям действий.
  • install.py / uninstall.py / update.py / verify.py — реализации по каждому действию, которые класс адаптера импортирует и вызывает.
  • materializer.py — необязательный materialize_native_config(profile) -> str, который рендерит общий профиль в нативный для окружения текст конфигурации.

Разделение каждого действия на собственный модуль держит класс адаптера тонким: это диспетчер, который сводит методы протокола с функциями действий. Читатель, открывающий verify.py, видит ровно логику обнаружения расхождения для одного этого окружения, без шума установки или удаления, через который пришлось бы продираться.

Три класса адаптеров

Семнадцать окружений потребляют конфигурацию не все одинаково. Apothem сортирует их на три класса по тому, сколько преобразований нужно профилю, прежде чем он достигнет окружения.

Класс I — сырое распространение

Окружение потребляет те же артефакты, которые Apothem уже пишет — плоские правила .md, agents, hooks — без шага рендеринга. Адаптер копирует сырые шаблоны в дерево конфигурации окружения. Здесь нет materializer.py, потому что ничего не рендерится; артефакты профиля и есть вывод.

Класс II-A — сырое плюс шаблоны поставщика

Окружение потребляет сырые артефакты Apothem И набор специфичных для поставщика файлов-шаблонов (файлы настроек, манифеста или каркаса, которые требуются окружению). Адаптер копирует сырые артефакты и шаблоны поставщика вместе. Шаблоны поставщика живут рядом с адаптером в каталоге templates/.

Класс II-B — рендеринг из профиля

Окружение хочет один нативный файл конфигурации, отрендеренный из структурированных полей общего профиля. materializer.py адаптера читает профиль и выдаёт нативный для окружения текст — config.yaml для Hermes, openclaw.json для Open-Claw, opencode.json для OpenCode или settings.json для Qwen Code. Класс II-B — это место, где сосредоточена работа по согласованию форматов; разбор сходимости конвенций рассматривает её подробно.

claude-code: эталонный адаптер полной поверхности

Адаптер claude-code — это эталонная реализация для самой широкой поверхности конфигурации — правила, agents, hooks, output-styles, настройки и каталоги конвенций. Он принадлежит к Классу II-A: он распространяет сырые шаблоны Apothem и уплощает каталоги конвенций, а также поставляет шаблоны настроек поставщика под src/apothem/harnesses/claude_code/templates/. Он не несёт materializer.py — он не рендерит нативный файл конфигурации из профиля; он распространяет артефакты и каталоги конвенций напрямую.

Одна намеренная граница: адаптер claude-code не управляет CLAUDE.md. Этот файл — территория, принадлежащая оператору. Apothem материализует окружающую поверхность конфигурации — правила, hooks, настройки — и оставляет собственный голос CLAUDE.md оператора нетронутым. Адаптер, который бы его перезаписывал, стирал бы написанные вручную инструкции проекта при каждом apothem install, поэтому адаптер проводит черту на границе каталога и останавливается.

Почему однородность важна

Протокол даёт оператору одну ментальную модель через семнадцать инструментов. apothem install, apothem verify, apothem uninstall ведут себя одинаково, рендерит ли цель один файл или уплощает дерево каталогов. Различия поставщиков живут внутри подпакетов адаптеров, за протоколом, там, где им и место.

Прочтите ориентированный на оператора справочник в Окружениях и модель профиля в Концепциях.

On this page