Предупреждающая наклейка — это не контроль
Большинство команд, развёртывающих кодирующего агента, начинают с одного и того же артефакта: системного промпта, который инструктирует модель не удалять файлы, не выносить секреты, не устанавливать недоверенные пакеты. Это предупреждающая наклейка. Это просьба, выраженная на естественном языке, к стохастической системе, на которую может повлиять любой прочитанный ею контент — README, postinstall-скрипт зависимости, стек-трейс, загруженный тред issue. Инструкция конкурирует с каждым другим токеном в контекстном окне.
Песочница исполнения не конкурирует. Это граница, обеспечиваемая ядром, средой выполнения контейнера и сетевым уровнем. Если агент не может писать вне /workspace, никакая инъекция в промпт не заставит его писать вне /workspace. Если egress запрещён по умолчанию, сгенерированный вызов curl завершится ошибкой на сокете, а не по усмотрению модели.
Именно поэтому контракт песочницы следует писать до того, как специфицирован агент. Возможности агента, его поверхность инструментов, уровень автономии — всё это производно от того, что допускает окружение. Спецификация агента в первую очередь порождает дизайн, под который песочнице затем приходится подстраиваться, а это неверное направление ограничения.
Где кодирующие агенты действительно причиняют вред
Вред от кодирующих агентов редко бывает драматичным. Обычно это одна из трёх заурядных категорий, каждая из которых является свойством окружения, а не свойством модели.
Доступ к файловой системе за пределами рабочего дерева
Агент, которому поручено отрефакторить модуль, может решить «прибраться» в соседней конфигурации, переписать lockfile или выйти в родительский каталог, чтобы разрешить импорт. Если контейнер монтирует домашний каталог разработчика или исходное дерево хоста, записываемое множество фактически неограничено. Отказ не в том, что модель выбрала плохо; а в том, что окружение предоставило выбор.
Доступ к учётным данным, унаследованный от окружения разработчика
Агенты, запущенные из оболочки разработчика, наследуют переменные окружения, файлы облачных учётных данных, сокеты SSH-агента и кэшированные токены. Долгоживущий облачный ключ в окружении — это постоянное предоставление всего, что этот ключ может делать. Агенту не нужно быть злонамеренным, чтобы злоупотребить им; ему достаточно выполнить команду, которая читает окружение и отправляет его куда-то, что является нормальным для инструментов сборки.
Эти три категории — не отказы модели. Это отказы конфигурации, и они устранимы до генерации хотя бы одного токена.
Спецификация контракта

