# CocoaSkills RFC 0007 - Зависимости навыков

Статус: черновик
Дата: 2026-07-02
Автор: Ivan Oparin
Цель: v0.9.0
Английская версия, источник правды: [v0.9-design.md](v0.9-design.md)

Навык может требовать другие навыки. Этот RFC определяет форму требования в манифесте, разрешение замыкания зависимостей, семантику установки и границу безопасности. Все код-блоки идентичны английской версии.

## 1. Обзор

- `Skillfile.json` сохраняет schema v1 и перечисляет навыки, которые проект устанавливает напрямую.
- `csk-skill.json` schema v4 добавляет `dependencies.skills`. Каждая запись называет навык-провайдер и несёт его git URL, точный ref и режим активации. Запись самодостаточна: требование содержит всё необходимое для загрузки провайдера.
- Три режима активации определяют, что зависимость даёт потребителю: `full` даёт промпт-контекст и команды, `runtime` даёт команды, `context` даёт промпт-контекст.
- Механизм разрешения раскрывает требования транзитивно. Внутри одного замыкания имя навыка разрешается в один commit и один источник.
- Машинный allowlist источников авторизует каждую загрузку.
- Установщик материализует каждый узел согласно его эффективному режиму, печатает разрешённое замыкание и записывает его в маркеры установки.
- Рабочий процесс это навык, который объявляет зависимости и экспортирует ноль команд. Потребитель устанавливает рабочий процесс одной записью в `Skillfile.json`.

## 2. Мотивирующие случаи

Дизайн опирается на два повторяющихся случая.

Навык-оркестратор ведёт многошаговый процесс. Его SKILL.md делегирует целые шаги навыкам-провайдерам, таким как трекер задач, клиент мониторинга и инструмент ревью: агент читает их инструкции и запускает их команды. Оркестратор публикует этот состав один раз; потребитель устанавливает рабочий процесс одной проектной записью.

Навык-библиотека строится на команде, которую экспортирует другой навык. Скрипты потребителя вызывают исполняемый файл провайдера, бинарь доступен на `PATH`, а использование описано в собственном SKILL.md потребителя. Требование воспроизводимо: csk загружает провайдера и устанавливает команду.

Первый случай активирует навыки целиком. Второй активирует одну команду. Поле режима покрывает оба.

## 3. Манифест требования

Требования живут в `csk-skill.json` schema v4 в блоке `dependencies.skills`.

```jsonc
{
  "schema_version": 4,
  "runtime_roots": ["scripts"],
  "capabilities": { "exec": ["trk", "git"], "network": "none" },
  "commands": {
    "report": { "type": "script", "unix_path": "scripts/report", "win_path": "scripts/report.cmd" }
  },
  "dependencies": {
    "skills": {
      "skill-tracker": {
        "git": "git@gitlab.example.com:skills/skill-tracker.git",
        "ref": { "kind": "tag", "value": "v1.4.2" },
        "mode": "runtime",
        "commands": ["trk"]
      }
    },
    "commands": {
      "git": { "type": "system", "command": "git", "hint": "Install git and retry." }
    }
  }
}
```

Правила:

- `git` и `ref` обязательны. `ref.kind` принимает `tag` или `revision`; значение закрепляет точный релиз. Ветка или диапазон версий в записи требования это ошибка парсинга; диапазоны приходят вместе с semver-контрактом навыков (раздел 10).
- `mode` по умолчанию равен `full`. Необязательный список `commands` применяется к требованиям `runtime` и сужает активацию до названных экспортов. Каждая названная команда обязана существовать у провайдера с `type: script`.
- Системные зависимости сохраняют существующую форму: записи `dependencies.commands` с `type: system` объявляют бинарь, который предоставляет окружение проекта, наличие проверяется через `shutil.which`. Поля манифеста, исполняющие код при установке (`install`, `check`, `post_install`, пробы версий), остаются под запретом.
- Файлы `Skillfile.json` остаются валидными как есть. Прямой навык проекта ведёт себя как требование `full` с корнем в проекте.

