Справочник CLI
Все команды предоставляет бинарник aiman.
Формат вывода нестабилен до версии 1.0. Человекочитаемый вывод команд — не стабильный API. Для автоматизации ожидайте будущий флаг
--json. Все изменения формата помечаютсяbreaking:в changelog.
Глобальные флаги
| Флаг | Описание |
|---|---|
--help | Показать help для команды |
--version | Показать версию бинарника |
aiman init
aiman init <repo-url> [--path <dir>]Подключает репозиторий инвентаря.
Аргументы:
<repo-url>— URL Git-репозитория инвентаря.
Флаги:
--path <dir>— локальный путь для clone или регистрации репозитория.
Поведение:
- клонирует или регистрирует репозиторий инвентаря;
- создаёт структуру для пустого репозитория;
- создаёт локальный
aim.local.yaml; - записывает активный репозиторий в глобальный конфиг;
- классифицирует существующие файлы как adoptable, existing AIM или conflicting.
aiman switch
aiman switch <path>Переключает активный репозиторий инвентаря без clone.
Используйте, если у вас несколько локальных репозиториев инвентаря или нужно запустить команды из другой директории.
switch безусловно снимает активный пин (aiman apply --loadout <name> --pin, см. Пин активного loadout) — даже если в новом репозитории есть loadout с таким же именем. Если после переключения нужен пин, установите его заново: aiman apply --loadout <name> --pin.
aiman apply
aiman apply [--dry-run] [--loadout <name> [--pin]] [--default] [--unpin]Применяет текущий локальный инвентарь в AI-среды без Git-операций.
Флаги:
--dry-run— показать sha256-дельту между локальным инвентарём и установленными AI-средами без записи файлов.--loadout <name>— применить именованный loadout декларативно: среды приводятся ровно к его набору в пределах AIM-managed namespace. См.aiman apply --loadout.--pin— требует--loadout <name>; после успешного применения сохраняет этот loadout как активный пин, чтобыaiman syncв дальнейшем применял именно его, а не полный инвентарь. См. Пин активного loadout.--default— применить весь инвентарь (как обычныйapplyбез флагов) и снять активный пин, если он был установлен.--unpin— снять активный пин, ничего не применяя. Не читает инвентарь и не трогает AI-среды; должен использоваться отдельно от--loadout,--pinи--default. С--dry-runтолько показывает, что было бы снято.
apply не делает commit, не выполняет push/fetch и не обновляет published_hash или synced_hash.
Без --loadout команда работает аддитивно: устанавливает и обновляет элементы инвентаря (A/M), но никогда ничего не удаляет из сред — даже если в репозитории есть loadouts/.
Пример вывода apply
При успехе apply выводит строку результата. Если в какой-либо AI-среде есть изменения, после строки результата печатается блок состава изменений с отступом в два пробела и маркерами A (новый артефакт) и M (изменённый):
applied: 21 skills, 1 MCP server → 3 environments
A skills/refactor-helper.md (new in all environments)
M skills/commit-message.md (updated in claude-code, cursor)Счётчики в строке результата (21 skills, 1 MCP server) — это объём операции: сколько всего применено. Блок ниже — состав изменений: что именно добавлено или перезаписано. Это разные числа: 21 skills означает 21 навык всего, а не 21 изменение.
Если в средах ничего не изменилось, печатается только строка результата без блока:
applied: 21 skills, 1 MCP server → 3 environmentsПример вывода apply --dry-run
Инвентарь совпадает с установленными AI-средами:
[dry-run] nothing to apply — environments match local inventoryЕсть изменения:
[dry-run] would apply 2 changes to 2 environments (claude-code, cursor):
A skills/new-skill.md (new in all environments)
M skills/existing.md (differs in cursor)
[dry-run] MCP context7 → claude-code, cursorДля MCP-серверов apply --dry-run показывает только целевые AI-среды и не вычисляет дельту: AIM не сравнивает установленную в среде MCP-конфигурацию с дескриптором инвентаря. См. Известное ограничение: дельта MCP.
Если список изменений превышает 20 строк, он усекается:
A skills/skill-1.md
A skills/skill-2.md
… and 15 moreИзвестное ограничение: дельта MCP-конфигов
Для навыков AIM вычисляет дельту: сравнивает содержимое инвентаря с установленным в каждой AI-среде файлом и помечает изменения маркерами A/M.
Для MCP-серверов дельта пока не вычисляется. AI-среды пишут MCP в разделяемые конфиги (~/.claude.json, mcp.json, config.toml), и сравнение установленного фрагмента с дескриптором требует парсинга и нормализации этих конфигов — это отложено. Поэтому в выводе MCP-строки показывают только целевые среды, без маркера A/M.
Отсутствие маркера у MCP-сервера не означает, что он не меняется. Оно означает, что AIM не проверяет его состояние в средах. Для навыков это утверждение проверено дельтой, для MCP — нет.
aiman apply --loadout <name>
aiman apply --loadout <name> [--dry-run]Применяет именованный loadout — подмножество инвентаря, описанное в loadouts/<name>.yaml, — декларативно: каждая AI-среда приводится ровно к набору loadout в пределах AIM-managed namespace.
AIM-managed namespace — всё, что существует в инвентаре как skills/<name> или mcp/<name>. Для каждого элемента действует одна из трёх веток:
| Элемент | Действие |
|---|---|
входит в loadout и допустим в этой среде по targets (loadout-level и item-level) | установить / обновить |
| есть в инвентаре, но не входит в желаемый набор этой среды, и присутствует в ней | удалить из среды |
| не существует в инвентаре (создан вручную или другим инструментом) | не трогать |
Это верно и для навыков, и для MCP-серверов: желаемый набор считается per-env, а targets каждого элемента (item-level) сужает его симметрично для обоих типов.
Удаление элементов вне loadout — поведение по умолчанию, а не opt-in-флаг. Граница namespace гарантирует: AIM удаляет только то, что считает своим. Файлы вне инвентаря не затрагиваются никогда.
Разрешение имени. <name> разрешается в таком порядке: точное имя файла loadouts/<name>.yaml, затем нормализованное имя (пробелы → дефисы, нижний регистр), затем loadout, чьё поле name после нормализации совпадает с запрошенным. Поэтому aiman apply --loadout "Documentation Work" находит loadouts/documentation-work.yaml.
targets. Loadout-уровневый targets ограничивает допустимые среды применения: среды вне списка не входят в план и не затрагиваются. Для каждого элемента (навыка и MCP-сервера) дополнительно действует item-level targets — элемент применяется в среду только при пересечении обоих ограничений. У MCP Item item-level targets обязателен; у Skill Item опционален — отсутствие или пустой список на item-level не сужает пересечение, элемент проходит по нему в любую среду, допустимую на loadout-level.
Ограничения двух уровней действуют по-разному. Среда, отсечённая loadout-уровневым targets, полностью выпадает из плана. Среда, допустимая для loadout, но не перечисленная в item-level targets элемента, остаётся в плане — и этот навык или MCP-сервер будет из неё удалён, если он там установлен: для этой среды он не входит в желаемый набор. Это правило действует только на этом declarative-пути (apply --loadout, pinned sync); обычные apply/sync ничего не удаляют. Подробнее — в формате инвентаря.
Пример вывода apply --loadout
Строка результата называет loadout, счётчики — объём операции: сколько элементов loadout применено, а не сколько изменений произошло. Блок состава использует три маркера: A (установлен), M (обновлён), D (удалён из среды):
applied loadout "Documentation Work": 2 skills, 1 MCP server → 1 environment
A skills/create-spec.md (new in all environments)
D skills/review-code.md (removed from all environments)
M skills/wpage.md (updated in all environments)
A mcp/context7.yaml (new in all environments)Здесь loadout состоит из двух навыков и одного MCP-сервера (отсюда 2 skills, 1 MCP server), а строк в блоке четыре: три изменения по навыкам, включая удаление review-code — навыка инвентаря вне loadout, — и установка MCP-сервера.
Строки блока отсортированы: сначала навыки по имени, затем MCP-серверы по имени. Пометка all environments означает «все среды плана» — то есть все обнаруженные среды, допустимые по targets loadout. Если действие затрагивает не все из них, вместо неё перечисляются имена сред через запятую.
Категория D существует только на loadout-пути. Обычный apply остаётся аддитивным.
Если среды уже совпадают с loadout, печатается только строка результата без блока.
Если элемент loadout ссылается на элемент инвентаря, которого больше нет или который сейчас невалиден, элемент пропускается с предупреждением — он не устанавливается и не удаляется:
warning: loadout "dev": no valid inventory item for skill:ghost (skipped)Пример вывода apply --loadout --dry-run
--dry-run показывает полный план A/M/D без записи в среды и конфиги:
[dry-run] would apply loadout "Documentation Work" — 4 changes to 1 environment (claude-code):
A skills/create-spec.md (new in all environments)
D skills/review-code.md (would remove from all environments)
M skills/wpage.md (differs in all environments)
A mcp/context7.yaml (new in all environments)Среды уже совпадают с loadout:
[dry-run] nothing to apply — environments match loadout "Documentation Work"Перед первым применением loadout всегда запускайте --dry-run: строки D показывают, что именно будет удалено (см. ограничения).
Ошибки apply --loadout
Loadout не найден (в loadouts/ нет ни файла, ни поля name с таким именем):
hint: available loadouts: dev, docs
error: loadout "ghost" not found in loadouts/Подсказка со списком печатается, если валидных loadout от одного до пяти: при их отсутствии подсказывать нечего, при большем числе список бесполезен. В подсказке перечисляются значения поля name, а не имена файлов.
Loadout найден, но невалиден — apply останавливается на первой ошибке:
error: loadout "empty": items: cannot be emptyПолный список ошибок по всем loadout-файлам сразу выдаёт aiman push.
Пин активного loadout: --pin, --default, --unpin
aiman apply --loadout <name> --pin
aiman apply --default
aiman apply --unpinПин — это сохранённое состояние, а не разовое действие: он живёт в глобальном конфиге пользователя (~/.config/aim/config.yaml, поле loadout — см. Справочник конфигурации) и переживает перезапуск CLI и обновления инвентаря. Пока пин установлен, aiman sync применяет именно этот loadout вместо полного инвентаря — так вы можете подтягивать обновления из remote, оставаясь в узком наборе. Подробнее о разнице между разовым apply --loadout <name> и пином — в Концепциях, сценарий использования — в Рабочих циклах.
aiman apply --loadout documentation-work --pin # применить и закрепить как активный пин
aiman apply --default # вернуться к полному инвентарю, снять пин
aiman apply --unpin # снять пин, ничего не применяяПин сохраняется только при успешном применении. С --dry-run план --loadout <name> --pin печатается как обычно, но пин не сохраняется: dry-run не имеет побочных эффектов ни в средах, ни в конфиге. Это правило распространяется на все три флага — --default --dry-run и --unpin --dry-run тоже только показывают, что произошло бы, и оставляют пин на месте:
[dry-run] would unpin loadout "documentation-work" — sync would go back to applying the full inventoryЕсли пина нет:
[dry-run] nothing to unpin — no loadout is pinned--default — единственный способ одним действием вернуться к полному инвентарю и снять пин. Строка "Default" никогда не записывается как значение пина: отсутствие пина и режим Default неразличимы на уровне конфига.
Конфликты флагов apply
Эти ошибки проверяются до чтения инвентаря и до любых изменений на диске:
| Комбинация | Ошибка |
|---|---|
--pin без --loadout | error: --pin requires --loadout <name> |
--default + --loadout | error: --default and --loadout are mutually exclusive |
--default + --pin | error: --pin is redundant with --default |
--unpin вместе с --loadout, --pin или --default | error: --unpin does not apply — combine only alone |
aiman push
aiman push [--dry-run]Валидирует инвентарь, создаёт commit и отправляет изменения в remote.
Флаги:
--dry-run— показать план публикации без commit/push.
push блокируется, если remote новее локального состояния или есть небезопасное состояние Git.
Валидация frontmatter: если поле frontmatter (кроме тела файла) содержит ошибку, push выводит warning: в stderr и продолжает работу. Ошибки в теле файла (body) остаются блокирующими: push выводит error: и прекращает публикацию.
Валидация loadouts/: если в репозитории есть директория loadouts/, push валидирует каждый loadouts/*.yaml — формат (обязательное name, непустой items, корректные префиксы skill:/mcp:) и ссылочную целостность: каждый skill:<name> должен существовать как skills/<name>.md или skills/<name>/SKILL.md, каждый mcp:<name> — как mcp/<name>.yaml. Все найденные ошибки выводятся сразу, публикация блокируется:
error: loadout "Documentation Work" references unknown skill "missing-skill"
hint: check loadouts/documentation-work.yaml → itemsОтсутствие description и несовпадение имени файла с нормализованным name — предупреждения, они не блокируют публикацию. Репозиторий без loadouts/ валидируется как раньше. Валидация выполняется и в push --dry-run.
После валидации push публикует loadouts/ вместе с skills/, mcp/, aim.yaml и .gitignore — отдельная команда git add не нужна.
Пример вывода push
При успехе push выводит строку результата с хэшем опубликованного commit. Если в инвентаре были изменения, после строки результата печатается блок состава: какие файлы опубликованы (A — новые, M — изменённые):
published: 96e091b · 19 skills, 1 MCP server
M skills/commit-message.md
A mcp/jira.yaml
A loadouts/documentation-work.yamlЕсли изменений нет, печатается только строка результата без блока.
Пример вывода push --dry-run
Рабочее дерево чистое:
[dry-run] nothing to publish — working tree is cleanЕсть изменения для публикации:
[dry-run] would publish managed changes:
M skills/review-code.md
A mcp/jira.yaml
A loadouts/documentation-work.yaml
validated inventory: 5 skills, 2 MCP serversБлок состава изменений строится по skills/, mcp/, loadouts/, aim.yaml и .gitignore. Строка validated inventory считает только элементы инвентаря — навыки и MCP-серверы.
aiman sync
aiman sync [--dry-run] [--force]Получает опубликованное состояние из remote и применяет его в локальные AI-среды.
Флаги:
--dry-run— показать план без записи в репозиторий и AI-среды;--force— удалить неотслеживаемые файлы, конфликтующие с remote, и применить опубликованное состояние. Файлы без конфликтов сохраняются в любом случае.
sync не выполняет merge. Если история разошлась, AIM останавливается и просит восстановить Git вручную.
Неотслеживаемые файлы в skills/, mcp/ и loadouts/ не блокируют sync, если они не конфликтуют по имени с файлами из remote. При конфликте sync останавливается и выводит список проблемных файлов.
Поведение с активным пином
Если в глобальном конфиге закреплён loadout (aiman apply --loadout <name> --pin, см. Пин активного loadout), транспорт sync не меняется: fetch и применение опубликованного состояния к рабочему дереву выполняются как обычно. Меняется только шаг установки в AI-среды: вместо аддитивной установки всего инвентаря (A/M, без D) sync декларативно приводит среды ровно к набору закреплённого loadout — так же, как aiman apply --loadout <name>, включая удаление элементов вне набора (D). Без активного пина поведение sync, описанное ниже в этом разделе, не меняется.
Пин проверяется после обновления рабочего дерева до актуального опубликованного состояния, поэтому переименование или удаление loadout, случившееся в этом же обновлении, будет обнаружено, а не пропущено по устаревшим данным. Если пин указывает на loadout, которого больше нет:
error: pinned loadout "documentation-work" not found in inventoryЭта ошибка блокирует обновление synced_hash: AI-среды остаются в состоянии, применённом до этого запуска sync. Ошибка отличается от loadout "X" not found in loadouts/, которую выдаёт apply --loadout, — тексты различаются намеренно, чтобы источник ошибки было легко отличить в логах и в обработке. См. Справочник ошибок.
В pinned-режиме перед строкой результата всегда печатается applying loadout "X" (pinned), а после — блок состава применения (A/M/D) в обычном выводе, не только в --dry-run. Это отдельный блок от дельты git-транспорта (что изменилось в опубликованном инвентаре относительно предыдущего состояния) — состав применения и состав транспорта никогда не смешиваются в одном блоке:
applying loadout "documentation-work" (pinned)
synced: 67451fc · 2 skills, 1 MCP server → 1 environment
A skills/create-spec.md (new in all environments)
D skills/review-code.md (removed from all environments)
M skills/wpage.md (updated in all environments)
A mcp/context7.yaml (new in all environments)--force относится только к git-транспорту: он удаляет неотслеживаемые файлы в самом репозитории инвентаря, конфликтующие с remote. Это не связано со строками D пинованного применения, которые описывают удаление элементов из AI-сред. Если оба случая происходят в одном запуске, оба отчёта печатаются раздельно.
sync --dry-run в pinned-режиме показывает такой же план A/M/D, как apply --loadout <name> --dry-run, — отдельным вторым блоком после обычной git-дельты (или после nothing to sync, если из remote нечего применять):
[dry-run] nothing to sync — environments up to date with origin/main
[dry-run] would sync loadout "documentation-work" — 3 changes to 1 environment (claude-code):
A skills/create-spec.md (new in all environments)
D skills/review-code.md (would remove from all environments)
M skills/wpage.md (differs in all environments)Если среды уже совпадают с закреплённым loadout:
[dry-run] nothing to sync — environments match loadout "documentation-work"Пример вывода sync без пина
Без активного пина sync работает как раньше: аддитивно устанавливает весь инвентарь, ничего не удаляя из сред. Блок состава ниже описывает изменения самого инвентаря (что прилетело из remote), а не действия в средах.
При успехе sync выводит строку результата с хэшем применённого состояния. Если из remote прилетели изменения, после строки результата печатается блок состава: что обновилось в инвентаре (A — новые, M — изменённые, D — удалённые):
synced: 67451fc · 21 skills, 1 MCP server → 3 environments
M skills/commit-message.md
A skills/refactor-helper.mdКак и в apply, счётчики строки результата — это объём операции (всего применено), а блок — состав прилетевших изменений. 21 skills означает 21 навык всего, а не 21 изменение.
Если из remote ничего не прилетело (локальное состояние уже совпадало с origin/main), печатается только строка результата без блока:
synced: 67451fc · 21 skills, 1 MCP server → 3 environmentsС флагом --force AIM перед применением удаляет конфликтующие неотслеживаемые файлы и сообщает, что именно удалено. Этот отчёт печатается до строки результата:
discarded untracked files (--force):
skills/draft.md
mcp/local-only.yaml
synced: 67451fc · 21 skills, 1 MCP server → 3 environmentsОтчёт об удалении выводится всегда, без возможности отключения: --force удаляет файлы безвозвратно, и AIM не делает этого молча.
Пример вывода sync --dry-run без пина
Из remote нечего применять (локальное состояние совпадает с origin/main):
[dry-run] nothing to sync — environments up to date with origin/mainЕсть изменения для применения:
[dry-run] would sync 2 changes from origin/main → 3 environments:
M skills/commit-message.md
A skills/refactor-helper.mdaiman status
aiman statusПоказывает состояние активного репозитория инвентаря: позицию относительно origin/main, состояние AI-сред и список изменений в skills/, mcp/ и loadouts/, которые ещё не опубликованы.
aiman status обращается к remote. Перед расчётом позиции команда выполняет Git fetch — она отвечает на вопрос «что в инвентаре изменилось относительно опубликованного состояния», а этот вопрос по определению включает состояние remote. Без fetch ответ строился бы по устаревшему локальному ref и мог бы быть неверным (показывать up-to-date, когда remote уже ушёл вперёд).
Это осознанное отличие от локального git status. У git status нет сетевого обращения, потому что его вопрос — о локальном рабочем дереве. У aiman status вопрос другой и включает remote, поэтому короткая задержка на fetch — ожидаемое поведение, а не сбой.
TODO: добавить спиннер во время fetch
Fetch выполняется с жёстким таймаутом. Если remote недоступен, команда не зависает: поле Position: принимает значение unknown (remote unreachable), в stderr печатается warning: cannot reach remote repository, код возврата остаётся 0.
Поле Position: принимает значения: up-to-date with origin/main | N commits ahead of origin/main | N commits behind of origin/main | diverged from origin/main (N ahead, M behind) | unknown (remote unreachable).
Поле Environments: принимает значения: applied (synced <hash>) | unknown | needs sync (N commits not applied).
Поле Pinned loadout: показывает активный пин (aiman apply --loadout <name> --pin, см. Пин активного loadout) или none, если пин не установлен. Это локальное состояние из глобального конфига — оно печатается всегда, даже если remote недоступен, и не требует сети.
Если список изменений превышает 20 строк, он усекается с подписью … and N more.
Пример вывода
Репозиторий синхронизирован, инвентарь применён, пин не установлен:
Repository: git@github.com:you/aim-loadout.git
Position: up-to-date with origin/main
Environments: applied (synced a1b2c3d)
Pinned loadout: none
Working tree matches origin/main · nothing to publishЕсть активный пин:
Repository: git@github.com:you/aim-loadout.git
Position: up-to-date with origin/main
Environments: applied (synced a1b2c3d)
Pinned loadout: documentation-work
Working tree matches origin/main · nothing to publishЕсть неопубликованные изменения:
Repository: git@github.com:you/aim-loadout.git
Position: 2 commits ahead of origin/main
Environments: needs sync (2 commits not applied)
Pinned loadout: none
Changes not yet published (origin/main → working tree):
A skills/new-skill.md
M skills/existing.md
run aiman push to publish
run aiman sync to applyRemote недоступен (нет сети или нет доступа к репозиторию) — Pinned loadout: показывается как обычно, поскольку это локальное состояние:
Repository: git@github.com:you/aim-loadout.git
Position: unknown (remote unreachable)
Environments: applied (synced a1b2c3d)
Pinned loadout: none
Working tree matches origin/main · nothing to publishaiman doctor
aiman doctorДиагностирует локальную установку:
- активный репозиторий;
- найденные AI-среды;
- пути адаптеров;
- валидность навыков в
skills/активного репозитория инвентаря; - обязательные MCP env-переменные;
- доступность remote и состояние синхронизации.
Секция === AI Environments === отвечает только на вопрос «найдена ли базовая директория среды». Секция === Skills === считает валидные и невалидные навыки в skills/ активного репозитория инвентаря — она не сканирует AI-среды и не показывает, что в них установлено. Ни для одной среды doctor не проверяет состав установленных навыков.
Пример вывода
Всё в порядке, все среды найдены:
Active Repo: /home/user/.aim/aim-loadout (from /home/user/.config/aim/config.yaml)
=== AI Environments ===
✓ claude-code /home/user/.claude found
✓ cursor /home/user/.cursor found
✗ codex /home/user/.codex not found
=== Skills ===
Found: 4 valid, 0 invalid
=== Sync State ===
synced_hash: a1b2c3d
published_hash: a1b2c3d
remote HEAD: a1b2c3d
status: up-to-date
=== MCP Environment Variables ===
✓ context7 › UPSTASH_REDIS_REST_URL — set
=== Issues ===
• codex: not installed or not found at /home/user/.codexЕсть проблемы — AI-среда не найдена, обязательная переменная не задана:
Active Repo: /home/user/.aim/aim-loadout (from /home/user/.config/aim/config.yaml)
=== AI Environments ===
✓ claude-code /home/user/.claude found
✗ cursor /home/user/.cursor not found
✗ codex /home/user/.codex not found
=== Skills ===
Found: 2 valid, 1 invalid
=== Sync State ===
synced_hash: not set
published_hash: not set
remote HEAD: a1b2c3d
status: not yet synced
=== MCP Environment Variables ===
✗ context7 › UPSTASH_REDIS_REST_URL — missing (required)
=== Issues ===
• cursor: not installed or not found at /home/user/.cursor
• codex: not installed or not found at /home/user/.codex
• my-skill.md: invalid: missing description
• context7 › UPSTASH_REDIS_REST_URL — missing (required)aiman add
aiman add skill <file|dir|-> [--name <string>] [--overwrite]
aiman add mcp <file|-> [--name <string>] [--overwrite]Добавляет элемент инвентаря (навык или MCP-сервер) в локальный репозиторий из файла, директории или stdin.
aiman add skill
aiman add skill <file|dir|->
aiman add skill ~/Downloads/my-skill.md
aiman add skill -Читает скилл из файла, директории или stdin (-), валидирует frontmatter, определяет имя и записывает результат в активный репозиторий инвентаря.
Аргументы:
<file|dir|->— путь к файлу скилла, путь к папочному скиллу (или егоSKILL.md), либо-для чтения из stdin.
Флаги:
--name <string>— переопределить имя скилла; если не указан, имя берётся из frontmatter файла (для плоского скилла) или из имени директории (для папочного скилла).--overwrite— перезаписать существующий скилл при конфликте содержимого.
Поведение:
- одиночный файл (не названный
SKILL.md) или stdin — записывается как плоскийskills/<name>.md; - путь к директории, либо путь к файлу
SKILL.mdвнутри неё — распознаётся как папочный скилл и копируется целиком вskills/<name>/(SKILL.md+ все файлы-references рядом с ним). Оба варианта пути дают одинаковый результат; - если директория не содержит
SKILL.md— возвращается понятная ошибка, а не системная "is a directory"; - если
skills/<name>.md(плоский скилл) илиskills/<name>/SKILL.md(папочный скилл) уже существует с тем же содержимым — команда завершается успешно без изменений; для папочного скилла сравнивается только содержимоеSKILL.md, файлы-references в сравнении не участвуют. Если изменились только они, команда сообщитalready identicalи не перенесёт их —--overwriteздесь не помогает, скопируйте изменившиеся файлы вручную; - права доступа при копировании не сохраняются: все файлы записываются как
0644, исполняемый бит скриптов внутри папочного скилла теряется; - если назначение уже существует с другим содержимым и
--overwriteне указан — возвращает ошибку с подсказкой использовать--overwrite.
Пример добавления из файла:
aiman add skill ~/Downloads/create-spec.mdПример добавления из stdin:
cat ~/Downloads/create-spec.md | aiman add skill -Пример добавления папочного скилла (оба варианта равнозначны):
aiman add skill ~/Downloads/get-team-tasks
aiman add skill ~/Downloads/get-team-tasks/SKILL.mdВывод при успешном добавлении:
added: skill create-specВывод, если скилл уже есть в инвентаре с тем же содержимым (операция не требуется):
up to date: skill create-spec · already identicalaiman add mcp
aiman add mcp <file|->
aiman add mcp jira.yaml
aiman add mcp -Читает описание MCP-сервера из YAML-файла или из stdin (-), применяет env-strip и записывает результат в активный репозиторий инвентаря.
Аргументы:
<file|->— путь к YAML-файлу MCP-сервера или-для чтения из stdin.
Флаги:
--name <string>— переопределить имя сервера; если не указан, имя берётся из поляnameфайла.--overwrite— перезаписать существующий MCP-сервер при конфликте содержимого.
Поведение:
- если
mcp/<name>.yamlуже существует с тем же содержимым — команда завершается успешно без изменений; - если
mcp/<name>.yamlуже существует с другим содержимым и--overwriteне указан — возвращает ошибку с подсказкой использовать--overwrite.
Env-strip: поля env с заполненным value не сохраняются в mcp/<name>.yaml. Вместо этого реальные значения записываются в aim.local.yaml под ключом mcp_env: {<name>.<VAR>: value}. В инвентаре хранятся только дескрипторы: name, description, required, example. Файл aim.local.yaml исключён из Git, поэтому секреты не попадают в репозиторий.
Пример входного файла:
name: jira
description: Jira MCP server
command: npx
args: [-y, mcp-jira]
targets: [claude-code]
env:
- name: JIRA_API_KEY
description: Jira API key
required: true
value: "secret123"После выполнения команды:
mcp/jira.yamlсодержит дескриптор без поляvalue;aim.local.yamlсодержитmcp_env: {jira.JIRA_API_KEY: "secret123"}.
Пример добавления из файла:
aiman add mcp jira.yamlПример добавления из stdin:
cat jira.yaml | aiman add mcp -Переопределить имя сервера:
aiman add mcp jira.yaml --name jira-workПерезаписать при конфликте:
aiman add mcp jira.yaml --overwriteВывод при успешном добавлении:
added: mcp jiraВывод, если MCP-сервер уже есть в инвентаре с тем же содержимым (операция не требуется):
up to date: mcp jira · already identicalaiman import
aiman import [--dry-run] [--yes] [--from <env>]...
aiman import skill <name> --from <env> [--print] [--overwrite]
aiman import mcp <name> --from <env> [--print] [--overwrite] [--targets all]Родительская команда import совмещает два режима:
- Без аргументов (
aiman import,--dry-run,--yes,--from) — discovery: скан установленных AI-сред и план/массовый импорт того, что ещё не в инвентаре. Описан ниже. - С именем подкоманды (
aiman import skill <name>,aiman import mcp <name>) — точечный перенос одного заранее известного элемента. Поведение не изменилось с более ранних версий.
Родительская команда объявлена с Args: cobra.NoArgs: skill и mcp резолвятся Cobra как подкоманды раньше, чем сработает этот запрет, поэтому реальный вызов подкоманды не затронут. Опечатка в имени подкоманды (aiman import skil review-code) не попадает молча в discovery, а получает явную ошибку:
Error: unknown command "skil" for "aiman import"Discovery: aiman import без имени
aiman import # план: что нашли, что можно импортировать — ничего не пишет
aiman import --dry-run # явный синоним поведения по умолчанию
aiman import --yes # выполнить план: импортировать все безопасные кандидаты
aiman import --from codex # ограничить набор источников; флаг повторяемыйСканирует Claude Code, Cursor и Codex CLI на предмет уже установленных навыков и MCP-серверов, которых ещё нет в активном репозитории инвентаря, и показывает план — логические элементы, а не сырые файлы. Без флагов и с --dry-run команда ничего не пишет; вывод обоих вызовов идентичен побайтово.
Пример плана (значения путей и имён — иллюстративные):
$ aiman import
Scanned: ~/.claude, ~/.codex, ~/.cursor — no network requests, nothing leaves this machine
Claude Code 1 skill, 1 MCP server
Codex nothing found
Cursor nothing found
found: 2 occurrences → 2 unique items
ready to import: 2
mcp:context7
skill:review-code
Run: aiman import --yes to import 2 items and store 1 local MCP value
Nothing will change until --yes is used. No AI environment or remote repository is touched.Термины: occurrence — один элемент в одном источнике; unique item — группа с ключом <kind>:<name>. Один и тот же mcp:context7, найденный в трёх средах, — три occurrences, один unique item. Подробнее о модели кандидата — в Концепциях.
Категории плана:
ready to import— новый однозначный элемент, безопасен для--yes;already in inventory— payload уже совпадает с существующим элементом; файл не переписывается, форматирование сохраняется. Если у такого MCP-элемента отсутствует однозначное локальное значение env,--yesвсё равно заполнит его вaim.local.yaml, не трогая сам элемент — в плане это видно по числу в закрывающей строке ("...and store N local MCP values");conflicts— source conflict (один ключ, разный payload в разных средах) или policy conflict (одинаковый payload навыка, но разные явныеtargetsв frontmatter) или inventory conflict (ключ уже есть в инвентаре с другим payload, либо в инвентаре одновременно естьskills/<name>.mdиskills/<name>/SKILL.md); каждая причина написана рядом с именем элемента;invalid— имя не прошло валидацию или payload не проходит валидацию AIM;unsupported— MCP-сервер с транспортом, отличным отstdio(см.aiman import mcpниже).
Если ничего не найдено ни в одной среде — Found nothing to import. Если что-то найдено, но всё уже в инвентаре (нет ни одного ready) — отдельное сообщение Nothing to import: found inventory already covers your AI environments. Это два разных сообщения для двух разных ситуаций, не один и тот же тихий успех.
--yes выполняет план: добавляет новые однозначные элементы (навык — целиком, включая ресурсы и исполняемый бит, через тот же путь, что aiman add skill <dir>; MCP — как дескриптор без секретов) и заполняет отсутствующие однозначные локальные MCP-значения. Массового --overwrite не существует — конфликт решается точечно, через aiman import skill|mcp <name> --from <env> --overwrite. Пример результата:
$ aiman import --yes
imported: 2
mcp:context7
skill:review-code
Stored 1 local MCP value in aim.local.yaml (never published)
Next: aiman apply to deliver, aiman push to publishСтрока Stored N local MCP value(s) печатается только если что-то реально записано — реальных значений в ней никогда нет, только счётчик. Перед записью локальных значений команда проверяет, что .gitignore активного репозитория покрывает aim.local.yaml; если нет — печатает предупреждение и не пишет значение (сами элементы инвентаря это не блокирует):
warning: aim.local.yaml is not in .gitignore — local config may be committed accidentallyПовторный --yes на неизменных источниках и working tree — чистый no-op: файлы не создаются и не переписываются, порядок полей YAML и mtime не меняются, те же локальные значения повторно не пишутся.
Флаги:
--dry-run— синоним поведения по умолчанию (ничего не пишет). Если указаны одновременно--dry-runи--yes, побеждает--dry-run.--yes— выполнить план.--from <env>— ограничить скан этим источником; флаг повторяемый (--from cursor --from codex). По умолчанию — все поддерживаемые источники. Неизвестное значение — ошибка со списком доступных, до любого обращения к диску:textError: unknown environment: bogus; available: claude-code, cursor, codex
Две осознанные асимметрии с точечными import skill|mcp <name> — не баг, задокументировано намеренно:
- Сравнение с инвентарём. Discovery сравнивает найденный payload с существующим элементом инвентаря семантически — после разбора обеих сторон, игнорируя различия форматирования и порядка полей, и не учитывая в сравнении frontmatter-поля
targetsиnameнавыка (это delivery policy и идентичность, а не payload). Точечныеaiman add/aiman import skill|mcp <name>сравнивают по-прежнему побайтово. Причина: точечная команда реагирует на один конкретный файл, который назвал пользователь; discovery — на логическое содержимое, слитое из нескольких источников. - Вычисление
targets.aiman import mcp <name> --from cursor(без--targets all) даётtargets: [cursor]— только среда-источник. Discovery для нового MCP-элемента даётtargets, равный отсортированному объединению всех сред, где нашёлся тот же payload. Одна и та же по смыслу операция, разный результат — потому что одна реагирует на явное указание пользователя, а другая на наблюдаемое состояние всей машины.
Требует активного репозитория инвентаря — как и точечные подкоманды ниже:
Error: no active inventory repository; run 'aiman init' firstБез него — ошибка до любой записи на диск, в любом режиме (--dry-run, --yes или без флагов).
Не входит в discovery: интерактивный выбор кандидатов, project-scoped скан, автоматический apply/push, объединение разных payload, изменение targets существующего элемента, remote registry.
Общие требования для точечных aiman import skill <name>/aiman import mcp <name> ниже:
Нужен активный репозиторий инвентаря — то же требование, что и у discovery выше. Команда завершается ошибкой до любой записи на диск, требование действует и с флагом
--print.Имя элемента проверяется до построения пути записи. Отклоняются пустое имя,
.,.., имена с/или\, абсолютные пути, управляющие символы и имена длиннее 255 символов:texterror: invalid item name "../evil": must not contain "/" or "\"
aiman import skill
aiman import skill <name> --from <env>
aiman import skill create-spec --from claude-code
aiman import skill create-spec --from claude-code --printЧитает скилл по имени из указанной AI-среды и записывает его в активный репозиторий инвентаря.
Скиллы в AI-средах хранятся в формате папки — <name>/SKILL.md рядом с ресурсными файлами (references/, скрипты). Такой скилл переносится целиком: SKILL.md и все ресурсы попадают в skills/<name>/. Плоский файл <name>.md, если он есть в среде, записывается как skills/<name>.md.
Аргументы:
<name>— имя скилла, который нужно импортировать.
Флаги:
--from <env>— источник импорта (обязательный). Доступные значения:claude-code,cursor,codex.--print— вывести содержимое скилла в stdout без записи на диск. Для папочного скилла печатается толькоSKILL.md, ресурсные файлы не выводятся.--overwrite— перезаписать существующий скилл при конфликте содержимого.--targets— принимается для единообразия сaiman import mcp, но для скиллов игнорируется:targetsскилла задаётся только через frontmatter (см. Концепции).
Источники скиллов по AI-средам:
| AI-среда | Идентификатор | Путь к скиллам |
|---|---|---|
| Claude Code | claude-code | ~/.claude/skills/<name>/SKILL.md и плоские ~/.claude/skills/*.md |
| Codex CLI | codex | ~/.codex/skills/<name>/SKILL.md |
| Cursor | cursor | ~/.cursor/skills/<name>/SKILL.md |
Поведение:
- если скилл не найден в указанной среде — возвращает ошибку;
- если скилл уже есть в инвентаре с тем же содержимым — завершается успешно без изменений;
- если скилл уже есть в инвентаре с другим содержимым и
--overwriteне указан — возвращает ошибку с подсказкой использовать--overwrite; - совпадение содержимого определяется по
SKILL.md; ресурсные файлы при сравнении не учитываются. Если в среде изменились только ресурсные файлы, аSKILL.mdостался прежним, команда сообщитalready identicalи не перенесёт изменения —--overwriteв этом случае тоже не помогает, скопируйте изменившиеся файлы вручную.
Исполняемый бит ресурсных файлов (скриптов) папочного скилла сохраняется — и при переносе в инвентарь, и при последующей установке в AI-среду.
Пример импорта из Claude Code:
aiman import skill create-spec --from claude-codeВывод при успешном импорте:
imported: skill create-spec · from claude-codeВывод, если скилл уже есть в инвентаре с тем же содержимым (операция не требуется):
up to date: skill create-spec · already identicalПросмотр содержимого без записи:
aiman import skill create-spec --from claude-code --printaiman import mcp
aiman import mcp <name> --from <env> [--print] [--overwrite] [--targets all]
aiman import mcp context7 --from claude-code
aiman import mcp jira --from cursor --print
aiman import mcp context7 --from claude-code --targets allСканирует живую конфигурацию указанной AI-среды, находит MCP-серверы, применяет env-strip и записывает дескриптор в активный репозиторий инвентаря.
Аргументы:
<name>— имя MCP-сервера для импорта.
Флаги:
--from <env>— источник импорта (обязательный). Доступные значения:claude-code,cursor,codex.--print— вывести YAML-дескриптор в stdout без записи файлов. Проверка конфликта выполняется до вывода: еслиmcp/<name>.yamlуже существует с другим содержимым, команда завершится ошибкой и ничего не напечатает — добавьте--overwrite, чтобы всё равно увидеть дескриптор (файл при этом не перезаписывается).--overwrite— перезаписать существующий файл, если содержимое отличается.--targets all— задать все три адаптера (claude-code,cursor,codex) как целевые среды в дескрипторе. По умолчанию используется только среда-источник.
Поведение:
Env-strip: реальные значения env-переменных не сохраняются в
mcp/<name>.yaml. Вместо этого они записываются вaim.local.yamlпод ключомmcp_env: {<name>.<VAR>: value}. В инвентарь попадают только дескрипторы:name,required. Файлaim.local.yamlисключён из Git, поэтому секреты не попадают в репозиторий.Детерминированный порядок env: дескрипторы env-переменных записываются отсортированными по
name. Повторный импорт неизменённого источника даёт побайтово идентичный YAML, поэтомуalready identicalсрабатывает надёжно, а в Git не появляются диффы от перестановки строк.Поддерживается только транспорт stdio: сервер, объявленный через
"type": "http","type": "sse"или голый"url"безcommand, не импортируется. Команда завершается с ошибкой, называющей сервер и причину, и ничего не пишет на диск:texterror: MCP server "remote-tool": unsupported transport "http" (only stdio servers can be imported)Остальные серверы того же конфига импортируются как обычно.
Дедупликация: если одно имя сервера встречается несколько раз с одинаковой командой и аргументами, берётся первая запись.
Неоднозначность (AmbiguousError): если одно имя сервера встречается с разными командами или аргументами, команда завершается с ошибкой — нужно явно указать источник через
--from.Сервер не найден: если сервер с указанным именем отсутствует в конфигурации среды, команда завершается с ошибкой
MCP server "<name>" not found in <env>. Сервер с неподдерживаемым транспортом не попадает в эту категорию — для него выводится ошибка с причиной (см. выше), а неnot found.Неизвестная среда: если значение
--fromне распознано, команда завершается с ошибкойunknown environment: X; available: claude-code, cursor, codex.если
mcp/<name>.yamlуже существует с тем же содержимым — команда завершается успешно без изменений;если
mcp/<name>.yamlуже существует с другим содержимым и--overwriteне указан — возвращает ошибку с подсказкой использовать--overwrite.
Источники MCP-конфигурации по AI-средам:
| AI-среда | Идентификатор | Файл конфигурации |
|---|---|---|
| Claude Code | claude-code | ~/.claude.json (ключ mcpServers) |
| Cursor | cursor | ~/.cursor/mcp.json (ключ mcpServers) |
| Codex CLI | codex | ~/.codex/config.toml (секция mcp_servers) |
Для Claude Code дополнительно читается ~/.claude/settings.json: сервер берётся оттуда, только если записи с таким именем нет в ~/.claude.json.
Пример импорта из Claude Code:
aiman import mcp context7 --from claude-codeВывод при успешном импорте:
imported: mcp context7 · from claude-codeЕсли MCP-сервер содержал env-переменные с заполненными значениями, они записываются в aim.local.yaml:
imported: mcp context7 · from claude-code · secrets stored in aim.local.yamlВывод, если MCP-сервер уже есть в инвентаре с тем же содержимым (операция не требуется):
up to date: mcp context7 · already identicalПросмотр YAML-дескриптора без записи:
aiman import mcp context7 --from claude-code --printИмпорт с установкой всех адаптеров как целевых сред:
aiman import mcp context7 --from claude-code --targets allПерезаписать, если файл уже существует:
aiman import mcp context7 --from claude-code --overwriteКоманды вне текущего публичного scope
aiman list может присутствовать в кодовой базе как историческая команда, но полноценный публичный контракт отложен до полного inventory view.