* fix(agents): add tool usage policy to AGENTS.md * fix(skills): replace raw bash with tools in 6 skills * feat(skills): restore tunnel skill * docs(handoff): scaffold handoff and ADR for PR * docs(handoff): set PR number * docs(project-map): add tunnel skill + tool usage policy note (PR#63) --------- Co-authored-by: opencode-agent <agent@opencode.local>
7.1 KiB
ADR-026: Enforce tool-usage policy across prompts and skills
Статус
Accepted (2026-07-25)
Контекст
Research (subagent explore) выявил 3 gap'а в tool-usage инфраструктуре репо
slaid098/opencode-config:
Gap A: Skills предписывают raw bash, заблокированный deny-правилами
6 skill-файлов предписывали subagent'ам raw bash команды, которые глобально
заблокированы в opencode.json:311-314 (4 deny-правила: git commit *,
gh pr create *, gh pr merge *, gh issue create *):
run-pipeline/SKILL.mdTemplate A:gh pr create,git commitrun-pipeline/SKILL.mdTemplate B/D:git commitissue/SKILL.md:83,127:gh issue create;:154:gh pr mergespec/SKILL.md:311:gh issue createrelease/SKILL.md:44,add-skill/SKILL.md:70,repo-init/SKILL.md:41:git commit
Симптом: subagent грузит skill → получает инструкцию нарушить permission
layer → падает (deny блокирует bash) или импровизирует обход через gh api
(см. memory technical/gh-issue-create-blocked-workaround.md — gh api repos/*/issues allow-rule существует, но использование его для создания
issue обходит валидацию тулзы и ломает формат репо).
Gap B: Tool failure handling только для 2 из 10 tools
Секция "Tool failure handling" (инструкция "при сбое tool — STOP, не fallback
на raw bash") была только для post_review (reviewer.md:285) и
post_docs_review (docs-reviewer.md:228). Для commit, create_pr,
create_issue, merge_pr, pipeline_status, spec_status, memory_setup,
tunnel — отсутствует. При сбое agent без инструкции, импровизирует.
Gap C: 4 tool'а не упомянуты нигде как tool
create_issue,create_pr— 0 упоминаний как tool в промптах/skills (только rawgh issue create/gh pr createв skills, заблокированные deny)tunnel— skill удалён в PR#42 (orchestration-switch), tool остался orphan (0 упоминаний как tool; пользователь использует вручную, но агент не "видит" его в контексте)memory_setup— 1 строка вmemory/SKILL.md:19, в промптах агентов нет
Дополнительно
gh pr comment* остался в allow-list reviewer/docs-reviewer (ADR-019
отклонил strict-deny "для обратной совместимости"). Решено: оставить в allow
(промпт уже запрещает fallback при сбое tool, противоречие minimal).
Решение
1. AGENTS.md: единая Tool Usage Policy секция
В AGENTS.md добавлена секция ## Tool Usage Policy с таблицей всех 10
tools. Колонки: имя tool | raw-эквивалент (заблокирован deny) | когда
использовать | при сбое — STOP, репорт, НЕ fallback. Правило: "Используй tool
вместо raw bash. Raw bash-эквиваленты заблокированы deny
(opencode.json:311-314). При сбое tool — STOP и репорт оркестратору, НЕ
fallback на raw bash, НЕ импровизируй обход через gh api."
Это устраняет Gap B (единая policy для всех 10 tools вместо per-tool инструкций) и Gap C (4 tool'а теперь упомянуты как tool в едином месте).
Global copy /root/.config/opencode/AGENTS.md — bind-mount read-only из
workspace AGENTS.md (compose: ./AGENTS.md:/root/.config/opencode/AGENTS.md:ro).
В контейнере файл не редактируется; изменения идут в workspace copy, после
merge + host git pull + container restart подхватываются автоматически. Это
symlink-эквивалент через bind-mount.
2. 6 skills: raw bash → tool-вызовы
Все предписания raw bash в 6 skills заменены на tool-вызовы (см. handoff "Что
сделано" для полного списка). git add и git push оставлены — они не
заблокированы deny. Anti-instructions (упоминания "НЕ raw bash") сохранены
как документация.
3. Skill tunnel восстановлен
Создан .opencode/skills/tunnel/SKILL.md (удалён в PR#42, tool остался
orphan). Frontmatter: name: tunnel, description с триггерами "подними
тоннель"/"пробрось порт"/"tunnel". Тело: инструкция вызывать tool tunnel()
(1-й вызов — start, 2-й — stop, беспараметровый). Skill станет доступен
после рестарта opencode (skills загружаются при старте).
4. gh pr comment* оставлен в allow-list
Не трогали — intentional (ADR-019). Промпт уже запрещает fallback при сбое
tool (post_review/post_docs_review), противоречие minimal. strict-deny
gh pr comment* отклонён (см. Альтернативы).
Альтернативы
-
Per-agent промпты: добавить tool failure handling в каждый agent.md по отдельности — отклонено из-за дублирования. 4 agent-файла × 10 tools = 40 упоминаний, дрейф при добавлении новых tools. Единая policy в AGENTS.md (грузится всеми агентами) — canonical источник, добавление нового tool = 1 строка в таблице.
-
strict-deny
gh pr comment*(принудить кpost_review/post_docs_review) — отклонено (повторяет ADR-019).gh pr comment*остаётся в allow-list для обратной совместимости; tools используют spawnSync напрямую (не через bash permission layer), rawgh pr comment*не конфликтует. Промпт уже запрещает fallback при сбое tool — этого достаточно. -
Упомянуть 4 orphan tool'а (Gap C) в per-agent промптах — отклонено по той же причине дублирования. Единая таблица в AGENTS.md покрывает все 10 tools одним источником правды.
-
Удалить skill
tunnelсовсем (tool orphan → удалить tool) — отклонено: tooltunnelиспользуется пользователем вручную и в pipeline (tunnel.sh scaffold). Восстановление skill даёт агенту контекст для вызова tool'а по триггерам пользователя.