Бесплатный интерактивный курс · aicoding.space

Слой адаптеров dz: один навык — десять редакторов

Практический курс о том, как навыки из dz попадают в твой редактор и чем ты за это платишь. Вместе с Костей ты разберёшь, что такое цель (--target), какой контракт общий у всех десяти адаптеров, на какие три измеренных класса они делятся, развернёшь один и тот же навык в два редактора и сравнишь результат, а в конце прочитаешь карту dz parity — включая те клетки, где она честно признаётся, что не измеряла.

Содержание курса

1. Зачем нужен слой адаптеров?

Один навык, десять редакторов — и почему это работа компилятора, а не копипасты.

Ключевая мысль: адаптер — компилятор навыка под конкретный редактор

Костя — тимлид, и у него ровно та же проблема, с которой ты сюда пришёл. Он написал двенадцать навыков в dz. Сам сидит в Claude Code. Фронтендер — в Cursor. Дата-инженер — в Gemini CLI. Ревьюер живёт внутри GitHub Copilot. Вопрос Кости звучал так: «я напишу навык один раз — что увидит каждый из них?»

Сначала два слова, чтобы дальше говорить на одном языке.

  • Навык (skill) — это папка с файлом SKILL.md: YAML-шапка (name, description) плюс тело в Markdown. Тело — инструкция агенту, шапка — метаданные, по которым его находят.
  • Адаптер (adapter) — это компилятор: на входе один канонический навык, на выходе — файлы ровно в том виде, в каком их читает конкретный редактор.

Вот вся идея курса одной фразой: навык — один источник истины, а у каждого редактора свой формат; адаптер — компилятор из одного во многие. Не десять инструментов, а один компилятор с десятью выходами.

Почему не копировать файлы руками? Потому что копия — это не «то же самое в другом месте». Cursor читает .cursor/rules/ и игнорирует файлы с неправильным расширением. Gemini читает ОДИН файл в корне. Copilot вообще не сканирует каталог навыков. Костя, копируя руками, через неделю не помнил бы, какая копия свежая, — а главное, не знал бы, что именно потерялось по дороге.

Все десять адаптеров лежат на npm рядом друг с другом — например @dzhechkov/adapter-claude и @dzhechkov/adapter-cursor; исходники — в публичном зеркале github.com/djd1m/dz-harness.

2. Что такое цель: dz init --target

Десять имён целей, таблица псевдонимов и ловушка claude против claude-code.

Ключевая мысль: цель --target — имя в реестре dz, а не имя платформы

Костя разворачивает навыки одной командой:

dz init --target claude-code --skills-dir ./skills --project .

ИЗМЕРЕНО, вывод дословно: dz init --target claude-code: 1 skill(s), 1 file(s) written, 0 skipped, код возврата 0.

Цель (target) — это имя в реестре dz, по которому выбирается адаптер. Имён ровно десять, и команда их сама перечисляет: agents-md, claude-code, codex, copilot, cursor, gemini, hermes, openclaude, opencode, windsurf.

А теперь ловушка, на которой Костя споткнулся первым. Внутри адаптера платформа называется claude, а имя цели — claude-code. Оба работают, но по-разному: --target claude проходит через таблицу псевдонимов, и dz честно об этом печатает — ИЗМЕРЕНО: dz init: --target "claude" → claude-code (alias). Псевдонимы — это ДАННЫЕ, одна строка таблицы, а не ветвление в коде: claude и ccclaude-code, agentsagents-md, gpt и openaicodex.

Опечатка не молчит. ИЗМЕРЕНО: --target cursur даёт unknown --target "cursur" — did you mean "cursor"? и полный список допустимых имён. Это важнее, чем кажется: цель, набранная с ошибкой, могла бы «успешно» ничего не развернуть.

Установка самого dz и ссылки: @dzhechkov/harness-cli, исходники — github.com/djd1m/dz-harness.

3. Общий контракт: compile, verify и EmitResult

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

