Amiga
Оглавление курса · урок 14 из 24

Модуль 3 · Датчики и ограничения · урок 14 из 24

Изолированные окружения на каждую задачу

Git worktree решает только половину задачи параллельной работы: у каждого агента свои файлы. Но если все агенты стучатся в один и тот же контейнер на порту 8001, одну базу и один кэш, их проверки смешиваются, и зелёный прогон перестаёт что-либо значить. Этот урок — о полном окружении на задачу: что в него входит, как его поднять за минуту и как не забыть его убрать.

Что говорят источники

Все источники трека сходятся в одном: параллельную работу надо изолировать.

  • В эксперименте OpenAI (Harness engineering) приложение поднимается на каждый git worktree, и к каждому привязан свой эфемерный стек наблюдаемости, который удаляется после задачи.
  • В спецификации Symphony у каждой задачи из трекера свой workspace, и агент обязан работать только внутри него — это первый инвариант безопасности спецификации.
  • Anthropic в схеме для длинных задач даёт агенту init.sh, который поднимает dev-сервер, чтобы тот не тратил время на выяснение, как запустить приложение.
  • В лучших практиках Codex параллельные задачи на одних и тех же файлах без worktree названы антипаттерном.

Наш вывод. Изоляция — это не только про безопасность, но и про достоверность сигнала. Тест, который прошёл на чужой базе, ничего не доказывает.

Что именно изолировать

Ресурс Что будет без изоляции Как развести
Файлы правки агентов затирают друг друга git worktree на задачу
Порты второй стенд не стартует или агент смотрит на чужой порт из хэша пути worktree
База данных миграции одной ветки ломают другую своя БД из фикстур на стенд
Кэши, очереди, сессии «призрачные» баги из чужого состояния отдельный префикс или свой Redis
Сборка фронта артефакты одной ветки в другой public/build внутри worktree
Браузерный профиль куки и localStorage переносятся новый контекст на каждый прогон
Секреты лишние права у агента только тестовые ключи, минимум
Логи и метрики наблюдения смешиваются файл логов внутри стенда

Знакомая ситуация в агентстве: основной стенд проекта смонтирован на основную рабочую копию, и правки в worktree он просто не видит — агент проверяет старый код и честно докладывает, что всё работает. Лечится только своим стендом на worktree.

Что даёт Codex

Managed worktrees в ChatGPT desktop app. Codex создаёт worktree в $CODEX_HOME/worktrees от HEAD выбранной ветки в состоянии detached HEAD, поэтому может сделать несколько штук, не плодя веток. Игнорируемые git файлы, нужные для запуска (.env, локальные конфиги), перечисляются в .worktreeinclude в корне репозитория; игнорируемый AGENTS.override.md копируется автоматически. По умолчанию хранятся 15 последних worktree, перед удалением делается снимок. Подробности для повседневной работы — в уроке о worktree.

Local environments. Там же можно задать setup-скрипт, который выполняется при создании нового worktree (установка зависимостей, сборка), и действия — частые команды вроде запуска dev-сервера. Настройки хранятся в папке .codex проекта, её можно закоммитить.

CLI. Флаг --worktree и команда /worktree начинают или продолжают работу в managed worktree; у codex exec fork тоже есть --worktree. Актуальный набор флагов проверьте в codex --help.

Облако. В Codex Cloud окружение описывается install-скриптом и start-навыком, публикуется, и каждая задача получает изолированную копию подготовленной файловой системы. Секреты можно передать как network secrets: процесс видит заглушку, а реальное значение подставляет прокси только для разрешённых доменов. Это урок об облачных окружениях.

Чего Codex за вас не сделает: не поднимет вашу базу, не разведёт порты и не уберёт контейнеры. Это ваша часть обвязки.

Стенд на worktree за один скрипт

Минимальная схема для проекта на docker compose: имя проекта и порт вычисляются из пути worktree, поэтому каждый стенд получает свои контейнеры, тома и порт, а повторный запуск попадает в тот же стенд.

yaml · docker-compose.yml
services:
  app:
    build: .
    ports:
      - "${APP_PORT:-8001}:80"
    environment:
      DB_HOST: db
      DB_DATABASE: site
      DB_USERNAME: root
      DB_PASSWORD: local-only
    volumes:
      - ./src:/var/www/html
    depends_on:
      db:
        condition: service_healthy
  db:
    image: mysql:8.4
    environment:
      MYSQL_DATABASE: site
      MYSQL_ROOT_PASSWORD: local-only
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-plocal-only"]
      interval: 3s
      retries: 30
    volumes:
      - db:/var/lib/mysql
volumes:
  db:
bash · scripts/env/up.sh
#!/usr/bin/env bash
# Поднимает стенд для текущего worktree и печатает его адрес.
set -euo pipefail
root=$(git rev-parse --show-toplevel)
hash=$(printf '%s' "$root" | cksum | cut -d' ' -f1)
export COMPOSE_PROJECT_NAME="site-$(basename "$root" | tr -c 'a-z0-9\n' '-')"
export APP_PORT=$((8100 + hash % 800))

dc=(docker compose -f "$root/docker-compose.yml")

"${dc[@]}" up -d --build --wait
"${dc[@]}" exec -T app php artisan october:migrate
"${dc[@]}" exec -T app php artisan db:seed --class=AgentFixtureSeeder

echo "{\"project\": \"$COMPOSE_PROJECT_NAME\", \"url\": \"http://localhost:$APP_PORT\"}"
bash · scripts/env/down.sh
#!/usr/bin/env bash
set -euo pipefail
root=$(git rev-parse --show-toplevel)
export COMPOSE_PROJECT_NAME="site-$(basename "$root" | tr -c 'a-z0-9\n' '-')"
docker compose -f "$root/docker-compose.yml" down --volumes --remove-orphans

Имя сидера и команды миграции подставьте свои. Healthcheck у базы нужен, чтобы up --wait дождался её готовности: без него миграции на первом запуске падают. Обратите внимание на последнюю строку up.sh: скрипт печатает адрес в машиночитаемом виде, и агент сразу знает, куда идти браузером. Строка в AGENTS.md замыкает петлю: «перед проверкой в браузере запусти scripts/env/up.sh и используй адрес из его вывода; по окончании — scripts/env/down.sh».

Коллизии портов при таком хэше возможны; при десятке одновременных стендов проще хранить выданные порты в файле или спрашивать у системы свободный порт.

База: фикстуры, а не дамп

Соблазн поднять стенд из свежего дампа прода понятен — «там же реальные данные». Против — три довода: персональные данные клиентов в контексте агента, размер дампа и время развёртывания, недетерминированность проверок. Лучше набор фикстур, который покрывает типовые сущности и известные пограничные случаи, плюс сидер, который агент может расширять при работе над задачей. Это заодно и тестовые данные для e2e.

Жизненный цикл

У окружения четыре фазы, и Symphony задаёт для них хуки: after_create, before_run, after_run, before_remove, по умолчанию с таймаутом 60 секунд. Даже если вы не используете Symphony, полезно думать этими же фазами:

  1. Создание — worktree, .worktreeinclude, установка зависимостей.
  2. Перед запуском агента — стенд поднят, миграции и фикстуры применены, адрес известен.
  3. После прогона — собраны артефакты: скриншоты, отчёт тестов, логи.
  4. Перед удалением — контейнеры и тома остановлены и удалены.

Четвёртую фазу забывают чаще всего. Через неделю параллельной работы на машине разработчика оказываются десятки забытых стендов с базами.

Модель доверия

Спецификация Symphony не навязывает политику песочницы и одобрений, но требует, чтобы каждая реализация явно описала свою модель доверия. Это правильная планка и для своих схем. Ответьте письменно: какие команды агент выполняет без вопросов, есть ли у него сеть, какие секреты ему доступны, что он может сломать за пределами worktree.

Одна практическая тонкость: вложенная песочница Codex внутри Docker может не работать. Для такого случая документация советует изолировать агента контейнером (например, Dev Container) и внутри запускать с --sandbox danger-full-access — граница безопасности тогда проходит по контейнеру, и проектировать её нужно соответственно.

Мобильная разработка

Для мобайла роль стенда играет симулятор или эмулятор. Несколько агентов на одном симуляторе мешают друг другу так же, как на одной базе. Варианты: отдельное устройство на агента (xcrun simctl clone для iOS, отдельный AVD или запуск эмулятора с -read-only для Android), мок-сервер API на своём порту из того же хэша, сборка в собственный каталог derived data внутри worktree.

Попробуйте сами

10–15 мин на рабочем месте
  1. Посчитайте по таблице из урока, какие ресурсы в вашем проекте общие для всех рабочих копий. Выберите самый опасный.
  2. Напишите up.sh и down.sh для своего проекта по образцу выше, поднимите два стенда из двух worktree одновременно и убедитесь, что они не видят данных друг друга.
  3. Создайте .worktreeinclude с файлами, без которых проект не стартует, и добавьте в AGENTS.md две строки о том, как агенту поднимать и убирать стенд.

Коротко

  • Worktree изолирует файлы; порты, база, кэши и логи требуют своей обвязки.
  • Тест на общем окружении не доказывает ничего о вашей ветке.
  • Codex даёт managed worktrees, .worktreeinclude, setup-скрипты и облачные окружения; стенд и его уборку делаете вы.
  • База стенда — из фикстур, а не из продового дампа.
  • Опишите модель доверия письменно и не забывайте фазу удаления.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX