Начни здесь

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

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

Знакомься: Костя

Костя — тимлид небольшой команды, в которой каждый сидит в своём редакторе: он сам в Claude Code, фронтендер в Cursor, дата-инженер в Gemini CLI, ревьюер в Copilot. Двенадцать навыков написаны один раз — и Костя идёт на шаг впереди тебя: сначала ошибается сам, потом показывает измерение.

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

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 и cc → claude-code, agents → agents-md, gpt и openai → codex.

Опечатка не молчит. ИЗМЕРЕНО: --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 <имя>.

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

Лицензии шрифтов

Onest

Copyright 2021 The Onest Project Authors (https://github.com/googlefonts/onest)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded, 
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

JetBrainsMono

Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded, 
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.