Некоторое время назад мое приложение зависло посреди тренировки в спортзале. Я загрузил отчет о сбое, предоставил своему ИИ-агенту некоторую информацию и вернулся к своему подходу. К тому времени, как я закончил, меня уже ждал запрос на слияние. Я его проверил, объединил, и вскоре после этого у меня на устройстве появилась исправленная сборка TestFlight — все это даже не открывая Xcode.
Такой поворот событий стал возможен только благодаря построенной мной системе разработки на основе агентного подхода. Именно об этом и пойдет речь в этой статье. Знайте, что этот пост не представляет ничего революционного в плане моей работы. Но эта система хорошо работает для меня, и я думаю, что в наше время важно, чтобы люди получали представление о том, что делают другие, вместо того, чтобы видеть очередные посты типа «Я выпускаю тонны кода с ИИ».
Я надеюсь быть немного более сбалансированным…
Агентный подход (или, как его еще называют, «вайб-кодинг») становится все популярнее с каждым днем. Все больше разработчиков позволяют ИИ-агентам обрабатывать значительную часть своих iOS-проектов, и, честно говоря, я понимаю это. Это невероятно продуктивно. Но это сопряжено с реальным риском: когда вы передаете разработку кода агенту, качество и архитектура могут быстро ухудшиться, если у вас нет надлежащих механизмов защиты.
В этом посте я хочу рассказать вам о конвейере, который я использую, чтобы, несмотря на использование агентного подхода к разработке, качество моего продукта оставалось на высоком уровне (да, это включает в себя чтение кода и иногда ручную корректировку).
Мы рассмотрим настройку локальной среды, почему важен режим планирования, автоматизированные проверки запросов на слияние с помощью BugBot от Cursor, запуск сборок и тестов CI с помощью Bitrise, а также волшебство почти мгновенной загрузки сборок TestFlight на ваше устройство после слияния.
Если вас интересуют мои более широкие мысли о балансе между ИИ и качеством, вам может понравиться мой предыдущий пост о важности человеческого фактора в разработке, управляемой ИИ.
Настройка локальной среды для агентной разработки
Всё начинается локально. Прежде чем вы даже подумаете о CI/CD или автоматизированных проверках, вам нужно убедиться, что ваш ИИ-агент знает, как писать код так, как вы хотите. Самый важный инструмент для этого — файл agents.md (или его эквивалент в вашем редакторе, например, правила Cursor).
Представьте себе файл agents.md как документ, содержащий стандарты кодирования для вашего агента. Он указывает агенту, какие языковые возможности следует предпочитать, как структурировать код и каким соглашениям следовать. Вот пример того, как выглядит мой файл agents.md для iOS-проекта:
## Swift code conventions - Use 2-space indentation - Prefer SwiftUI over UIKit unless explicitly targeting UIKit - Target iOS 26 and Swift 6.2 - Use async/await over completion handlers - Prefer structured concurrency over unstructured tasks ## Architecture - Use MVVM with Observable for view models - Keep views thin; move logic into view models or dedicated services - Never put networking code directly in a view ## Testing - Write tests for all new logic using Swift Testing - Run tests before creating a pull request - Prefer testing behavior over implementation details
Добавьте этот файл в корневую папку вашего проекта Xcode, и агент Xcode 26.3 тоже будет использовать ваши правила.
Этот файл — всего лишь отправная точка. Дело в том, что ваш agents.md — это живой документ. Каждый раз, когда агент делает что-то, что вам не нравится, вы добавляете правило. Каждый раз, когда вы замечаете шаблон, который хорошо работает, вы кодифицируете его. Я постоянно обновляю свой.
Например, я могу заметить, что мой агент создает новые вспомогательные классы для работы с сетью вместо использования уже имеющегося APIClient. Поэтому я могу добавить правило: «Всегда использовать существующий APIClient для сетевых запросов. Никогда не создавать новые вспомогательные классы для работы с сетью». С этого момента агент должен учитывать мои предпочтения и использовать существующий код вместо добавления нового.
Помимо правил, вы также можете наделить своего агента навыками. Навык — это отдельный Markdown файл, который подробно обучает агента определенной теме. В то время как agents.md устанавливает общие правила и соглашения, навык обычно содержит подробные шаблоны для структурирования таких вещей, как навигация в SwiftUI, безопасная обработка Swift Concurrency или работа с Core Data. В Xcode 26.3 даже есть MCP (его можно рассматривать как предшественника навыков), который может помочь агентам найти документацию, лучшие практики и многое другое.
Ваша локальная среда — это основа. Все, что происходит после (проверка запросов на слияние, CI, TestFlight), зависит от того, что агент изначально создает разумный код.
Планирование перед созданием
Этот шаг, на мой взгляд, имеет огромную ценность, но его легко пропустить.
Если вы используете Cursor (или аналогичный инструмент), у вас, вероятно, есть доступ к режиму планирования. Вместо того чтобы позволять агенту сразу переходить к написанию кода, вы просите его сначала составить план. Агент описывает, что он намерен сделать — какие файлы он будет изменять, какой подход он выберет, какие компромиссы он рассматривает — и вы проверяете этот план, прежде чем дать ему зеленый свет.
Разница между «отправить запрос и надеяться на лучшее» и «просмотреть план, а затем выполнить» огромна. При просмотре плана вы выявляете неудачные архитектурные решения до того, как они превратятся в плохой код. Вы можете направить агента к правильному подходу, не переделывая большую часть работы.
Планирование также делает более очевидным, если агент вас неправильно понял. Например, если ваш запрос не очень точно определяет все неясности заранее, агент может уверенно подумать, что вы имели в виду одно, а на самом деле — другое. Забавный пример: «сохранить эти данные на устройстве» — агент предполагает «записать в User Default», тогда как вы имели в виду «создать модели Swift Data». Часто такие ошибки можно обнаружить в режиме планирования и скорректировать траекторию действий агента.
На практике мой рабочий процесс выглядит так: я описываю, что хочу получить в режиме планирования, агент предлагает подход, я даю обратную связь или одобряю, и только после этого агент переключается на реализацию. Предварительное планирование может показаться долгим процессом, но обычно результат получается настолько лучше, что это того стоит на 100%.
Например, когда я хотел добавить функцию отслеживания результатов в Maxine, агент предложил создать совершенно новую модель данных и модель представления с нуля. В ходе проверки плана я заметил, что это будет дублировать логику, которая уже была в моих запросах к истории тренировок. Я направил проект на повторное использование существующего слоя данных, и результат получился более чистым и удобным для сопровождения. Без этапа планирования у меня получился бы избыточный код, который пришлось бы исправлять позже.
Автоматизированная проверка запросов на слияние с помощью BugBot
После того, как агент написал код, и я быстро проверил изменения, я запускаю код на своем устройстве, чтобы убедиться, что все выглядит и работает правильно. После моего одобрения агент может создать запрос на слияние в моем репозитории. Если агент работает в облаке, я полностью пропускаю этот шаг, и агент создаст запрос на слияние сразу же, как только посчитает, что работа завершена.
Вот тут-то и пригодится BugBot. BugBot является частью экосистемы Cursor и автоматически проверяет ваши запросы на слияние. Он ищет логические ошибки, граничные случаи и непреднамеренные изменения, которые я мог пропустить при быстром сканировании. Он даже может отправлять исправления непосредственно в ветку запроса на слияние.
BugBot оказался бесценным помощником в моем процессе, потому что, хотя я и провожу собственную проверку запросов на слияние, вся суть агентной инженерии заключается в том, чтобы позволить агенту обрабатывать как можно больше. Моя цель — сформировать промпт, быстро оценить результат, запустить его на своем устройстве и двигаться дальше. BugBot действует как автоматизированная система безопасности, которая обнаруживает то, что я могу упустить из виду.
Позвольте мне привести два примера из Maxine. Первый касается крайних случаев. Maxine восстанавливает вашу тренировку, если приложение вылетает. BugBot указал на возможную ситуацию, когда, если пользователь нажмет «начать тренировку» до завершения восстановления, приложение попытается запустить тренировку на Watch дважды. Честно говоря, я считал этот сценарий практически невозможным на практике — но код это допускал. Вместо того чтобы полагаться на то, что я не мог реально протестировать, BugBot добавил средства защиты, чтобы убедиться, что этот путь обрабатывается должным образом. Это именно то, что я никогда бы не обнаружил при беглом визуальном просмотре.
Второй пример касается непреднамеренных изменений. Однажды у меня был PR, где я оставил несколько «осиротевших» свойств, которые существовали для отладки. BugBot обнаружил их как «вероятно, не являющиеся частью этого изменения» — в описании PR, написанном агентом, они не упоминались (потому что я сам проводил отладку), и ни один код фактически не ссылался на эти свойства. BugBot их удалил. Мелочь, но это своего рода очистка, которая поддерживает порядок в кодовой базе, когда вы быстро работаете и оперативно проводите проверку.
Запуск сборок и тестов с помощью Bitrise
Хотя агент запускает тесты локально до того, как я увижу код, мне нужен второй уровень уверенности. Вот тут-то и пригодится CI. Я использую Bitrise для этого, но те же принципы рабочего процесса применимы к Xcode Cloud, GitHub Actions или любому другому CI-провайдеру, который может запускать xcodebuild.
Этот шаг еще важнее для моих облачных агентов, потому что они вообще не имеют доступа к xcodebuild.
У меня настроены два рабочих процесса Bitrise для моих проектов, каждый из которых запускается разными событиями.
Рабочий процесс тестирования (запускается при каждом запросе на слияние)
Первый рабочий процесс — это конвейер только для тестирования, который запускается всякий раз, когда открывается или обновляется запрос на слияние. Шаги минимальны:
- Клонировать репозиторий
- Отресолвить пакеты Swift
- Запустить набор тестов с помощью xcodebuild test
Вот и все. Никакого архивирования, никакой подписи, никакой загрузки. Единственная задача этого рабочего процесса — ответить на один вопрос: по-прежнему ли проходят тесты? Если что-то, написанное агентом (или что-то, исправленное BugBot), ломает тест, я знаю об этом до слияния. И я могу сказать агенту исправить то, о чем сообщила Bitrise.
Я настроил это как триггер для запросов на слияние, нацеленных на мою основную ветку. Bitrise автоматически подхватывает запрос на слияние, запускает рабочий процесс и сообщает результат в виде проверки статуса GitHub. Если он красный, я не делаю слияние.
Рабочий процесс релиза (запускается при слиянии в основную ветку)
Второй рабочий процесс запускается, когда что-то отправляется в основную ветку — что на практике означает мердж PR. Этот шаг значительно расширяет возможности:
- Клонирование репозитория
- Ресолв пакетов Swift
- Запуск полного набора тестов
- Архивирование приложения с подписью релиза
- Загрузка сборки в App Store Connect
Шаг тестирования может показаться избыточным, поскольку мы уже протестировали PR, но мне нравится иметь его здесь в качестве последней подстраховки. Слияния иногда могут вызывать проблемы (особенно если несколько PR попадают близко друг к другу), и я предпочитаю выявлять это до загрузки неработающей сборки.
Шаги архивирования и загрузки используют встроенные шаги Bitrise для архивирования Xcode и развертывания в App Store Connect. Вы настраиваете свои сертификаты подписи и профили подготовки один раз на вкладке подписи кода Bitrise, и с этого момента каждое слияние создает подписанную сборку, которая отправляется прямо в TestFlight.
Почему с ИИ тесты еще важнее
Наличие надежного набора тестов, вероятно, является наиболее эффективным инструментом для агентной инженерии. Ваши тесты действуют как контракт. Они показывают агенту, как выглядит правильное поведение, и выявляют регрессии в CI, даже если локальный запуск агента что-то пропустил. Более качественные тесты означают большую уверенность, а это значит, что вы можете позволить агенту обрабатывать больше задач.
К тому моменту, когда я фактически нажимаю «merge» в пул-реквесте, код уже прошел: локальные тесты агента, мой собственный быстрый обзор, автоматический обзор BugBot и зеленую сборку Bitrise. Это очень высокая уверенность при минимальных ручных усилиях.
Магия быстрой обратной связи TestFlight
Здесь все, о чем я писал до сих пор, сходится воедино. Поскольку рабочий процесс выпуска автоматически загружает каждое слияние в App Store Connect, каждое слияние в основную ветку приводит к созданию сборки TestFlight — ручное вмешательство не требуется. Вам не нужно открывать Xcode, не нужно архивировать локально, ничего. Вы выполняете слияние, и через несколько минут в TestFlight появляется новая сборка. Это замыкает цикл от «У меня появилась идея» до «У меня есть сборка на моем устройстве» с минимальными препятствиями.
Когда вы тестируете свое приложение в полевых условиях и замечаете что-то, что хотите подправить — неправильный макет, неясная метка, неудобный интерфейс — вы часто можете просто сказать своему агенту, что нужно исправить. Если изменение достаточно простое, и вы хорошо умеете подсказывать и планировать, вы можете получить новую сборку на своем устройстве удивительно быстро. Через локальное планирование, через запрос на слияние, через Bitrise и на ваше устройство через TestFlight.
Вернемся к примеру из вступления к посту…
Во время одной из моих тренировок с Maxine приложение вылетело. Прямо в спортзале я открыл Cursor, загрузил отчет о сбое, который мне предоставил TestFlight, добавил немного контекста о том, что я делал в приложении, и запустил промпт в работу. Затем я просто продолжил тренировку.
К тому времени, как я закончил, меня уже ждал запрос на слияние. Исправление было не идеальным — мне пришлось немного подправить некоторые вещи — но основная работа была выполнена. Я объединил его, Bitrise подхватил его, и вскоре у меня появилась новая сборка TestFlight. И все это время я был сосредоточен на тренировке, а не на отладке.
Вот что происходит, когда каждый этап конвейера автоматизирован. Агент пишет исправление, BugBot проверяет его, Bitrise тестирует и собирает, а TestFlight доставляет его. Ваша задача — управлять, а не крутить ручку.
Итог
Агентная разработка не означает отказ от качества. Она означает создание правильных механизмов защиты, позволяющих быстро двигаться вперед, не ломая ничего.
Используемый мной конвейер выглядит следующим образом: хорошо прописанный файл agents.md и ИИ-навыки закладывают локальную основу. Режим планирования гарантирует правильность подхода агента до того, как он напишет хотя бы одну строку кода. BugBot обнаруживает ошибки в запросах на слияние, которые я мог бы пропустить. Bitrise запускает тесты для каждого запроса на слияние, архивирует и загружает их при каждом слиянии с основной веткой. А TestFlight автоматически доставляет результаты на мое устройство.
Каждая часть усиливает другие. Без хорошей локальной настройки агент пишет плохой код. Без планирования он принимает плохие архитектурные решения. Без BugBot и Bitrise ошибки просачиваются. Без автоматической загрузки TestFlight цикл обратной связи слишком медленный, чтобы быть полезным.
Чтобы было ясно: этот конвейер не обнаруживает всего. Агент все еще может писать код, который проходит все тесты, но имеет сомнительную архитектуру, и BugBot не всегда будет его отмечать. Вам по-прежнему необходимо проводить анализ и критически мыслить. Но сочетание всех этих уровней значительно снижает риск выпуска неисправного продукта — и в этом вся суть. Речь идёт о снижении риска, а не об его устранении.
Если вы занимаетесь прототипированием или просто изучаете идею, вам, вероятно, всё это не понадобится сразу. Но как только у вас появятся реальные пользователи, зависящие от вашего приложения, подобный конвейер окупится. Настройте его один раз, дорабатывайте agents.md по мере необходимости, и вы сможете быстро двигаться вперёд, не жертвуя качеством, которого ожидают ваши пользователи.