Ключевая мысль: compile и verify — чистые функции, возвращающие EmitResult

Костя открыл три адаптера подряд и увидел одно и то же. Не случайность: все десять реализуют один интерфейс Adapter из @dzhechkov/core (src/adapter.ts:68) — три члена и больше ничего:

  1. platform — имя платформы, для которой этот адаптер эмитит;
  2. compile(skill, ctx) — возвращает EmitResult { files, warnings };
  3. verify(emitResult) — возвращает VerifyResult { ok, errors, warnings }.

И compile, и verify — чистые функции. Чистая функция (pure function) — это функция, которая на одном и том же входе всегда даёт один и тот же выход и не делает ничего снаружи: не пишет файлы, не ходит в сеть, не смотрит на часы. Зачем это здесь: адаптер можно проверить целиком без файловой системы, а его вывод воспроизводим — тот же навык всегда компилируется в те же байты.

Запись на диск — забота вызывающей стороны, а не адаптера. Отсюда второе правило, записанное прямо в комментарии контракта: пути в files[] относительны ctx.targetRoot, и адаптер НЕ должен приклеивать корень сам — иначе получится <root>/<root>/… или абсолютный путь, который хост отвергнет.

Третий член контекста — ctx.strict. Смысл: «не применяй потерю молча — откажись». Про него будет отдельная секция, но запомни сейчас: строгий режим превращает предупреждение в отказ.

И измеренная мелочь, которая многое объясняет: у всех десяти пакетов ровно одна зависимость — @dzhechkov/core, и ни один не объявляет bin. Адаптер не самостоятельная утилита; он всегда вызывается через dz init --target.

4. Три класса адаптеров — и как их измерить

Побайтовые, трансформирующие, уплощающие: классификация из исходников, а не из названий.

Ключевая мысль: класс адаптера определяется измерением исходников, а не именем

Костя попробовал угадать класс по названию и ошибся на первом же пакете. Смотри сам: adapter-openclaude звучит как «ещё один вариант Claude» — а по коду это тонкая обёртка над emitSkillTree с корнем .openclaude/skills, то есть чистый побайтовый перенос. Класс адаптера измеряется по исходникам, а не выводится из имени.

Измерение дало ровно три класса:

  1. Побайтовые адаптеры дерева навыков — пять штук: claude, codex, opencode, hermes, openclaude. Все пять — тонкие обёртки над одним движком emitSkillTree из core; отличие ровно одно — константа корневого каталога.
  2. Трансформирующие — два: cursor, windsurf. Файл на навык, но в СВОЁМ формате шапки.
  3. Уплощающие и потерянные — три: copilot, gemini, agents-md. Структура, которой у цели нет, выбрасывается.

Как измерять самому, по шагам: прочитать description в package.json; открыть src/index.ts; посмотреть, ЧТО импортируется из core (emitSkillTree — побайтовый; renderCursorMdc или renderGeminiMdSection — не побайтовый); посмотреть путь эмита; прочитать текст строки-предупреждения lossy, если она есть. Пять шагов, и класс назван по коду.

Ещё один измеренный факт, который выглядит подсказкой: версии разложились по классам — 0.2.x у побайтовой пятёрки, 0.1.x у остальных. Честная оговорка: это вывод из номеров версий, а не из журнала изменений — считай это гипотезой, а не доказательством общей ревизии API.

Все десять на npm: adapter-claude, adapter-codex, adapter-opencode, adapter-hermes, adapter-openclaude, adapter-cursor, adapter-windsurf, adapter-copilot, adapter-gemini, adapter-agents-md.

5. Побайтовая пятёрка: один движок, пять корней

emitSkillTree и доказательство, что SKILL.md доезжает без единого изменённого байта.

Ключевая мысль: побайтовый перенос: SKILL.md доезжает без единого изменённого байта

Костя ожидал пять разных реализаций. Их пять — но код в них почти одинаковый, и это по замыслу.

