Permission profile объединяет границы файловой системы и сети в именованный переиспользуемый пресет. Вместо того чтобы каждый раз вручную решать, что агенту можно читать, писать и куда ходить по сети, вы описываете это один раз как профиль и применяете к сессии или задаче. Встроенные профили - :read-only, :workspace и :danger-full-access - покрывают частые случаи, а свои объявляют в секции [permissions.<name>] и выбирают через default_permissions или picker разрешений.
Файловая часть профиля строится на специальных корнях, и их семантику нужно знать. :minimal, :workspace_roots, :tmpdir и :slash_tmp - это не произвольные пути, а именованные области с определённым смыслом. Внутри профиля им и конкретным путям назначают уровень: read, write или deny. Ключевое правило приоритета простое и его нельзя обойти по невнимательности: deny выигрывает. Широкий write не отменяет узкий deny, поэтому запрет на чувствительное остаётся, даже если рядом разрешена запись.
Полезно один раз увидеть осмысленный профиль редактирования проекта целиком. Ниже - фрагмент: минимальный доступ на чтение, запись в рабочих корнях, но явный deny на любые .env, и выключенная сеть. Читается он как явное описание рабочих границ, а не как набор случайных строк. К этой форме возвращаются, задавая политику под контекст: профиль отвечает на вопрос "что агенту вообще позволено тронуть в этой роли", а не решает это заново на каждом действии.
Сетевая часть профиля устроена не менее строго, и в ней легко ошибиться на семантике доменов. Сеть включают явно, а затем перечисляют домены с решением allow или deny. Важно: точный хост совпадает только сам с собой, *.example.com покрывает поддомены вроде api.example.com, но НЕ сам example.com, а **.example.com берёт и apex, и поддомены. Разница именно в apex, а не в глубине вложенности - и на ней ошибаются чаще всего. Глобальный * разрешает любой публичный хост и допустим только в allow-правилах. Как и в файловой части, deny выигрывает, поэтому запрет на нежелательный домен держится, даже если рядом разрешён более широкий шаблон.
Полезно один раз увидеть и сетевой фрагмент профиля. Ниже - включённая сеть с узким allowlist документационных доменов и явным deny на нежелательный. К этой форме возвращаются, когда задача действительно требует сети: её открывают не целиком, а точечно, под конкретные хосты. Разница между "включил сеть" и "включил сеть к этим двум доменам" - это разница между широкой поверхностью риска и узкой, контролируемой границей, которую можно объяснить в ревью.
Есть тонкости, о которых легко забыть, а они меняют реальную границу. Локальные и приватные цели блокируются отдельно - это защита от обращений внутрь вашей сети, которую не стоит обходить бездумно. Unix-сокеты вроде Docker-сокета - это тоже канал воздействия, а не безобидный файл: доступ к нему фактически даёт управление контейнерами. Профиль полезен ровно настолько, насколько вы понимаете, что каждая его строка на самом деле открывает, а не только что она разрешает на словах.
Смысл профилей - в переиспользовании осознанной политики, а не в удобстве копирования. Именованный пресет позволяет применить одну и ту же проверенную границу к множеству задач и объяснить её в ревью как единое целое. Но копировать чужой профиль механически опасно: он разрешает именно те пути и хосты, что были нужны другому проекту. Профиль - это шаблон структуры, который наполняют своими значениями, понимая цену каждой строки, а не готовый allowlist на все случаи.
Типичные провалы вокруг профилей предсказуемы. Понадеяться, что широкий write перекроет забытый deny, - хотя deny выигрывает всегда. Написать *.example.com и удивиться, что сам example.com закрыт, или взять **, открыв заодно apex. Включить сеть целиком вместо узкого allowlist доменов. И недооценить Unix-сокет как канал воздействия. Стройте профиль как явное описание границ, помните, что deny сильнее allow, открывайте сеть точечно и понимайте, что каждая строка реально открывает.
default_permissions = "project-edit"
[permissions.project-edit.filesystem]
":minimal" = "read"
[permissions.project-edit.filesystem.":workspace_roots"]
"." = "write"
"**/*.env" = "deny" # deny выигрывает над write
[permissions.project-edit.network]
enabled = false
# специальные roots: :minimal, :workspace_roots, :tmpdir, :slash_tmp[permissions.docs-check.network]
enabled = true
[permissions.docs-check.network.domains]
"developers.openai.com" = "allow"
"learn.chatgpt.com" = "allow"
"ads.example.com" = "deny"
# точный хост - только он сам; *.example.com - поддомены, БЕЗ example.com;
# **.example.com - apex и поддомены; глобальный * - только в allow; deny выигрывает
# local/private targets блокируются отдельно; Unix sockets (Docker) - канал воздействия