Skip to content

Справочник CLI

Все команды предоставляет бинарник aiman.

Формат вывода нестабилен до версии 1.0. Человекочитаемый вывод команд — не стабильный API. Для автоматизации ожидайте будущий флаг --json. Все изменения формата помечаются breaking: в changelog.

Глобальные флаги

ФлагОписание
--helpПоказать help для команды
--versionПоказать версию бинарника

aiman init

bash
aiman init <repo-url> [--path <dir>]

Подключает репозиторий инвентаря.

Аргументы:

  • <repo-url> — URL Git-репозитория инвентаря.

Флаги:

  • --path <dir> — локальный путь для clone или регистрации репозитория.

Поведение:

  • клонирует или регистрирует репозиторий инвентаря;
  • создаёт структуру для пустого репозитория;
  • создаёт локальный aim.local.yaml;
  • записывает активный репозиторий в глобальный конфиг;
  • классифицирует существующие файлы как adoptable, existing AIM или conflicting.

aiman switch

bash
aiman switch <path>

Переключает активный репозиторий инвентаря без clone.

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

switch безусловно снимает активный пин (aiman apply --loadout <name> --pin, см. Пин активного loadout) — даже если в новом репозитории есть loadout с таким же именем. Если после переключения нужен пин, установите его заново: aiman apply --loadout <name> --pin.

aiman apply

bash
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 (изменённый):

text
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 изменение.

Если в средах ничего не изменилось, печатается только строка результата без блока:

text
applied: 21 skills, 1 MCP server → 3 environments

Пример вывода apply --dry-run

Инвентарь совпадает с установленными AI-средами:

text
[dry-run] nothing to apply — environments match local inventory

Есть изменения:

text
[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 строк, он усекается:

text
  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>

bash
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 (удалён из среды):

text
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 ссылается на элемент инвентаря, которого больше нет или который сейчас невалиден, элемент пропускается с предупреждением — он не устанавливается и не удаляется:

text
warning: loadout "dev": no valid inventory item for skill:ghost (skipped)

Пример вывода apply --loadout --dry-run

--dry-run показывает полный план A/M/D без записи в среды и конфиги:

text
[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:

text
[dry-run] nothing to apply — environments match loadout "Documentation Work"

Перед первым применением loadout всегда запускайте --dry-run: строки D показывают, что именно будет удалено (см. ограничения).

Ошибки apply --loadout

Loadout не найден (в loadouts/ нет ни файла, ни поля name с таким именем):

text
hint: available loadouts: dev, docs
error: loadout "ghost" not found in loadouts/

Подсказка со списком печатается, если валидных loadout от одного до пяти: при их отсутствии подсказывать нечего, при большем числе список бесполезен. В подсказке перечисляются значения поля name, а не имена файлов.

Loadout найден, но невалиден — apply останавливается на первой ошибке:

text
error: loadout "empty": items: cannot be empty

Полный список ошибок по всем loadout-файлам сразу выдаёт aiman push.

Пин активного loadout: --pin, --default, --unpin

bash
aiman apply --loadout <name> --pin
aiman apply --default
aiman apply --unpin

Пин — это сохранённое состояние, а не разовое действие: он живёт в глобальном конфиге пользователя (~/.config/aim/config.yaml, поле loadout — см. Справочник конфигурации) и переживает перезапуск CLI и обновления инвентаря. Пока пин установлен, aiman sync применяет именно этот loadout вместо полного инвентаря — так вы можете подтягивать обновления из remote, оставаясь в узком наборе. Подробнее о разнице между разовым apply --loadout <name> и пином — в Концепциях, сценарий использования — в Рабочих циклах.

bash
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 тоже только показывают, что произошло бы, и оставляют пин на месте:

text
[dry-run] would unpin loadout "documentation-work" — sync would go back to applying the full inventory

Если пина нет:

text
[dry-run] nothing to unpin — no loadout is pinned

--default — единственный способ одним действием вернуться к полному инвентарю и снять пин. Строка "Default" никогда не записывается как значение пина: отсутствие пина и режим Default неразличимы на уровне конфига.

Конфликты флагов apply

Эти ошибки проверяются до чтения инвентаря и до любых изменений на диске:

КомбинацияОшибка
--pin без --loadouterror: --pin requires --loadout <name>
--default + --loadouterror: --default and --loadout are mutually exclusive
--default + --pinerror: --pin is redundant with --default
--unpin вместе с --loadout, --pin или --defaulterror: --unpin does not apply — combine only alone

aiman push

bash
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. Все найденные ошибки выводятся сразу, публикация блокируется:

text
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 — изменённые):

text
published: 96e091b · 19 skills, 1 MCP server
  M skills/commit-message.md
  A mcp/jira.yaml
  A loadouts/documentation-work.yaml

Если изменений нет, печатается только строка результата без блока.

Пример вывода push --dry-run

Рабочее дерево чистое:

text
[dry-run] nothing to publish — working tree is clean

Есть изменения для публикации:

text
[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

bash
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, которого больше нет:

text
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-транспорта (что изменилось в опубликованном инвентаре относительно предыдущего состояния) — состав применения и состав транспорта никогда не смешиваются в одном блоке:

text
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 нечего применять):

text
[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:

text
[dry-run] nothing to sync — environments match loadout "documentation-work"

Пример вывода sync без пина

Без активного пина sync работает как раньше: аддитивно устанавливает весь инвентарь, ничего не удаляя из сред. Блок состава ниже описывает изменения самого инвентаря (что прилетело из remote), а не действия в средах.

При успехе sync выводит строку результата с хэшем применённого состояния. Если из remote прилетели изменения, после строки результата печатается блок состава: что обновилось в инвентаре (A — новые, M — изменённые, D — удалённые):

text
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), печатается только строка результата без блока:

text
synced: 67451fc · 21 skills, 1 MCP server → 3 environments

С флагом --force AIM перед применением удаляет конфликтующие неотслеживаемые файлы и сообщает, что именно удалено. Этот отчёт печатается до строки результата:

text
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):

