Как писать навыки для ИИ-ассистентов: куда их класть и пять готовых примеров

Что такое навык

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

Думайте о нём как о вводной документации для коллеги, который забывает всё между сессиями: точной, построенной на примерах и достаточно короткой, чтобы её действительно прочитали. В OpenCode агент на каждом шаге видит только id, название и описание, а полный текст загружает по требованию инструментом skill — или вы загружаете его сами через @skill-id. Поведение, которое должно сохраняться между сессиями, живёт в навыках, разовые пожелания — в промпте. Роли со своей моделью и разрешениями — это агенты, а не навыки.

Куда класть навыки

Навыки не зависят от модели: бесплатная модель OpenCode, GPT 6 Luna и Claude Opus 5.5 читают из одних и тех же мест. Различается только то, насколько строго каждая модель следует длинному навыку — см. Навыки и модели. Командные навыки кладите в проект, чтобы они коммитились, личные помощники — в глобальный каталог.

Две формы файлов, один реестр. Либо плоский файл в корне источника, либо каталог с ровно одним SKILL.md где-то внутри. В OpenCode путь задаёт id, а name во frontmatter — только метка; Claude Code и стандарт Agent Skills ожидают, что name и есть тот же id в kebab-case, поэтому пишите name: git-release, и навык работает в обоих:

skills/review.md -> id: review skills/git-release/SKILL.md -> id: git-release skills/teams/release/SKILL.md -> id: release

Дополнительные записи в opencode.jsonc разрешаются от активного рабочего каталога, домашний каталог раскрывается, массивы объединяются между конфигурациями:

vi opencode.jsonc

{ "$schema": "https://opencode.ai/config.json", "skills": ["./team-skills", "~/shared/opencode-skills"] }

Приоритет задаётся по id, побеждает более поздний источник: встроенные, затем .claude, затем .agents, затем глобальный opencode/skills, затем проектный .opencode/skills от корня к текущему каталогу, затем явные записи skills. Избегайте повторяющихся id, если только не хотите осознанно что-то переопределить. Полная раскладка со ссылками — в разделе Реальный скелет проекта, ограничение по агентам — в разделе Ограничение навыков по агентам.

Анатомия хорошего навыка

В каждом навыке нужны четыре части. Название и описание в одну строку, чтобы ассистент мог решить, к месту ли он. Условия срабатывания: когда его загружать и — не менее важно — когда не загружать. Сама процедура нумерованными шагами, с точными командами вместо общих советов. И два-три примера со входом, действиями и ожидаемым результатом.

Во frontmatter OpenCode полей мало и они необязательны, но именно описание решает обнаружение — нет описания, значит навык никогда не объявляется. Ставьте opencode/autoinvoke: false только чтобы скрыть помощника, который другие навыки подключают вручную. Берите в кавычки любое значение с двоеточием и пробелом: YAML читает description: Aredel: decide без кавычек как вложенный ключ и отвергает весь frontmatter, после чего навык молча исчезает. Пример файла .claude/skills/git-release/SKILL.md:

mkdir -p .claude/skills/git-release

vi .claude/skills/git-release/SKILL.md

--- name: git-release description: Prepare release notes, version bumps, and GitHub releases --- ## Workflow 1. Read references/release-policy.md. 2. Summarize merged changes since the previous tag. 3. Propose the version bump before changing files.

Пути внутри навыка относительны каталога с SKILL.md, поэтому скрипты и ссылки держите рядом. Объявленный список показывает только id, название и описание плюс до десяти вспомогательных путей, но никогда полный текст. Что убивает навыки: общие рассуждения, отсутствие отрицательных случаев и длина. Если он не помещается на один экран, разделите его на два навыка.

Пять готовых примеров

Берите их как отправную точку. Каждый — полный текст файла, а не фрагмент. Все пять есть в дереве из раздела Реальный скелет проекта.

Пример 1 — плоский стиль коммитов. Файл .opencode/skills/commit-style.md, id commit-style. Учит формату сообщений для всего репозитория в 12 строках:

mkdir -p .opencode/skills

vi .opencode/skills/commit-style.md

--- name: commit-style description: Write repo commit messages in Area: change form under 70 chars --- ## Use when User asks to commit, stage, or push the changes. ## Do not use for Code review, unstaged debug logs, release notes. ## Workflow 1. Run git status --short and git diff --stat. Never commit unrelated files. 2. Message form: Area: specific change, under 70 chars. Example: Auth: reject expired tokens with 401. 3. Stage only the agreed paths, show the staged summary, wait for approval. 4. Commit with the approved message, no push unless asked.