Контракт песочницы состоит из трёх пунктов: что можно записывать, что можно читать и что может уходить.
Определите записываемое множество, читаемое множество и запретите всё остальное
Начинайте с запрета и перечисляйте разрешения. Рабочее значение по умолчанию для задачи кодирования выглядит так:
writable: /workspace/repo/**
readable: /workspace/repo/**, /usr/lib/**, /usr/share/**
denied: everything else
Репозиторий — единица работы. Всё вне его — либо системная зависимость, которая должна быть доступна только для чтения, либо ресурс хоста, который не должен быть виден вовсе. Это политика монтирования, а не инструкция в промпте, и она обеспечивается средой выполнения контейнера.
Компромисс реален: узкое записываемое множество ломает рабочие процессы, которым законно нужно трогать родительский каталог, соседний репозиторий или глобальный кэш. Команды, которым нужны такие процессы, должны намеренно расширять контракт и документировать почему, а не наследовать широкий контракт случайно. Расширение — это событие, подлежащее ревью; случайно широкое монтирование — нет.
Запретите egress по умолчанию и внесите реестры и эндпоинты в allowlist
Сетевая политика должна зеркалить политику файловой системы. По умолчанию — никаких исходящих соединений. Allowlist явный и небольшой: реестр пакетов, который проект действительно использует, эндпоинт провайдера модели, если агент его вызывает, и любой внутренний сервис, необходимый задаче.
egress: deny
allow: registry.npmjs.org
allow: api.internal.example
Это одновременно ограничивает путь установки и путь сгенерированного кода. Это также делает сетевое поведение агента наблюдаемым: любая попытка соединения вне allowlist — это сигнал, а не шум.
Честный компромисс — операционное трение. Легитимным сборкам иногда нужен эндпоинт, который не был предусмотрен, и режим отказа — заблокированный запрос, выглядящий как временная ошибка. Allowlist должен рассматриваться как конфигурация под контролем версий, ревьюиться как код и обновляться, когда задача законно этого требует, — а не ослабляться до allow: * из-за одной неудачной сборки.
Запускайте с эфемерными учётными данными, ограниченными задачей
Учётные данные должны выпускаться для задачи и истекать вместе с ней. Ограниченный, короткоживущий токен, выданный при старте песочницы и отозванный при её завершении, ограничивает ценность любого выноса. Собственные долгоживущие учётные данные разработчика никогда не должны попадать в песочницу; агент не должен иметь возможности действовать как разработчик за пределами границы задачи.
Этот пункт часто труднее всего реализовать, потому что он требует системы идентификации, способной выдавать узкие, короткоживущие разрешения. Там, где такой системы нет, запасной вариант — запускать агента вообще без учётных данных и направлять любую привилегированную операцию через отдельный шаг с одобрением человеком.

Обнаружение и реагирование
Контракт определяет границу. Обнаружение сообщает вам, когда что-то давит на неё, а реагирование определяет, что происходит дальше.
Рассматривайте аномальные паттерны системных вызовов как первичный сигнал
Инспекция промптов ненадёжна. Одна и та же инструкция может быть безобидной в одном контексте и частью инъекции в другом, а собственное описание моделью своих намерений не является доказательством её поведения. Надёжный сигнал — это то, что процесс фактически делает: неожиданные вызовы open вне читаемого множества, попытки connect к адресам вне allowlist, execve оболочек или интерпретаторов, отсутствующих в профиле задачи, необычная активность файловых дескрипторов.
Всё это наблюдаемо на уровне среды выполнения без инспекции рассуждений модели. Монитор на уровне системных вызовов может оповещать об отклонении от базового профиля задачи, и он не зависит от того, говорит ли агент правду о том, что делает.
Логируйте diff и историю команд вместе
Ревью постфактум требует обоих артефактов в одном месте. Diff без команд, которые его произвели, трудно атрибутировать; история команд без результирующего diff трудна для оценки. Хранение их вместе — команда, временная метка, код выхода, результирующий diff — делает возможным ревью постфактум и позволяет восстановить, что делал агент, когда тест падает спустя дни.
Это вопрос логирования, а не вопрос модели, и он должен быть специфицирован в контракте наряду с правилами монтирования и egress.
Требуйте одобрения человеком для необратимых операций вне песочницы
Некоторые операции нельзя отменить, откатив рабочее дерево: push в удалённый репозиторий, публикация пакета, удаление облачного ресурса, отправка письма, слияние pull request. Они должны быть закрыты шлюзом. Шлюз — это не инструкция в промпте «спроси перед push»; это политика, которая удаляет учётные данные или сетевой маршрут, необходимые для операции, пока человек не предоставит их для конкретного действия.
Порядок спецификации
Практическое следствие — изменение порядка работы. Прежде чем специфицировать инструменты агента, его память, его цикл планирования или уровень автономии, специфицируйте окружение, в котором он работает: записываемое множество, читаемое множество, allowlist egress, область действия учётных данных, монитор системных вызовов, объединённый лог diff и команд и шлюз одобрения для необратимых операций вне песочницы.
Затем агент проектируется относительно известной границы. Его возможности — это пересечение того, что может делать модель, и того, что допускает песочница, что является меньшей и более честной поверхностью, чем предупреждающая наклейка в системном промпте.
Компромисс в том, что жёсткий контракт будет иногда блокировать легитимную задачу, и команде придётся намеренно его расширять. В этом и суть. Граница, которую никогда не проверяют, — не граница; граница, которую расширяют через ревью, — это граница, которую понимают.