Рабочий процесс публикует свой состав тем же механизмом. Навык-оркестратор объявляет своих провайдеров и экспортирует ноль команд:

```jsonc
{
  "schema_version": 4,
  "capabilities": { "exec": "none", "network": "none" },
  "dependencies": {
    "skills": {
      "skill-tracker": { "git": "git@gitlab.example.com:skills/skill-tracker.git", "ref": { "kind": "tag", "value": "v1.4.2" } },
      "skill-monitor": { "git": "git@gitlab.example.com:skills/skill-monitor.git", "ref": { "kind": "tag", "value": "v2.0.1" } },
      "skill-review":  { "git": "git@gitlab.example.com:skills/skill-review.git",  "ref": { "kind": "revision", "value": "8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d" } }
    }
  }
}
```

Потребитель устанавливает рабочий процесс одной записью в неизменном `Skillfile.json`:

```json
{
  "schema_version": 1,
  "project": { "alias": "demo-project" },
  "agents": ["claude_code"],
  "skills": [
    {
      "name": "triage-workflow",
      "git": "git@gitlab.example.com:workflows/triage-workflow.git",
      "tag": "v1.0.0"
    }
  ]
}
```

## 4. Режимы активации

| Режим | Промпт-контекст | Shim-ы команд |
|-------|-----------------|---------------|
| `full` | SKILL.md и references провайдера | все экспортируемые команды |
| `runtime` | нет | экспортируемые команды, при необходимости суженные списком `commands` |
| `context` | SKILL.md и references провайдера | нет |

`full` служит делегированию: агент читает контракт провайдера и запускает его команды. `runtime` служит обвязке: скрипты потребителя вызывают исполняемый файл провайдера, а собственный SKILL.md потребителя описывает поведение, которое он предоставляет. `context` служит провайдерам правил: навыкам конвенций и методологий.

Когда один провайдер требуется несколькими потребителями, эффективная поверхность равна объединению рёбер: ребро `full` даёт `full`; иначе множества runtime-команд объединяются, а ребро `context` добавляет промпт-контекст.

## 5. Разрешение

1. Собрать навыки проекта из `Skillfile.json`.
2. Авторизовать источник каждой предстоящей загрузки по машинному allowlist (раздел 7).
3. Загрузить каждый навык по его точному ref и прочитать его `csk-skill.json`.
4. Рекурсивно раскрыть `dependencies.skills` по непосещённым узлам.
5. Унифицировать по имени: внутри одного замыкания имя навыка разрешается в один commit и один канонический источник. Навык, присутствующий и напрямую, и как требование, унифицируется по тому же правилу, при этом прямая запись вносит ребро `full`. Когда цепочки требований расходятся, механизм разрешения сообщает о конфликте и перечисляет цепочки.
6. Отклонить циклы зависимостей.
7. Упорядочить провайдеров раньше потребителей и передать план установщику.

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

Для разработки `Skillfile.dev.json` подменяет провайдеров локально. Файл лежит рядом со `Skillfile.json`, входит в managed-блок `.gitignore`, который пишет `csk init`, и остаётся вне версионного контроля. Подмена действует на всё замыкание и принимает локальный путь или git-источник с любым видом ref, включая ветки:

```json
{
  "substitutions": {
    "skill-tracker": { "path": "../skill-tracker" },
    "skill-monitor": { "git": "git@gitlab.example.com:skills/skill-monitor.git", "ref": { "kind": "branch", "value": "fix/api" } }
  }
}
```

`csk install` и `csk status` печатают каждую активную подмену. Git-подмена проходит allowlist источников (раздел 7); подмена путём читает локальный чекаут. Строгий аудит завершается ошибкой, пока подмены активны. Коммитимые манифесты остаются единственной декларацией графа.

## 6. Семантика установки