text
[dry-run] nothing to sync — environments up to date with origin/main

Есть изменения для применения:

text
[dry-run] would sync 2 changes from origin/main → 3 environments:
  M skills/commit-message.md
  A skills/refactor-helper.md

aiman status

bash
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.

Пример вывода

Репозиторий синхронизирован, инвентарь применён, пин не установлен:

text
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

Есть активный пин:

text
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

Есть неопубликованные изменения:

text
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 apply

Remote недоступен (нет сети или нет доступа к репозиторию) — Pinned loadout: показывается как обычно, поскольку это локальное состояние:

text
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 publish

aiman doctor

bash
aiman doctor

Диагностирует локальную установку:

  • активный репозиторий;
  • найденные AI-среды;
  • пути адаптеров;
  • валидность навыков в skills/ активного репозитория инвентаря;
  • обязательные MCP env-переменные;
  • доступность remote и состояние синхронизации.

Секция === AI Environments === отвечает только на вопрос «найдена ли базовая директория среды». Секция === Skills === считает валидные и невалидные навыки в skills/ активного репозитория инвентаря — она не сканирует AI-среды и не показывает, что в них установлено. Ни для одной среды doctor не проверяет состав установленных навыков.

Пример вывода

Всё в порядке, все среды найдены:

text
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-среда не найдена, обязательная переменная не задана:

text
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

bash
aiman add skill <file|dir|-> [--name <string>] [--overwrite]
aiman add mcp <file|-> [--name <string>] [--overwrite]

Добавляет элемент инвентаря (навык или MCP-сервер) в локальный репозиторий из файла, директории или stdin.

aiman add skill

bash
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.

Пример добавления из файла:

bash
aiman add skill ~/Downloads/create-spec.md

Пример добавления из stdin:

bash
cat ~/Downloads/create-spec.md | aiman add skill -

Пример добавления папочного скилла (оба варианта равнозначны):

bash
aiman add skill ~/Downloads/get-team-tasks
aiman add skill ~/Downloads/get-team-tasks/SKILL.md

Вывод при успешном добавлении:

text
added: skill create-spec

Вывод, если скилл уже есть в инвентаре с тем же содержимым (операция не требуется):

text
up to date: skill create-spec · already identical

aiman add mcp

bash
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, поэтому секреты не попадают в репозиторий.

Пример входного файла:

yaml
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"}.

Пример добавления из файла:

bash
aiman add mcp jira.yaml

Пример добавления из stdin:

bash
cat jira.yaml | aiman add mcp -

Переопределить имя сервера:

bash
aiman add mcp jira.yaml --name jira-work

Перезаписать при конфликте:

bash
aiman add mcp jira.yaml --overwrite

Вывод при успешном добавлении:

text
added: mcp jira

Вывод, если MCP-сервер уже есть в инвентаре с тем же содержимым (операция не требуется):

text
up to date: mcp jira · already identical

aiman import

bash
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, а получает явную ошибку:

text
Error: unknown command "skil" for "aiman import"

Discovery: aiman import без имени

bash
aiman import                       # план: что нашли, что можно импортировать — ничего не пишет
aiman import --dry-run             # явный синоним поведения по умолчанию
aiman import --yes                 # выполнить план: импортировать все безопасные кандидаты
aiman import --from codex          # ограничить набор источников; флаг повторяемый

Сканирует Claude Code, Cursor и Codex CLI на предмет уже установленных навыков и MCP-серверов, которых ещё нет в активном репозитории инвентаря, и показывает план — логические элементы, а не сырые файлы. Без флагов и с --dry-run команда ничего не пишет; вывод обоих вызовов идентичен побайтово.

