Раздел: Codex
Идентификатор:codex_skills· Экран:ui/codex/CodexSkillsScreen.kt(480) +CodexSkillCards.kt(492)
Снимок: 2026-10-11
1. Зачем и что это
Скилл — это папка с SKILL.md и необязательными references/, scripts/. Codex читает каталог ~/.codex/skills, а также проектные и встроенные скиллы. Экран показывает всё это списком с группировкой по scope.
Экран намеренно один и для хаба, и для треда (тот же CodexSkillsScreen), чтобы настройка скиллов не расходилась между точками входа.
2. Как попасть
Хаб инструментов → секция Codex → карточка «Skills» (hub_codex_skills_title, тайл на главной — «Skills»).
| Откуда ещё | Путь |
|---|---|
| Меню треда | Codex → Skills (тот же экран) |
| Меню композера | Skills… рядом с Prompts… |
| Мост | app_navigate с screen: "codex_skills" |
Маршрут: Screen.kt:139 ("codex_skills" -> Screen.CodexSkillsHub) → MainRouter.kt:317.
3. Экран: элементы и действия
| Элемент | Что делает | Где в коде |
|---|---|---|
| Секция «Что это» | Раскрывающаяся шпаргалка (что/где/как вызывать/тумблер/прикрепить/бюджет) | explainerOpen, SkillExplainerLine |
| Секция «Каталог» | Настройки каталога: инструкции, бюджет токенов, встроенные | SkillCatalogCard |
| Секция «Прикреплённые» | Чипы скиллов, прикрепленных к следующему сообщению | attached-chips |
| Поле поиска | Фильтр по названию/описанию | OutlinedTextField |
| Список скиллов | Карточки, сгруппированные по scope | SkillCard |
| Тумблер скилла | Вкл/выкл — пишет skills/config/write | toggleSkillEnabled |
| Кнопка «Использовать» | Вставляет interface.defaultPrompt в поле ввода | useSkillPrompt |
| «Содержимое» | Окно с чтением SKILL.md и файлов скилла | CodexSkillContentWindow |
| Секция ошибок | Список битых SKILL.md из errors[] | — |
| Полоса статуса | ToggleStatusStrip — сообщения и «Отменить» | ToggleStatusStrip |
4. Возможности подробно
Группировка и порядок
Скиллы сортируются функцией sortSkills по scope, затем по имени — стабильный порядок, который не меняется при переключении тумблера. Scope подписан по skillScopeLabelRes: user → личные, repo → проектные, system → встроенные, admin → админские, прочее → «other».
Загрузка каталога
skills/list запрашивается для cwd активного треда. loadSkills(forceReload, silent):
forceReloadзаставляет сервер пересканировать диск (кнопка «Обновить»);silent— тихий перечит, без мигания спиннером.
Сбой запроса не стирает уже загруженный список: экран остаётся с прежними скиллами, а причину показывает строкой внутри экрана.
Тумблер скилла
toggleSkillEnabled пишет skills/config/write {path, enabled} — это правило [[skills.config]] в ~/.codex/config.toml; включение скилла добавляет правило, выключение — снимает. Сервер может ответить effectiveEnabled, отличным от запрошенного: тогда приложение показывает предупреждение «сервер оставил как есть» и приводит тумблер к фактическому значению. Успешная запись кладёт «Отменить» с прежним значением (pendingSkillUndo).
Если скилл выключается и был прикреплён, он автоматически открепляется (detached) — прикреплённый, но выключенный скилл в промпте не нужен.
Перечитывание после skills/changed
После записи сервер шлёт нотификацию skills/changed. Приложение не делает свой forceReload (это бы мигало списком), а тихо перечитывает каталог с дебаунсом SKILLS_RELOAD_DEBOUNCE_MS = 300 мс.
Настройки каталога
Три настройки из секции [skills] в config.toml:
| Настройка | Ключ | Смысл |
|---|---|---|
| Инструкции | skills.include_instructions | добавлять ли блок инструкций по скиллам в ходы |
| Бюджет | skills.max_context_tokens | сколько токенов каталог может занять в контексте |
| Встроенные | skills.bundled.enabled | отдавать ли встроенные скиллы Codex (каталог .system) |
Запись идёт через config/value/write (upsert), перезатем config/read сверяет значение и тихий skills/list перечитывает состав (он меняется при выключении встроенных). «Отменить» возвращает прежнее значение.
Важная деталь: skills.bundled сервер материализует всегда ({"enabled": true}), поэтому «ключа нет» и «включено» для UI неразличимы — это ровно то поведение, которое нужно.
Прикрепление скилла
Кнопка «Прикрепить» (чип) отправляет скилл в следующем сообщении как input[{type:"skill", name, path}]. Прикреплённые скиллы показываются чипами в секции «Прикрепленные», и они действуют только на одно сообщение.
Кнопка «Использовать»
Доступна, если у скилла непустой interface.defaultPrompt. Нажатие вставляет текст в поле ввода и закрывает экран (в отличие от Прикрепить).
Предупреждения о зависимостях
skillDependencyIssues проверяет dependencies.tools[] из agents/openai.yaml скилла против состояния MCP из config/read. Значение вида mcp__<сервер>__<инструмент> (или mcp__<сервер>__* — весь сервер) предупреждает, если сервер выключен или инструмент отключён: скилл останется в промпте, но вызвать инструмент агент не сможет.
Пока config/read не прошёл (serverEnabled == null), предупреждений нет — иначе все зависимости выглядели бы выключенными.
Не-MCP зависимости (команды, URL) показываются как справка, но не считаются поломкой.
5. Данные: БД, файлы, настройки
| Что | Где лежит | Как меняется | Кто читает |
|---|---|---|---|
| Скиллы | ~/.codex/skills (+ проектные) | Внешние правки или skill-installer | skills/list на app-server |
| Правила вкл/выкл | [[skills.config]] в ~/.codex/config.toml | skills/config/write | Codex |
| Настройки каталога | [skills] в config.toml | config/value/write | Codex |
| Содержимое скилла | Файлы скилла | — | fs/readDirectory + fs/readFile |
Содержимое SKILL.md и файлов скилла (references/, scripts/) читается через app-server (fs/readDirectory, fs/readFile → base64) — каталог ~/.codex приложению напрямую недоступен.
6. Backend: REST/роуты
Приложение ходит не в REST, а в app-server Codex по JSON-RPC:
| Запрос | Что делает |
|---|---|
skills/list {cwds, forceReload?} | каталог скиллов для cwd |
skills/config/write {path, enabled} | вкл/выкл скилла |
config/read {} | конфиг: [skills] + MCP-серверы/инструменты |
config/value/write {keyPath, value} | запись настройки каталога (upsert, null — снять) |
fs/readDirectory {path} | список файлов скилла |
fs/readFile {path} | содержимое SKILL.md (base64) |
7. Мост и MCP
| Что | Как | Примечание |
|---|---|---|
| Открыть экран | app_navigate с screen: "codex_skills" | BridgeScreenCatalog |
Отдельных MCP-тулов для управления скиллами нет — это часть настроек Codex, которые пишутся через app-server.
8. Настройки, конфиг, квоты и лимиты
| Параметр | Значение | Где задаётся |
|---|---|---|
| Дебаунс перечитывания | 300 мс | SKILLS_RELOAD_DEBOUNCE_MS |
| Дефолт бюджета | 2% окна контекста, максимум 10 000 | Codex |
| Границы бюджета | 1…1 000 000 токенов | SKILL_TOKENS_MIN/MAX |
Дефолт include_instructions | true | SkillCatalogSettings |
Дефолт bundled.enabled | true | То же |
9. Ловушки и ограничения
- Скорость тумблера — не факт применения. Сервер может оставить
effectiveEnabledне тем, что просили; экран покажет предупреждение и приведёт тумблер к фактическому состоянию. - «Ключа нет» ≠ «выключено» для
skills.bundled: сервер всегда материализует{"enabled": true}, так что UI не может отличить дефолт от явного включения — и это нормально. - Выключенный скилл не стирает список. Список остаётся, карточка просто гаснет (нет секций «в промпте»/«выключено»).
- Ошибки при загрузке не очищают каталог. Если
skills/listупал, экран покажет прежний список и строку с причиной. - Прикрепление действует на одно сообщение. Прикрепленный скилл не «приклеивается» к треду навсегда.
- «Использовать» вставляет текст и закрывает экран — в отличие от «Прикрепить», которое оставляет экран открытым.
- Предупреждения о зависимостях не появляются, пока не прочитан
config/read. Это защита от ложных срабатываний, но на старте, пока конфиг не пришёл, список будет выглядеть «чистым». - Пустой
defaultPromptубирает кнопку «Использовать» — не баг, а отсутствие метаданных в скилле. - Встроенные скиллы — каталог
.system. Их можно выключить, но тогда они исчезнут и изskills/list, и из промпта.
10. Источники правды
app/src/main/java/com/y83/ws/ui/codex/CodexSkillsScreen.kt— экран.app/src/main/java/com/y83/ws/ui/codex/CodexSkillCards.kt— карточки, тумблеры, слоты.app/src/main/java/com/y83/ws/ui/codex/CodexSkillActions.kt— действия (каталог, тумблеры, настройки, содержимое).app/src/main/java/com/y83/ws/ui/codex/CodexSkillContentWindow.kt— окно содержимого.app/src/main/java/com/y83/ws/data/codex/CodexSkillsSettings.kt—SkillCatalogSettings.app/src/main/java/com/y83/ws/data/codex/CodexSkillsDeps.kt— разбор и проверка зависимостей.app/src/main/java/com/y83/ws/data/codex/CodexSkillsParse.kt— разбор ответаskills/list, сортировка.app/src/main/java/com/y83/ws/ui/components/ToggleControls.kt—ToggleBusySlot,ToggleStatusStrip.agents/openai.yamlв каждом скилле — метаданныеdependencies.tools[],interface.defaultPrompt.