---
pr: 63
title: fix(agents+skills): enforce tool-usage policy across prompts and skills
---

## Что сделано

- **AGENTS.md** — добавлена секция `## Tool Usage Policy` с таблицей 10 tools
  (commit, create_pr, create_issue, merge_pr, post_review, post_docs_review,
  pipeline_status, spec_status, memory_setup, tunnel). Колонки: имя tool |
  raw-эквивалент (заблокирован deny) | когда использовать | при сбое — STOP,
  репорт, НЕ fallback. Правило: "Используй tool вместо raw bash. Raw bash
  заблокирован deny (`opencode.json:311-314`). При сбое tool — STOP и репорт
  оркестратору, НЕ fallback на raw bash, НЕ импровизируй обход через `gh api`."
  Global copy `/root/.config/opencode/AGENTS.md` — bind-mount read-only из
  workspace `AGENTS.md`, обновится после merge + хост `git pull` + рестарт
  контейнера (см. ADR-026 Решение).
- **6 skills** — raw bash заменён на tool-вызовы:
  - `run-pipeline/SKILL.md` Template A: `git commit` → `commit({ message })`,
    `gh pr create` → `create_pr({ title, body, issue_number })`
  - `run-pipeline/SKILL.md` Template B: `git commit` → `commit({ message })`
    (`git add` и `git push` оставлены — не заблокированы)
  - `run-pipeline/SKILL.md` Template D: `git commit` → `commit({ message: "fix(ci): ..." })`
  - `issue/SKILL.md`: `gh issue create` → `create_issue({ title, body, labels })`
    (3 места), `gh pr merge` → `merge_pr({ pr_number })`
  - `spec/SKILL.md:311`: `gh issue create` → `create_issue({ title, body, labels })`
  - `release/SKILL.md:44`, `add-skill/SKILL.md:70`, `repo-init/SKILL.md:41`:
    `git commit` → `commit({ message })`
- **Skill `tunnel` восстановлен** — `.opencode/skills/tunnel/SKILL.md` (удалён
  в PR#42 как orphan; tool `tunnel` остался без skill-описания, пользователь
  вызывал вручную, но агент не "видел" его в контексте). Frontmatter: name:
  tunnel, description: "Подними cloudflare туннель когда пользователь просит
  'подними тоннель', 'пробрось порт', 'tunnel'". Тело: инструкция вызывать
  tool `tunnel()` (1-й вызов — start, 2-й — stop, беспараметровый).

## Почему

Research (subagent explore) выявил 3 gap'а в tool-usage инфраструктуре:

- **Gap A**: 6 skills предписывали raw bash (`git commit`, `gh pr create`,
  `gh issue create`, `gh pr merge`), заблокированный deny в
  `opencode.json:311-314`. Симптом: subagent грузит skill → получает
  инструкцию нарушить permission layer → падает или импровизирует обход через
  `gh api` (см. memory `technical/gh-issue-create-blocked-workaround.md`).
- **Gap B**: Tool failure handling ("при сбое tool — STOP, не fallback на raw
  bash") был только для 2 из 10 tools — `post_review` (reviewer.md:285) и
  `post_docs_review` (docs-reviewer.md:228). Для остальных 8 tools при сбое
  agent без инструкции, импровизирует.
- **Gap C**: 4 tool'а не упомянуты нигде как tool — `create_issue`,
  `create_pr` (0 упоминаний), `tunnel` (skill удалён в PR#42, tool orphan),
  `memory_setup` (1 строка в `memory/SKILL.md:19`).

Дополнительно: `gh pr comment*` остался в allow-list reviewer/docs-reviewer
(ADR-019 отклонил strict-deny "для обратной совместимости"). Решено оставить
как есть — промпт уже запрещает fallback при сбое tool, противоречие minimal.

## Pending

- После merge: на хосте `git pull` + рестарт opencode-контейнера чтобы global
  config подхватил обновлённый `AGENTS.md` (bind-mount read-only) и
  восстановленный skill `tunnel` (авто-дискаверится при старте).
- Зависимости: supersedes partial PR#42 (orchestration-switch) — Watch out в
  handoff pr-42 явно пишет "Третий PR серии: обновить промпты
  reviewer.md/memory-syncer.md/skills"; related PR#61 (issue #60) добавил
  "Tool failure handling" в reviewer.md/docs-reviewer.md для
  post_review/post_docs_review — этот PR расширяет на все 10 tools через
  единую policy в AGENTS.md.

## Watch out

- `/root/.config/opencode/AGENTS.md` — bind-mount read-only из
  `/dev/vda1[/root/dockers/opencode-config/AGENTS.md]` (compose:
  `./AGENTS.md:/root/.config/opencode/AGENTS.md:ro`). В контейнере файл НЕ
  редактируется — изменения идут в workspace copy, после merge +
  host git pull + container restart подхватятся автоматически. Это
  symlink-эквивалент через bind-mount (issue предусматривал оба варианта).
- Skill `tunnel` станет доступен только после рестарта opencode (skills
  загружаются при старте, см. add-skill/SKILL.md секция 3).
- `gh pr comment*` в allow-list reviewer/docs-reviewer НЕ трогали — это
  intentional (ADR-019), не regression.
- 7 оставшихся упоминаний `gh pr create|git commit -m|gh issue create|gh pr merge`
  в skills — это anti-instructions (упоминания в контексте "НЕ raw bash") и
  examples в permission-rules docs (`configure-opencode/SKILL.md:89`), не
  предписания. Grep на raw patterns нужно фильтровать по контексту.
- Ветка создана от `main` (не `master` — master не существует в этом репо).
  Issue говорил "от master" — это соглашение naming, фактически main.