Пример плана (значения путей и имён — иллюстративные):

text
$ 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. Пример результата:

text
$ 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; если нет — печатает предупреждение и не пишет значение (сами элементы инвентаря это не блокирует):

text
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). По умолчанию — все поддерживаемые источники. Неизвестное значение — ошибка со списком доступных, до любого обращения к диску:

    text
    Error: unknown environment: bogus; available: claude-code, cursor, codex

Две осознанные асимметрии с точечными import skill|mcp <name> — не баг, задокументировано намеренно:

  1. Сравнение с инвентарём. Discovery сравнивает найденный payload с существующим элементом инвентаря семантически — после разбора обеих сторон, игнорируя различия форматирования и порядка полей, и не учитывая в сравнении frontmatter-поля targets и name навыка (это delivery policy и идентичность, а не payload). Точечные aiman add/aiman import skill|mcp <name> сравнивают по-прежнему побайтово. Причина: точечная команда реагирует на один конкретный файл, который назвал пользователь; discovery — на логическое содержимое, слитое из нескольких источников.
  2. Вычисление targets. aiman import mcp <name> --from cursor (без --targets all) даёт targets: [cursor] — только среда-источник. Discovery для нового MCP-элемента даёт targets, равный отсортированному объединению всех сред, где нашёлся тот же payload. Одна и та же по смыслу операция, разный результат — потому что одна реагирует на явное указание пользователя, а другая на наблюдаемое состояние всей машины.

Требует активного репозитория инвентаря — как и точечные подкоманды ниже:

text
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 символов:

    text
    error: invalid item name "../evil": must not contain "/" or "\"

aiman import skill

bash
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 Codeclaude-code~/.claude/skills/<name>/SKILL.md и плоские ~/.claude/skills/*.md
Codex CLIcodex~/.codex/skills/<name>/SKILL.md
Cursorcursor~/.cursor/skills/<name>/SKILL.md

Поведение:

  • если скилл не найден в указанной среде — возвращает ошибку;
  • если скилл уже есть в инвентаре с тем же содержимым — завершается успешно без изменений;
  • если скилл уже есть в инвентаре с другим содержимым и --overwrite не указан — возвращает ошибку с подсказкой использовать --overwrite;
  • совпадение содержимого определяется по SKILL.md; ресурсные файлы при сравнении не учитываются. Если в среде изменились только ресурсные файлы, а SKILL.md остался прежним, команда сообщит already identical и не перенесёт изменения — --overwrite в этом случае тоже не помогает, скопируйте изменившиеся файлы вручную.

Исполняемый бит ресурсных файлов (скриптов) папочного скилла сохраняется — и при переносе в инвентарь, и при последующей установке в AI-среду.

Пример импорта из Claude Code:

bash
aiman import skill create-spec --from claude-code

Вывод при успешном импорте:

text
imported: skill create-spec · from claude-code

Вывод, если скилл уже есть в инвентаре с тем же содержимым (операция не требуется):

text
up to date: skill create-spec · already identical

Просмотр содержимого без записи:

bash
aiman import skill create-spec --from claude-code --print

aiman import mcp

bash
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, не импортируется. Команда завершается с ошибкой, называющей сервер и причину, и ничего не пишет на диск:

    text
    error: 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 Codeclaude-code~/.claude.json (ключ mcpServers)
Cursorcursor~/.cursor/mcp.json (ключ mcpServers)
Codex CLIcodex~/.codex/config.toml (секция mcp_servers)

Для Claude Code дополнительно читается ~/.claude/settings.json: сервер берётся оттуда, только если записи с таким именем нет в ~/.claude.json.

Пример импорта из Claude Code:

bash
aiman import mcp context7 --from claude-code

Вывод при успешном импорте:

text
imported: mcp context7 · from claude-code

Если MCP-сервер содержал env-переменные с заполненными значениями, они записываются в aim.local.yaml:

text
imported: mcp context7 · from claude-code · secrets stored in aim.local.yaml

Вывод, если MCP-сервер уже есть в инвентаре с тем же содержимым (операция не требуется):

text
up to date: mcp context7 · already identical

Просмотр YAML-дескриптора без записи:

bash
aiman import mcp context7 --from claude-code --print

Импорт с установкой всех адаптеров как целевых сред:

bash
aiman import mcp context7 --from claude-code --targets all

Перезаписать, если файл уже существует:

bash
aiman import mcp context7 --from claude-code --overwrite

Команды вне текущего публичного scope

aiman list может присутствовать в кодовой базе как историческая команда, но полноценный публичный контракт отложен до полного inventory view.

Released under the Apache 2.0 License.