Вызов: @commit-style Write a commit for the auth fix. Хороший путь: два изменённых файла дают один подготовленный коммит. Крайний случай: смешанные несвязанные файлы дают два отдельных предложения. Похожая задача, где навык должен промолчать: пользователь просит сделать ревью диффа.

Пример 2 — навык миграций в виде каталога с помощниками. Файл .opencode/skills/db-migrate/SKILL.md, id db-migrate:

mkdir -p .opencode/skills/db-migrate

vi .opencode/skills/db-migrate/SKILL.md

--- name: db-migrate description: Safe database migration with review and rollback plan --- ## Use when User mentions migration, migrates the DB, edits files under db/. ## Do not use for Plain SELECT questions, schema explainers, seed data design. ## Workflow 1. Read references/policy.md for naming and reversibility rules. 2. Run git diff --stat and show the planned SQL diff. Stop and wait for approval. 3. Run scripts/rollback.sh --dry-run and paste the output. 4. Apply the migration, then run npm test -- --tag migration. 5. Output: applied files, rollback command, test result. ## Example Input: Add unique index on users.email. Actions: propose db/014_unique_email.sql, show rollback DROP INDEX, dry run first. Output: three bullet lines with file, rollback, tests green.

Рядом: scripts/rollback.sh печатает обратный SQL, не применяя его, а references/policy.md хранит правила именования в 20 строках:

# policy.md: every migration has a down file, no raw DROP TABLE, # index names like idx_users_email, all SQL reviewed before apply.

Агент читает помощников только тогда, когда навык велит ему это сделать. У плоских навыков нет списка соседних файлов, поэтому форма каталога — верный выбор, как только навыку нужно больше одного файла.

Пример 3 — плоский навык релиза. Файл .opencode/skills/git-release.md, id git-release:

vi .opencode/skills/git-release.md

--- name: git-release description: Prepare changelog, version bump, tag, and release notes --- ## Use when User asks for release, changelog, version bump, tag the release. ## Workflow 1. Run git log --oneline v1.4.0..HEAD and group into Features, Fixes, Docs. 2. Propose the semver bump with reasons. Wait for approval. 3. Update CHANGELOG.md and package.json, run npm test. 4. Tag v1.5.0 and draft notes with highlights first. ## Example Input: Prepare 1.5.0. Output: bump minor because of new export API, changelog draft, tag command ready.

Пример 4 — писатель тестов для дешёвых моделей. Файл .opencode/skills/test-writer/SKILL.md, id test-writer. Написан под бесплатную модель OpenCode и GPT 6 Luna: короткий, в повелительном наклонении, одна точная команда тестов:

mkdir -p .opencode/skills/test-writer

vi .opencode/skills/test-writer/SKILL.md

--- name: test-writer description: Add focused unit tests for one module with repo test runner --- ## Use when User asks to add tests, cover a module, fix missing coverage. ## Do not use for E2E suites, load tests, manual QA plans. ## Workflow 1. Read the target module and glob sibling tests under tests/ for style. 2. Write one test file per module: happy path, one edge, one error. 3. Run npm test -- --run tests/auth.test.ts and paste failures. 4. Fix until green. Output: new file path, cases added, command result. ## Example Input: Cover src/auth.ts. Actions: read src/auth.ts, mirror tests/auth.test.ts style, three cases. Output: file created, 3 passed in output block.

Пример 5 — строгий навык ревью для топовой модели. Файл .opencode/skills/api-review/SKILL.md, id api-review. Рубрика длиннее, и загружать её разрешено только агенту-ревьюеру на Opus (см. Ограничение по агентам):

mkdir -p .opencode/skills/api-review

vi .opencode/skills/api-review/SKILL.md

--- name: api-review description: Review API diffs for bugs, security, and missing tests in severity order --- ## Use when User asks to review a diff, audit an endpoint, check auth handling. ## Workflow 1. Run git diff --cached and list touched endpoints. 2. Check in order: auth bypass, injection, broken status codes, missing tests. 3. For each finding give file, line, severity, and a minimal fix. 4. Verdict: ship, fix first, or block. Never edit files, report only. ## Example Input: Review staged auth diff. Output: 1. High: missing 401 on expired token in src/auth.ts:42. 2. Medium: no test for refresh replay. Verdict: fix first.

Дополните его агентом-ревьюером из руководства по OpenCode, который запрещает edit, чтобы ревью никогда не меняло код.

Реальный скелет проекта

Полная раскладка проекта со всеми пятью навыками плюс общие командные навыки. Вывод tree, каждый элемент ссылается на главу, где он объяснён:

my-app/ ├── opencode.jsonc ├── .opencode/skills/ │ ├── commit-style.md │ ├── db-migrate/ │ │ ├── SKILL.md │ │ ├── scripts/ │ │ │ └── rollback.sh │ │ └── references/ │ │ └── policy.md │ ├── git-release.md │ ├── test-writer/ │ │ └── SKILL.md │ └── api-review/ │ └── SKILL.md ├── team-skills/ │ └── deploy/ │ └── SKILL.md └── .opencode/agents/ ├── reviewer.md └── builder.md

Читайте сверху вниз: opencode.jsonc регистрирует дополнительные каталоги и ограничивает id по агентам, commit-style — плоский стартовый навык, db-migrate — форма каталога с помощниками, test-writer настроен под дешёвые модели, api-review — строгий навык только для Opus. Соседний каталог агентов хранит профили, которые загружают эти id.

Карта проекта Aredel

Репозиторий aredel — большой сайт на PHP с более чем 7000 PHP-файлов, где URL отображается на путь к файлу один к одному. Корень репозитория и докрут:

/home/andrei/github/aredel

container/src/

С репозиторием работают через OpenCode и Claude Code, поэтому каждый навык лежит в одном месте — в .claude/skills/ в корне репозитория: OpenCode читает его как совместимое расположение, Claude Code — как родное. Глобальных навыков для работы с aredel нет: глобальные записи расширяют объявленный список на каждом шаге и стоят токенов на каждой модели. Эта раскладка заменила набор в .opencode/skills/ плюс вложенное переопределение внутри докрута; почему и как проверялся каждый шаг — в материале «Аудит настройки агентов». Связка ролей — в разделе Трио Aredel на одном репозитории.

aredel/ ├── AGENTS.md ├── opencode.jsonc └── .claude/skills/ ├── aredel-map/SKILL.md ├── aredel-page/ │ ├── SKILL.md │ └── references/page-checklist.md ├── aredel-blocks/ │ ├── SKILL.md │ └── references/block-classes.md ├── aredel-css/SKILL.md ├── aredel-tooling/SKILL.md ├── aredel-verify/SKILL.md └── ai-style/SKILL.md

Модель видит семь коротких id, и все они объявлены. Тяжёлые заметки лежат в references/ и загружаются только тогда, когда текст навыка велит агенту их прочитать. Каждое описание начинается с Aredel:, поэтому фильтрация идёт по объявленному списку без загрузки текстов, и каждое описание взято в кавычки: YAML читает Aredel: decide без кавычек как вложенный ключ и отвергает весь frontmatter.

Навык Aredel 1 — карта, крошечный. Файл .claude/skills/aredel-map/SKILL.md. Сжат из внутренних правил «страница или включаемый файл», меньше 20 строк, чтобы даже бесплатная модель OpenCode ему следовала:

--- name: aredel-map description: "Aredel: decide page versus include before editing or creating any PHP file under container/src/" --- ## Use when User asks to edit, fix, or create any file under container/src/. ## Do not use for CSS-only edits (aredel-css), tooling under container/tools/ or tests (aredel-tooling). ## Workflow 1. Basename matches _top_path, _menu, _inc, _footer fragment, arj, copy dup, validate_, demo, or PascalCase helper like RelatedArticles.php: hands off, it is a non-page. 2. Else check footer path: page must render bottomid via createFooter or terminal _footer include. If already covered, hands off. 3. Else it is a page candidate: URL equals src plus path, confirm in container/src/sitemap.xml before patching. ## Example Input: Fix src/ao/chessboard/game.php. Output: Non-page, game tooling, refuse footer patch, propose page-level fix instead. ## Deep reference Full pattern table and footer rules: _internal_ai_skill_for_files.md at the repo root.

Навык Aredel 2 — скелет страницы. Файл .claude/skills/aredel-page/SKILL.md. Длинная таблица классов лежит в references, чтобы текст оставался коротким:

--- name: aredel-page description: "Aredel: scaffold a new page under container/src: ArticlePage, BasePage, RelatedArticles, tcont and lesson nav" --- ## Use when User asks for a new article, lesson, hub, or course index. ## Do not use for Edits to article body text (aredel-blocks), CSS (aredel-css), tooling, or redirects. ## Workflow 1. Read references/page-checklist.md for the class choice: ArticlePage for lessons, BasePage for hubs, DictPage for dictionary entries. 2. Create sibling RelatedArticles.php with articles plus breadcrumbs, wire tcont_urls, wire prev and next lesson on both neighbours. 3. Never use legacy 010_header, 020_header, hand TOC tables, or new Page. 4. Run php -l and CLI render with DOCUMENT_ROOT shim, then regenerate the sitemap (a page was added). ## Example Input: Add dev/ruby/course lesson 51. Output: ArticlePage file plus RelatedArticles entry plus tcont plus sitemap run. ## Deep reference Working notes on page classes and migration: skill.md at the repo root, sections 2 and 6.

Навык Aredel 3 — блоки и деревья. Файл .claude/skills/aredel-blocks/SKILL.md:

--- name: aredel-blocks description: "Aredel: article body HTML between createHead and createFooter: code and command blocks, trees, paths, external links" --- ## Use when User edits article body HTML between createHead and createFooter. ## Do not use for New pages (aredel-page), CSS (aredel-css), tooling, or test files. ## Workflow 1. One shell command per cmd1, narrative in p2, output in cout1, Python in pycode, generic code in somecode. Never use pre code. 2. Tree output uses cout1 wspw with each element as link to its chapter anchor, same as ai-style pages. 3. Standalone filesystem path on its own line uses path p1 (tight) or path p2 (section break); inline mentions stay tt spans. 4. External URLs are always real links with class exturl and rel nofollow, never bare https text. 5. First-mention Linux, Windows, Unix links only in prose p2, never in code or paths. 6. A snippet the reader must put in a file (config, agent, skill) names that file and is preceded by the cmd1 that opens it, e.g. `vi opencode.jsonc`; add `mkdir -p <dir>` first when the directory may not exist. 7. A reference to another part of the same page (test 3, step 2, the table above) is a link to an anchor placed right before that part: `<div id="test-3" class="anchor"></div>` there, `<a href="#test-3">test 3</a>` here. 8. Keep tag balance: php -l plus render must stay exit 0. ## Example Input: Add project tree to a lesson. Output: cout1 wspw block with five linked elements plus render check. ## Deep reference Full block class list: references/block-classes.md; highlight rules: skill.md at the repo root, code-block section.

Навык Aredel 4 — CSS. Файл .claude/skills/aredel-css/SKILL.md. Объявляется как остальные: раньше он был скрыт через opencode/autoinvoke: false, а скрытый навык — тот, который роль, правящая CSS, никогда не найдёт:

--- name: aredel-css description: "Aredel: CSS changes: code-block classes in source/_codeblocks.css, site overrides, building the served sheets with build-css.sh" --- ## Use when User asks for a new code block class or a change to site CSS under container/src/.css/. ## Do not use for Page markup (aredel-blocks), page scaffolds (aredel-page), tooling. ## Workflow 1. New code class: clone the nearest sibling language block in `container/src/.css/source/_codeblocks.css` (`.phpcode`, `.pycode`, `.somecode`, …), rename the class, label and header colors. Keep the HTML class casing (`.incFr13`, not `.incfr13`). 2. Add the class to the table in `container/docs/articles.md` and to `CODE_CLASSES` in `container/tests/test_css_sources.py`. 3. Build from `container/`: `tools/css/build-css.sh`; gate with `tools/css/build-css.sh --check`. Never edit `.css/output/*.css`; language classes live in `source/_codeblocks.css`, which is a core input, so do not copy them into the layout partials or a site file. 4. Verify the class is present in all four built sheets and render one page using it (header label, dark background, line numbers). 5. Fixing an existing code-block rule: edit `_codeblocks.css`; use the site file only for a genuinely site-specific override, never rewrite shared selectors in place. ## Deep reference Full CSS pipeline and override precedent: skill_css.md at the repo root, section 5.

Навык Aredel 5 — инструменты. Файл .claude/skills/aredel-tooling/SKILL.md. Скрипты, тесты и бэк-офис живут по другим правилам, чем страницы, поэтому у них свой короткий навык:

--- name: aredel-tooling description: "Aredel: Python and shell tooling in container/tools, tests in container/tests, the backoffice in backoffice-container" --- ## Use when User changes a script, a test, or backoffice code. ## Do not use for Pages and CSS under container/src (aredel-map, aredel-page, aredel-css). ## Workflow 1. Shell scripts: bump the `# version X.Y.Z` header on line 2 on every edit (pre-commit check-version); shellcheck runs in pre-commit. 2. Python targets 3.12. Gate with `pre-commit run --files <paths>` (ruff, ruff format, mypy, pylint with container/pyproject.toml). 3. Dependencies: add to the owning pyproject.toml, then `uv lock --project <dir>` and `uv sync --project <dir>`. Never pip install into a .venv; the next uv sync wipes it. 4. Tests: `cd container && ./tools/run-tests-venv.sh -- <tests> -q`; backoffice: `cd backoffice-container && .venv/bin/python -m pytest -q`. 5. A script that rewrites a file other code reads writes a temp file in the same directory and renames it (container/docs/atomic-file-writes.md). 6. Tree-wide rewrites read and write bytes so CRLF survives where HEAD has it. 7. Backoffice: blocking work goes in plain `def` endpoints (FastAPI runs them in a thread pool), never in `async def`. Restart backoffice-container/start.sh to rebuild the UI. ## Example Input: Add a --dry-run flag to container/tools/generate-sitemap.sh. Output: flag plus usage line, version header bumped, shellcheck and a dry run shown. ## Deep reference skill.md at the repo root, sections 1 and 4; container/tests/README.md; backoffice-container/README.md.

Навык Aredel 6 — проверка перед коммитом. Файл .claude/skills/aredel-verify/SKILL.md. Здесь показаны только триггер и порядок работы; в файле ещё есть согласование коммита, жизненный цикл плана коммита и аудит падений pre-commit:

--- name: aredel-verify description: "Aredel: finish or commit work: php -l, CLI render, venv tests, pre-commit failure audit, CRLF-safe commit" --- ## Use when User asks to commit, verify, or finish aredel work. ## Do not use for Content planning, new page scaffolds, CSS design. ## Workflow 1. Run php -l on touched files. Render touched pages via CLI shim with DOCUMENT_ROOT set to container/src, expect exit 0 and only REMOTE_ADDR noise. 2. Run container tests via `container/tools/run-tests-venv.sh -- <tests>` (from `container/`: `./tools/run-tests-venv.sh`), never pip install into managed venv. 3. For tree-wide edits preserve CRLF where HEAD has CR, run check-reflow gate without SKIP on final state. 4. Regenerate sitemap after page add or remove and show grep -c loc count. 5. On a failed pre-commit run: name the hook, audit its finding, retry with the narrowest fix. `SKIP=<hook-id>` disables one hook only after the audit below; every other gate must still run. Never bypass the whole suite with `git commit --no-verify`, `git -c core.hooksPath=/dev/null`, or an equivalent. If a hook environment is broken, repair it and rerun. 6. Python tooling must stay on 3.12. Run `python3 container/tools/linters/check_python_consistency.py --require-precommit` (the `check-python-consistency` pre-commit hook does this automatically) and the matching pytest guard before finishing.

Навык области — только статьи об ИИ. Файл .claude/skills/ai-style/SKILL.md. Он лежит вместе с остальными и ограничивает себя container/src/ai/ через своё описание. Прежняя вложенная копия в container/src/ai/.opencode/ лежала внутри докрута и уезжала на сайт вместе с ним:

--- name: ai-style description: "Aredel: AI articles under container/src/ai/ only: model names and prices, free-model links, cross-links between the agent guides" --- ## Use when The task edits or creates a page under container/src/ai/. ## Do not use for Any page outside container/src/ai/. ## Workflow 1. Model pricing tables carry a link to /ai/opencode/#verify-prices; never quote prices as eternal. 2. Prose never names a free model id: write "free OpenCode model" and link it to /ai/opencode/free_model/, the one page that names the current id and its fallbacks. Config examples use the current id from that page. 3. First mention per page or chapter links GPT 6 Luna to /ai/models/luna/, Claude Opus 5.5 to /ai/models/claude5_5/, Muse Spark 1.3 (paid) to /ai/models/muse_spark/. 4. OpenCode agent examples live on /ai/opencode/agents/ (#ex-triage, #ex-builder, #ex-reviewer, #ex-orchestrator); /ai/agents/ is the tool-agnostic overview. 5. External URLs use class exturl with rel nofollow. 6. No secrets, customer data, or private code to a free tier; route to a paid zero-retention model or a local model.

Корневая обвязка. Корневой AGENTS.md направляет каждую задачу к её навыкам и хранит несколько правил, нужных каждой задаче; процедуры несут навыки:

# Project instructions aredel is a PHP site: `container/src` is the docroot and a URL maps 1:1 to a file. Tools live in `container/tools`, tests in `container/tests`, the local dashboard in `backoffice-container`. Skills live in `.claude/skills/<name>/SKILL.md`; OpenCode and Claude Code both read them. ## Route the task | Task | Load these skills first | |---|---| | Edit or create anything under `container/src` | `aredel-map` | | New page, lesson, hub or course index | `aredel-page` + `aredel-blocks` | | Article body HTML | `aredel-blocks` | | CSS under `container/src/.css` | `aredel-css` | | Pages under `container/src/ai` | `ai-style` too | | `container/tools`, `container/tests`, `backoffice-container` | `aredel-tooling` | | Finish, verify or commit | `aredel-verify` | ## Always - Never commit without asking: finish verification, then ask whether to commit or hand over explicit-path `git add` / `git commit` commands. Never `git add -A`, never `--no-verify` or another hook bypass, never edit ignore files to hide untracked work (details: `aredel-verify`). - Bump the `# version X.Y.Z` header of every changed versioned file. - Python stays on 3.12; declare dependencies in `pyproject.toml` and lock with uv, never `pip install` into a uv-managed `.venv`. - Keep CRLF line endings where HEAD has them. - Regenerate the sitemap (`cd container && ./tools/generate-sitemap.sh`) only after adding or removing pages. - Articles written by an assistant credit `author: ['Arthur Isaev', '/about/arthur_isaev/']`. ## Agents - OpenCode: start it with `container/tools/ai/opencode.sh`, which checks that every pinned model id still exists first. Roles in `.opencode/agents/`: `triage` (read-only, free model), `builder` (edits, GPT 6 Luna), `reviewer` (read-only, Claude Opus 5.5; `/review`). - Claude Code: the same three roles in `.claude/agents/`.

Ограничивайте по роли только там, где это позволяет задача: triage видит лишь карту, builder и ревьюер на Opus видят все навыки, потому что роль, которая правит или судит PHP, обязана видеть правила для него. Полная конфигурация ролей — в разделе Трио Aredel.

Навыки и модели

Одно место, три стиля чтения. Подгоняйте длину и строгость под модель из раздела Модели, которые важны:

Практическое разделение из раздела Рабочие приёмы OpenCode: бесплатная модель OpenCode делает черновики с @test-writer, Luna гоняет рутинные миграции с @db-migrate, Opus делает финальный проход с @api-review. Никогда не отправляйте секреты на бесплатный тариф для участников — для чувствительного кода переходите на платную или локальную модель. Как три модели делят один репозиторий с видимостью по агентам, показано в разделе Три модели, один проект.

Ограничение навыков по агентам

Объявляйте каждый навык глобально, а потом ограничивайте по агенту. Побеждает последнее совпавшее правило. Пример: все видят навыки коммита и тестов, только ревьюер видит строгий навык ревью, а агенту explore нечего загружать. Всё это идёт в opencode.jsonc:

vi opencode.jsonc

{ "$schema": "https://opencode.ai/config.json", "permissions": [ { "action": "skill", "resource": "*", "effect": "allow" } ], "agents": { "reviewer": { "permissions": [ { "action": "skill", "resource": "*", "effect": "deny" }, { "action": "skill", "resource": "api-review", "effect": "allow" } ] }, "explore": { "permissions": [ { "action": "skill", "resource": "*", "effect": "deny" } ] } } }

Эффекты: allow загружает молча, ask показывает навык, но спрашивает перед загрузкой, deny прячет его от модели полностью. Блоки агентов добавляются после глобальных правил. Сторона агентов подробно разобрана в разделе «Как построить агента».

Два фильтра: обнаружение и разрешение

Чтобы навык загрузился, должны пройти два независимых фильтра, и отвечают они на разные вопросы. Обнаружение спрашивает где: объявлен ли навык для текущего рабочего каталога. Разрешение спрашивает кто: можно ли этому агенту его загружать. Нужны оба; если не прошёл хоть один, модель навык не увидит:

Обнаружен здесьРазрешение агентаЧто видит модель
даallowОбъявлен, загружается молча
даaskОбъявлен, спрашивает перед загрузкой
даdenyНевидим, как будто его нет
нетallowНевидим, разрешение никогда не срабатывает

Есть и третье состояние: обнаружен и зарегистрирован, но скрыт из объявленного списка через opencode/autoinvoke: false. Навык остаётся доступен для ручной загрузки через @skill-id. Используйте это только для помощников, которые подтягивает другой навык: скрытый навык никогда не предлагается той роли, которой он нужен. Навык aredel aredel-css был так скрыт и простоял без дела всю работу по CSS, поэтому теперь он объявляется снова.

Пример 1 — одно разрешение, разные каталоги. В монорепозитории builder может загружать web-style, который лежит в packages/web/.opencode/skills/. Правя веб-пакет, builder видит чек-лист и загружает его. Правя пакет API, он не видит навык: там он не объявлен, поэтому то же правило allow не срабатывает. Одна конфигурация разрешений, видимость зависит от расположения. Держите такие вложенные навыки вне каталогов, которые выкладываются: навык внутри докрута уезжает на сайт вместе с ним.

Пример 2 — один каталог, разные роли. В корне репозитория aredel обнаруживаются все семь навыков, но triage может загружать только aredel-map, а builder и ревьюер на Opus видят все навыки. Скрывайте навык от роли только тогда, когда роли он не нужен никогда: одна из прежних конфигураций aredel скрывала aredel-map от builder, который правит PHP, хотя AGENTS.md велел каждому агенту читать его первым. Одна полка, разная видимость по ролям — то же разделение, что в разделе Три модели, один проект.

Пример 3 — отладка пропавшего навыка. Агент должен знать навык, но не упоминает его: сначала проверьте обнаружение (не тот каталог, не то имя файла — нужен *.md в корне или ровно SKILL.md, frontmatter, который не разбирается как YAML), затем разрешение (deny ниже в объединённом списке побеждает), затем autoinvoke: false. В девяти случаях из десяти дело в первых двух.

Командный каталог по HTTP

Для навыков, общих для нескольких репозиториев, отдайте каталог по HTTP с index.json по базовому URL. Каждая запись перечисляет безопасные относительные файлы, обязательно включает SKILL.md или name.md, а версия поднимается, чтобы обновить кеши:

{ "skills": [ { "name": "deploy", "version": "3", "files": ["SKILL.md", "references/checklist.md"] } ] }

Зарегистрируйте его рядом с локальными каталогами в opencode.jsonc:

{ "$schema": "https://opencode.ai/config.json", "skills": ["./team-skills", "https://example.com/skills/"] }

Скачанные каталоги становятся корнями источников, поэтому deploy/SKILL.md сохраняет id deploy. Держите id в нижнем регистре и kebab-case, уникальными во всех источниках, иначе более поздние источники молча перекроют ранние.

Проверка и обмен

Проверяйте каждый новый навык тремя промптами до коммита. Пример для db-migrate:

Загружайте вручную через @skill-id, чтобы проверить текст, затем проверьте разрешение агента, которое его ограничивает. Делитесь обычными файлами рядом с кодом, которым они управляют, и ссылайтесь на них из командной документации — тот же принцип единственного входа, что и у агентов. Упомяните @db-migrate один раз вместо того, чтобы вставлять чек-лист в каждый промпт.

Проектирование триггеров

Триггеры — это половина навыка. Плохой блок триггеров срабатывает везде:

Use when: any database question.

Хороший блок триггеров срабатывает только на намерение плюс путь:

## Use when User mentions migration, migrates the DB, edits files under db/. ## Do not use for Plain SELECT questions, schema explainers, seed data design.

Называйте точные фразы, пути к файлам и контексты, при которых навык нужно загружать, и так же явно перечисляйте близкие случаи, где он должен молчать. Слишком широкие триггеры учат ассистента игнорировать навык целиком. Хорошие блоки называют каталог, глагол и два отрицания. Проверяйте отрицания — именно на них чаще всего и ломается.

Признаки поломки

Четыре признака говорят, что сломан навык, а не модель, и у каждого есть лечение:

Сначала лечите навык; большая модель лишь заставляет плохие инструкции ошибаться красноречивее. Когда для исправления нужна другая роль или набор инструментов, а не лучший текст, превратите навык в агента.

Автор статьи: Клавдия Кондакова