Окружение облачного агента - это описание того, как из пустой машины получить рабочий проект. Cursor ищет его по порядку: сначала файл в репозитории, затем сохранённое личное окружение, затем командное. Такой порядок разумен: репозиторий - самое конкретное и самое проверяемое место, потому что его видно в ревью и оно едет вместе с кодом. Личное окружение при этом остаётся полезным черновиком, но пока описание живёт только у автора, воспроизводимости у команды нет.
Есть два пути подготовки. Рекомендуемый - дать агенту собрать окружение самому по описанию проекта. Продвинутый - собственный образ через файл сборки. Второй нужен, когда у проекта тяжёлые системные зависимости или жёсткие требования к версиям инструментов. Типичная ошибка при этом - копировать в образ весь проект: код всё равно будет получен заново на нужном коммите, а образ нужен для окружения, а не для исходников. Побочный эффект такой ошибки заметен не сразу - образ перестраивается на каждое изменение кода, и подготовка машины из быстрой становится долгой.
Полезно один раз увидеть цельное описание. Ниже - блок сборки с файлом образа и контекстом, команда установки зависимостей и генерации кода и команда запуска сервисов. Три поля - три разные роли, и путать их не стоит: установка готовит состояние диска, запуск поднимает процессы, сборка задаёт базовый образ. Проверить, что роли не перепутаны, просто: спросите про каждую строку, переживёт ли её результат выключение машины.
Главное требование к команде установки - идемпотентность. Она выполняется при создании сборки и должна давать один и тот же результат при повторном запуске. Сюда входят зависимости, генерация кода, компиляция и прогрев кэшей. Долгоживущие сервисы сюда не входят: их место в запуске или в терминалах, потому что сборка сохраняет состояние диска, но не сохраняет процессы, экспортированные переменные и содержимое памяти.
Это различение объясняет самый частый провал первой облачной задачи. Разработчик поднимает сервер в установочной команде, сборка успешно завершается, а агент потом не может достучаться до сервиса - процесс не пережил границу этапов. Симптом выглядит загадочно, причина проста: сохраняется диск, а не запущенное. То же правило объясняет и вторую по частоте загадку - переменную, экспортированную в установке и исчезнувшую к моменту работы агента.
Окружение может клонировать несколько связанных репозиториев сразу, и это открывает согласованные изменения через границы проектов. Но группу держат минимальной осознанно: каждый дополнительный репозиторий расширяет контекст, добавляет учётные данные и увеличивает радиус поражения при ошибке. Три репозитория в группе - это три источника недоверенного содержимого, а не только три источника кода.
Из правила про диск следует практический приём, который окупается быстрее всего. Всё, что можно сделать один раз и оставить на диске, переносят в установку: зависимости, сгенерированный код, скомпилированные артефакты, прогретые кэши сборщика и тестового прогона. Каждая такая минута экономится не однажды, а на каждом запуске агента поверх этой сборки, а запусков за жизнь одной сборки бывает много. Обратное тоже верно: тяжёлая установка, которую пересобирают на каждое изменение описания, съедает выигрыш, поэтому редко меняющиеся системные части держат в образе, а часто меняющиеся - в установке.
У такого описания есть граница, о которую спотыкаются при первой же попытке подключить внешний сервис. Идемпотентность гарантируется только для того, что вы контролируете: команда, которая тянет пакеты без фиксации версий или дёргает сторонний адрес, воспроизводима ровно до тех пор, пока внешний мир не изменился. Признак, по которому в реальной работе это ловят, - сборка, падающая без единого изменения в репозитории, или, что хуже, собирающаяся успешно, но дающая другое поведение. Лечится это не отладкой агента, а фиксацией версий и переносом внешних зависимостей в образ, где они превращаются в осознанно обновляемый слой.
Инженерный вывод простой: облачное окружение - это инфраструктурный код, и относиться к нему нужно как к коду. Оно версионируется вместе с проектом, ревьюится, проверяется на воспроизводимость и должно уметь собираться с нуля. Окружение, которое собирается только с третьего раза и только у автора, не годится для автономной работы независимо от качества модели.
Типичные провалы предсказуемы. Запустить долгоживущий сервис в установочной команде и потерять его. Скопировать в образ весь проект вместо окружения. Сделать установку неидемпотентной и получить разные сборки из одного описания. Оставить внешние зависимости без фиксации версий. И собрать в одну группу больше репозиториев, чем нужно задаче.
// .cursor/environment.json
{
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"install": "pnpm install && pnpm run codegen",
"start": "pnpm run dev"
}
// установка идемпотентна; долгоживущие сервисы - в start, а не в install