Установщик материализует каждый узел один раз, согласно его эффективному режиму, поверх существующих слоёв: промпт-контекст копируется в `.agents/skills/<name>/` и зеркалируется в адаптеры агентов; runtime roots копируются в runtime store; shim-ы команд попадают в `.agents/bin`.

- Активные shim-ы подчиняются правилу уникальности: внутри замыкания одно имя команды соответствует одному провайдеру.
- `csk install` печатает разрешённое замыкание и по каждому узлу: какие команды попадают в `.agents/bin` и материализуется ли промпт-контекст.
- Маркер установки (`.csk-install.json`) каждого узла расширяет существующую запись content-hash разрешённым commit, каноническим источником, эффективным режимом и списком требующих. Маркеры делают установленное замыкание проверяемым офлайн.
- Замыкания проектов разрешаются локально в проекте. Глобальные навыки служат интерактивному использованию; замыкание проекта загружает собственную копию каждого узла.

## 7. Граница безопасности

Решения об авторизации живут в машинной конфигурации. `~/.cocoaskills/config.json` принимает список `allowed_sources` из канонических префиксов URL; механизм разрешения проверяет каждый источник, прямой и транзитивный, до первой сетевой операции с этим источником. Пустой список разрешает все источники и подходит личным машинам; организации закрепляют список за своим хостингом.

```json
{
  "allowed_sources": [
    "gitlab.example.com/skills/",
    "gitlab.example.com/workflows/"
  ]
}
```

Каноническая форма: host в нижнем регистре, транспорт и суффикс `.git` удалены, путь сохранён. SSH- и HTTPS-адреса одного репозитория нормализуются в одну идентичность. Криптографическая подпись этой конфигурации относится к будущей работе (раздел 10).

Существующие защиты применяются к каждому узлу замыкания: усиленное клонирование (`GIT_ALLOW_PROTOCOL`, разделение аргументов), content-hash снимков, конвейер аудита с проверками capabilities и trust pin, а также `--strict-tags`.

## 8. Каталог отказов

Разрешение и установка останавливаются с конкретной ошибкой, когда:

- две цепочки требований закрепляют одно имя навыка за разными commit;
- две цепочки требований берут одно имя навыка из разных источников;
- два активных провайдера экспортируют одно имя команды;
- граф зависимостей содержит цикл;
- список `commands` называет экспорт, которого у провайдера нет;
- источник выходит за пределы allowlist;
- запись требования несёт ссылку на ветку или диапазон версий;
- объявленная системная команда отсутствует в `PATH`.

## 9. Совместимость и миграция

- Существующие проекты устанавливаются без изменений. Файлы `Skillfile.json` schema v1 остаются валидными, а навыки с манифестами schema v1-v3 действуют как листья замыкания.
- Schema v4 впервые объявляет требования навык-к-навыку. Старые манифесты с dependency-подсказками принимаются для совместимости, а csk сообщает migration warning, когда может их распознать.
- Репозиторий рабочего процесса публикует свой состав как навык: SKILL.md плюс `csk-skill.json`, чей блок `dependencies.skills` называет навыки-провайдеры. Потребители устанавливают этот workflow-навык одной проектной записью.
- Репозиторий рабочего процесса может держать `Skillfile.json` для чекаута разработчика. Публикуемый состав живёт в `csk-skill.json`.

## 10. Будущая работа

- Диапазоны версий, semver-контракт навыков и файл блокировки. Диапазоны делают результат разрешения зависимым от доступных тегов, и файл блокировки приходит в том же RFC, который их вводит.
- Коммитимый механизм переопределений, пересматриваемый вместе с диапазонами версий; переопределение тогда удовлетворяет каждому объявленному ограничению.
- Подписанная машинная конфигурация: при включённой строгой проверке csk требует криптографическую подпись конфигурации безопасности (раздел 7) и проверяет её по цепочке доверия; конфигурация, не прошедшая проверку, отклоняется.
- Требования MCP-серверов как поверхность зависимостей.
- Частичный контекст: импорт выбранных references провайдера вместо целого SKILL.md.
- Реэкспорт команд и неймспейсы.