Все пять зовут один движок emitSkillTree из core. Разница между адаптерами — одна константа, корневой каталог:

  • claude.claude/skills
  • codex.agents/skills
  • opencode.opencode/skills
  • hermes.hermes/skills
  • openclaude.openclaude/skills

Побайтовый перенос (lossless) означает буквально это: содержимое SKILL.md — текст документа дословно, поэтому эмиссия ничего не теряет. Меняется только место файла, не его байты.

ИЗМЕРЕНО прямо для этого курса. Канонический навык hello-adapters развёрнут командой dz init --target claude-code; затем:

$ diff canon/hello-adapters/SKILL.md proj-claude/.claude/skills/hello-adapters/SKILL.md
$ echo $?
0
$ sha256sum canon/.../SKILL.md proj-claude/.../SKILL.md
3c8f59dd00e6d737552eb01e28e04c7567af1617dfa15112e4fe6fce561f7c82  (оба файла)

Пустой diff и один и тот же sha256 — это и есть побайтовость, предъявленная, а не обещанная.

Что отсюда следует практически: круговой рейс. Скомпилировал навык в цель, разобрал обратно — получил исходник. Активы (scripts/, references/) переносятся тоже, а не остаются дома. И движок защищается на входе: небезопасный идентификатор навыка или путь актива с .. — ошибка, а не запись мимо каталога.

6. Трансформирующие цели: Cursor и Windsurf

Своя шапка вместо канонической, файл на навык — и почему расширение решает всё.

Ключевая мысль: трансформирующая цель заменяет каноническую шапку своей

Фронтендер пожаловался: «правило не подхватывается». Костя полез разбираться и нашёл ответ в одной строке комментария адаптера.

Cursor читает проектные правила из .cursor/rules/один файл на правило, и расширение обязано быть .mdc: обычный .md в этом каталоге Cursor игнорирует. Адаптер поэтому пишет ровно .cursor/rules/<id>.mdc.

Трансформирующая цель — это цель, у которой своя шапка, и адаптер заменяет нашу целиком. Каноническая шапка навыка несёт около 26 проектных ключей; Cursor понимает три: description, необязательный globs и alwaysApply. Всё остальное не переезжает — и это решение, а не недоделка: оба адаптера прямо говорят «не побайтовый» и исключены из набора проверок побайтового равенства.

ИЗМЕРЕНО. Тот же навык, что в предыдущей секции, скомпилирован в Cursor. Тело — слово в слово то же. Шапка — другая:

---
description: "Демонстрационный навык для курса про адаптеры …"
alwaysApply: false
---

alwaysApply: false — это не «выключено». Это правило по запросу агента: оно подтягивается, когда модель сочтёт его уместным, вместо того чтобы вливаться в каждый ход. Экономия контекста прямо здесь.

Windsurf — та же идея с тремя отличиями: каталог .windsurf/rules/, обычный .md (не .mdc), и ключ активации называется trigger (always_on | manual | model_decision | glob) вместо alwaysApply. Адаптер эмитит trigger: model_decision — тот же смысл «по запросу агента».

И оба verify проверяют ровно несущее: у Cursor — что description стоит в ВЕДУЩЕЙ шапке, а не где-то в теле; у Windsurf — что есть trigger, потому что без него редактор просто не знает, когда включать правило.

7. Уплощающие цели: всё в один файл

GEMINI.md и AGENTS.md: что именно исчезает — и почему твои заметки всё-таки выживают.

Ключевая мысль: уплощающая цель сводит все навыки в один файл

Костя развернул два навыка в Gemini и пересчитал файлы. Их оказалось не два. Один.

ИЗМЕРЕНО, вывод дословно: dz init --target gemini: 2 skill(s), 1 file(s) written, 0 skipped, а find по проекту вернул ровно одну строку — GEMINI.md.

Уплощающая цель (flattening) — это цель, у которой нет ни каталога навыков, ни шапки: всё сводится в ОДИН файл в корне проекта. GEMINI.md читают Gemini CLI и Code Assist; AGENTS.md — договорённость, которую понимают около пятнадцати инструментов (Cursor, Zed, Warp, Aider, goose, RooCode, Junie, Devin, Windsurf и другие).

Что теряется — поимённо, из текста самого предупреждения адаптера:

  • YAML-шапка навыка;
  • постепенное раскрытие (progressive disclosure) — режим, при котором агент читает подробности навыка только когда к нему обратился; в плоском файле всё лежит открытым всегда;
  • границы между навыками как отдельными файлами;
  • активы scripts/ и прочие — они не переносятся вовсе.

А теперь неожиданное. Костя дописал в GEMINI.md руками свои заметки после управляемого блока и запустил dz init ещё раз. Заметки остались на месте. Управляемая часть обёрнута маркерами <!-- dz:skills BEGIN (managed by dz — do not edit) --><!-- dz:skills END -->, и стратегия записи — слияние, а не перезапись: dz меняет только то, что между маркерами.

Ещё одна тонкость для тех, кто полезет в код: compile уплощающего адаптера отдаёт СЕКЦИЮ одного навыка по пути GEMINI.md. Сборка всех секций и слияние с твоим файлом происходят слоем выше — адаптер один навык видит, а файл целиком собирает не он.

8. Практика: один навык в два редактора и diff

Полный проход руками: развернуть один и тот же навык в Claude Code и Cursor и сравнить.

Ключевая мысль: один навык в две цели: diff показывает, чем они отличаются

Это тот проход, после которого Костя перестал задавать вопросы. Повтори его целиком — он занимает минуту.

Шаг 1. Один канонический навык. Каталог canon/hello-adapters/ с файлом SKILL.md: шапка name и description, тело в Markdown.

Шаг 2. Развернуть в две цели.

dz init --target claude-code --skills-dir ./canon --project ./proj-claude
dz init --target cursor      --skills-dir ./canon --project ./proj-cursor

ИЗМЕРЕНО: обе команды напечатали 1 skill(s), 1 file(s) written, 0 skipped.

Шаг 3. Посмотреть раскладку. find по обоим проектам дал две строки:

proj-claude/.claude/skills/hello-adapters/SKILL.md
proj-cursor/.cursor/rules/hello-adapters.mdc

Слева — каталог на навык. Справа — один файл, и расширение другое.

Шаг 4. Сравнить. У Claude Code diff с каноном пустой, sha256 совпадает (3c8f59dd00e6…) — байт в байт. У Cursor тело совпадает слово в слово, а шапка заменена на description + alwaysApply: false.

Вывод словами, чтобы его можно было пересказать: тело инструкции доезжает до обоих редакторов одинаково, а цена цели видна ровно в двух местах — в шапке и в раскладке файлов. Именно поэтому diff здесь не формальность: это самый дешёвый способ увидеть, чем ты заплатил за совместимость.

9. Copilot: потерянный, но пофайловый

Странный случай: файл на каждый навык — и при этом самая заметная потеря.

Ключевая мысль: Copilot теряет адресность: инструкция на навык, но всегда включённая

Костя ждал, что Copilot окажется похож на Cursor. Оказалось — нет, и разница поучительная.

GitHub Copilot не сканирует каталог навыков вообще. У него нет такого механизма. Зато он сам читает инструкции репозитория из .github/instructions/*.instructions.md. Поэтому адаптер пишет туда — файл на каждый навык, <id>.instructions.md.

Формально Copilot в классе потерянных — вместе с gemini и agents-md. Но, в отличие от них, у него файл ОТДЕЛЬНЫЙ на каждый навык. Тогда в чём же потеря? Вот в чём, поимённо:

  1. applyTo: "" — инструкция всегда включена** для всех файлов; постепенного раскрытия нет;
  2. команды вызова навыка у Copilot нет — навык нельзя позвать по имени;
  3. scripts/ кладутся в отдельный корень .github/copilot-skills/<id>/ как справочные: Copilot их не исполняет.

Открытый вопрос, на который стоит потратить минуту: «потерянный» и «трансформирующий» — это не про РАЗМЕР потери, а про то, ЧТО именно исчезает. Cursor теряет шапку, но сохраняет адресность: правило подтягивается по решению агента. Copilot сохраняет отдельный файл, но теряет адресность: инструкция висит всегда. Какая потеря дороже?

Честный ответ Кости: зависит от числа навыков. На трёх навыках всегда включённая инструкция — мелочь. На тридцати — это тридцать инструкций в каждом ходе, и цена уже не мелочь.

10. Потеря всплывает предупреждением — или отказом

Правило контракта: молчаливой потери не бывает, а strict превращает предупреждение в отказ.

Ключевая мысль: потеря всплывает предупреждением, а под strict — отказом

Костя спросил ровно то, что должен был спросить: «а как я УЗНАЮ, что цель что-то потеряла?»

Ответ записан в самом контракте Adapter: компиляция может быть с потерями — но потеря обязана всплыть предупреждением, никогда молча. Это не пожелание в документации, это то, как написан каждый непобайтовый адаптер.

Механика одинаковая у всех:

  1. адаптер собирает строку lossy с ИМЕНЕМ навыка и перечислением того, что исчезает;
  2. если ctx.strict !== true — строка едет в warnings результата;
  3. если ctx.strict === true — компиляция ОТКАЗЫВАЕТСЯ: refusing lossy compile under strict mode.

Строгий режим — это выключатель «лучше не собрать, чем собрать тихо неправильно». Он нужен там, где потеря недопустима: в конвейере сборки, а не на твоём ноутбуке.

Второе место, где это видно, — verify. Он не просто проверяет структуру: он ПЕРЕНОСИТ предупреждения дальше — const warnings = [...emit.warnings]. Комментарий в адаптере объясняет зачем прямым текстом: чтобы dz verify --target cursor никогда не отчитался «чисто», не сказав про потерю.

Сноска здесь не украшение (и это общее правило хорошего инструмента): предупреждение — часть контракта, а не примечание внизу экрана. Проверь себя прямо сейчас: если ты не можешь назвать, что теряет твоя цель, — ты цель не выбрал, ты взял первую попавшуюся.

11. adapter-claude: эталон и планировщик спутников

Единственный адаптер с четырьмя файлами: почему он и база сравнения, и планировщик MCP.

Ключевая мысль: adapter-claude — эталон побайтовости и планировщик спутниковой конфигурации

Костя пробежал find по исходникам всех десяти пакетов и заметил аномалию: у девяти адаптеров ровно один файл src/index.ts. У adapter-claude их четыре — index.ts, compile.ts, verify.ts и integrations.ts. Значит, он делает что-то ещё.

Роль первая — эталон. Формат Claude Code и есть канонический формат agentskills.io, поэтому именно этот адаптер служит базой побайтового сравнения для остальных. Когда где-то говорится «исключён из набора проверок побайтового равенства» — равенство измеряется относительно него.

Роль вторая — спутниковая конфигурация. claudeIntegrationAdapter планирует то, что живёт рядом с навыками: MCP-серверы и хуки. Он тоже ничего не пишет — он возвращает ПЛАН из двух частей:

  • фрагменты-носители: например, файл .mcp.json, корневой ключ mcpServers, область project;
  • отказы — с кодом причины и подсказкой, что сделать.

И вот главное, ради чего эта секция вообще есть: отказ здесь ИМЕННОЙ, из закрытого словаря. INTENT_NOT_EXPRESSIBLE — «квитанция доказывает только локальную команду stdio, без env и url», то есть намерение нельзя выразить честно. NO_ACTIVATION_RECEIPT — «для хуков нужна канарейка с одноразовым значением и отрицательный контроль», то есть нет доказательства, что хук реально сработал. Словарь причин закрыт и живёт в core/src/adapter.ts — придумать новую причину на месте нельзя.

ИЗМЕРЕНО на реальном прогоне: dz init без явного согласия печатает MCP: NOT-REQUESTED и Hooks: NOT-REQUESTED. Спутниковая конфигурация не приезжает сама — её надо запросить, и согласие на манифест интеграций требует точной контрольной суммы.

12. dz parity: честная карта возможностей и целей

Двенадцать возможностей на десять целей, вычисленные из модели, а не написанные руками.

Ключевая мысль: паритет — вычисленная карта: что работает на цели и в какой форме

Костя дошёл до вопроса, который рано или поздно задают все: «ладно, навыки доехали — а остальной харнес?» Для этого есть одна команда.

dz parity

Она печатает таблицу: двенадцать возможностей харнеса по строкам, десять целей по столбцам. Ключевое свойство: таблица не написана руками — она ВЫЧИСЛЕНА из модели возможностей (harness-core/src/parity.ts). Рукописная копия такой таблицы была бы вторым источником расхождения: код меняется, документ отстаёт, и читатель верит документу.

Три знака в клетках:

  • — полностью: возможность работает сама;
  • — вручную: возможность ДОСТУПНА, но ведёшь её ты;
  • — недоступно на этой цели.

— не «сломано». Это самая частая ошибка чтения. ИЗМЕРЕНО: у Cursor конвейер feature-adr стоит как — «интерактивный навык, ведёшь руками», а не «не работает».

ИЗМЕРЕНО из живого прогона: у всех десяти целей на строках «dz CLI (all commands)» и «Skill packs (compiled per target)» — базовая совместимость полная. Живая статусная панель только у claude-code, у остальных . MCP-память: у claude-code, у codex, у остальных восьми.

Читается это как компромисс, а не как рейтинг: чем ближе цель к родному формату, тем больше возможностей едет автоматом; чем дальше — тем больше остаётся на твоих руках.

13. Где карта честно неполна

Пустая клетка значит «не измерено», а знак вопроса — «улика устарела».

Ключевая мысль: непроверенное не помечается поддержанным: пустая клетка значит «не измерено»

Это секция, ради которой Костя и просил курс. Карта паритета полезна ровно настолько, насколько честно она признаётся в незнании.

Контракт честности записан в самом модуле: флаг возможности утверждает только то, что ПРОВЕРЕНО, и у каждого флага в коде рядом стоит источник. Неизвестная поддержка НЕ отмечается. Обоснование там же: ложно обещанная возможность хуже, чем консервативно отмеченная как отсутствующая.

Отсюда следствие, которое надо читать правильно. У семи целей — opencode, hermes, openclaude, copilot, cursor, gemini, windsurf — в модели ровно две возможности: shell и skills, с комментарием «консервативная первая версия: эмиссия навыков подтверждена адаптерами, более богатые среды не доказаны». Это надо читать как «не измерено», а не как «нет».

И есть четвёртый знак, которого нет в общей таблице, — ?. ИЗМЕРЕНО:

$ dz parity --target codex
? Self-learning: automatic apply-leg  … INCONCLUSIVE: stale evidence for hooks-prompt
⚠ hooks-prompt: улика записана на codex-cli 0.147.0, свежайшая запись — 0.148.0

Что здесь произошло: возможность когда-то была ДОКАЗАНА живой пробой, но проба относится к старой версии инструмента, а с тех пор появилась новая. Модель не стала утверждать по инерции — она понизила клетку до «неубедительно», пока не перепроверят. Важная тонкость: inconclusive — это уровень ОТЧЁТА, а не модели. Модель по-прежнему знает, что было доказано; отчёт отказывается это предъявлять как действующее.

Проверь себя одним вопросом: когда ты в следующий раз увидишь пустую клетку в чьей-нибудь таблице совместимости — ты сможешь сказать, это «не умеет» или «не проверяли»? В большинстве таблиц ответа нет. Здесь он есть, и в этом вся ценность.

14. Твой выбор: какой потерей ты платишь

Финальная развилка: подобрать цель под свою команду и назвать цену вслух.

Ключевая мысль: выбор цели — решение о том, какой потерей ты платишь

Теперь роль твоя, а не Костина. Костя уже прошёл этот выбор и вот к чему пришёл.

Правило одной фразой: цель выбирают не по названию редактора, а по тому, какую потерю ты готов принять. Три ответа, три цены:

  1. Редактор понимает формат agentskills.io (Claude Code, Codex, OpenCode, Hermes, OpenClaude) — бери побайтовую цель. Цена: ноль. Ограничение: список редакторов короткий.
  2. Редактор имеет свой формат правил (Cursor, Windsurf) — бери трансформирующую. Цена: каноническая шапка и активы scripts/. Приобретение: правило по запросу агента, экономия контекста.
  3. У редактора вообще нет понятия навыка (Copilot, Gemini CLI, всё семейство AGENTS.md) — бери уплощающую. Цена: шапка, постепенное раскрытие, границы навыков, активы. Приобретение: работает почти везде.

Две проверки перед тем, как объявить выбор сделанным:

  • запусти dz parity --target <имя> и прочитай, что уедет автоматом, а что останется на руках;
  • разверни ОДИН навык и сделай diff — секция 8 занимает минуту и отвечает точнее любого README.

И последнее, что стоит унести из курса целиком. Слой адаптеров ценен не тем, что «работает везде» — так не бывает. Он ценен тем, что каждая потеря названа по имени, всплывает предупреждением и может быть запрещена строгим режимом. Инструмент, который честно говорит, чем ты платишь, лучше инструмента, который обещает бесплатно.

Частые вопросы

Я поставил навыки в Cursor, а шапка выглядит совсем иначе — это баг?

Нет, это заявленное поведение трансформирующей цели. Cursor понимает три ключа (description, необязательный globs, alwaysApply), поэтому каноническая шапка заменяется целиком. Тело навыка при этом переезжает слово в слово — проверь diff тел, он будет пустым.

Почему --target claude работает, если в списке написано claude-code?

Через таблицу псевдонимов, и dz об этом печатает: «dz init: --target "claude" → claude-code (alias)». Псевдонимы — данные, не логика: claude и cc ведут на claude-code, agents — на agents-md, gpt и openai — на codex.

Я дописал свои заметки в AGENTS.md — их затрёт следующий dz init?

Нет, если они за пределами управляемого блока. dz меняет только то, что между маркерами dz:skills BEGIN и dz:skills END; стратегия записи — слияние, а не перезапись. Измерено повторным запуском: дописанные вручную строки остались на месте.

Как узнать, что именно теряет моя цель, не читая исходники?

Потеря обязана всплыть предупреждением — это записано в контракте адаптера, и verify переносит предупреждения дальше. Если потеря вообще недопустима, включай строгий режим: под ним адаптер откажется компилировать с сообщением refusing lossy compile under strict mode.

В dz parity у моей цели почти пустая колонка. Значит, она мало что умеет?

Не обязательно. Контракт честности запрещает отмечать непроверенное как поддержанное, поэтому пустая клетка значит «не измерено», а не «не умеет». Отдельно есть знак ?: он означает, что улика устарела — например, записана на codex-cli 0.147.0, а свежайшая запись 0.148.0.

Можно ли из скомпилированного файла восстановить исходный навык?

У побайтовых целей — да: SKILL.md совпадает с каноном байт в байт, что проверяется diff и sha256sum. У трансформирующих и уплощающих — нет: каноническая шапка заменена или выброшена. Именно поэтому канонический каталог навыков остаётся единственным источником истины.

Адаптер — это отдельная утилита, которую можно запустить?

Нет. Измерено по package.json: ни один из десяти адаптеров не объявляет bin, и у каждого ровно одна зависимость — @dzhechkov/core. Адаптеры всегда вызываются через dz init --target <имя>.