Я начал с 10 строк JavaScript, которые просто открывали браузер и кликали по кнопкам. Через 17 последовательных промптов к Claude Code это превратилось в 142-строчный скрипт с прокси-ротацией, перехватом clipboard и рекурсивной retry-логикой - и всё на одной зависимости.
Почему я не написал один большой промпт
Первый инстинкт был именно таким: описать всё сразу. “Мне нужен Playwright-скрипт, который открывает веб-сервис, регистрирует аккаунт через сервис временной почты, дожидается письма с кодом, копирует код из буфера обмена, использует прокси из файла и запускается 50 раз подряд”. Звучит как нормальное ТЗ. На практике AI генерирует что-то похожее на правду, но когда запускаешь - половина не работает, и непонятно с какого конца чинить.
Я попробовал по-другому. Первый промпт: “напиши простой Playwright-скрипт, открой 2 вкладки”. Результат - 15 строк, которые работали. С этого момента каждый следующий промпт добавлял одну конкретную вещь.
Это называется incremental prompting - подход, при котором задача разбивается на последовательные подзадачи. Каждая следующая опирается на результат предыдущей. Когда что-то ломается, сразу понятно что именно и в каком шаге. Контроль над генерацией принципиально другой: ты видишь каждое изменение в изоляции и можешь откатиться к последней рабочей точке.
Как скрипт эволюционировал шаг за шагом
Первые три шага были базовые: открыть страницу, добавить прокси, выставить локаль EN-US. 15 строк превратились в 30. Всё работало, можно двигаться дальше.
Четвёртый промпт принёс переход к сервису временной почты вместо Google-авторизации. Здесь же - снятие чекбоксов на форме регистрации. Пятая и шестая итерации добавили генерацию случайного email, заполнение формы, polling-цикл ожидания письма с кодом подтверждения.
Седьмой промпт стал первым серьёзным препятствием. Скрипт падал с ошибкой:
Error: strict mode violation: getByRole('button', { name: 'Continue' })
resolved to 2 elements
На форме было две кнопки с текстом “Continue”: обычная и “Continue with Google”. Playwright требует, чтобы локатор указывал ровно на один элемент - это intentional поведение, которое защищает от случайного клика не туда. Решилось одной опцией:
page.getByRole('button', { name: 'Continue', exact: true })
С exact: true Playwright ищет точное совпадение текста, а не подстроку. Кнопка “Continue with Google” перестала матчиться.
Промпты 8-9 - извлечение кода верификации из DOM письма. Следующая пара добавила обработку ситуации “email недоступен” - сервис временной почты иногда отказывал. Решение: рекурсивная retry-логика, где функция generateEmail() вызывает саму себя при ошибке. Не exponential backoff, а именно рекурсия - проще и достаточно для этой задачи.
Двенадцатый промпт оказался самым интересным технически.
Три технических момента, которые стоит запомнить
Перехват clipboard через monkey-patching. Веб-сервис генерировал API-ключ и клал его в буфер обмена через встроенную кнопку “Copy”. Задача: этот ключ нужно сохранить в файл. Проблема: Playwright не может напрямую читать clipboard после того, как страница сама туда записала.
Решение - подменить navigator.clipboard.writeText до загрузки страницы:
await page.addInitScript(() => {
const original = navigator.clipboard.writeText.bind(navigator.clipboard);
navigator.clipboard.writeText = async (text) => {
window.__copiedText = text;
return original(text);
};
});
// После клика на кнопку "Copy":
const apiKey = await page.evaluate(() => window.__copiedText);
Скрипт встраивается до инициализации страницы, перехватывает запись в буфер и параллельно сохраняет значение в window.__copiedText. Никаких permissions, никаких дополнительных зависимостей.
Прокси-ротация из файла. После того как без прокси скрипт заблокировали уже на третьей попытке, добавили чтение прокси из proxies.txt и round-robin ротацию:
const proxies = fs.readFileSync('proxies.txt', 'utf8')
.split('\n').filter(Boolean);
// В цикле на TOTAL_RUNS итераций:
const proxy = proxies[attempt % proxies.length];
const context = await browser.newContext({
proxy: { server: proxy }
});
Каждый новый контекст получает следующий прокси по кругу. Прокси задаётся на уровне context, а не browser - это даёт изоляцию сессий между запусками.
Параметризация через env. Количество запусков задаётся переменной окружения:
const TOTAL_RUNS = parseInt(process.env.TOTAL_RUNS || '50');
Дефолт 50, но для отладки достаточно TOTAL_RUNS=3 node script.js.
Как я промптировал
Структура, которая сработала лучше всего: current state + desired state + constraint.
“У нас есть функция generateEmail(). Она иногда получает ошибку ’email unavailable’ от сервиса. Добавь рекурсивную retry-логику - при ошибке функция должна вызывать саму себя и генерировать новый email. Без дополнительных зависимостей.”
Три компонента: что есть, что хочу, что нельзя. Claude не переписывал всё с нуля, а точечно добавлял нужное. И это работает именно потому, что контекст сессии сохраняется - не нужно каждый раз прикладывать весь файл.
На тринадцатом шаге я добавил: “после успешного сохранения результата - вызывай browser.close()”. До этого скрипт не закрывал браузер при выходе, и после нескольких запусков в памяти висели zombie-процессы. Одно предложение в промпте - три строки в коде - проблема исчезла.
Пятнадцатый промпт добавил логику пропуска: если письмо с кодом не пришло за 10 попыток polling - пропускаем итерацию и переходим к следующей. Без этого скрипт мог зависнуть на одном аккаунте навсегда.
Что получилось в итоге
142 строки CommonJS. Одна зависимость - playwright. Скрипт запускается с TOTAL_RUNS=100 node script.js, читает прокси из файла, ротирует их по кругу, регистрирует аккаунты через сервис временной почты, перехватывает API-ключи из clipboard и сохраняет результаты в JSON. После финализации проработал автономно 4.5 часа.
Для сравнения: если бы я пытался написать это всё в одном промпте или вручную - разбирался бы значительно дольше. И код был бы хуже, потому что каждый шаг я проверял в изоляции и мог попросить улучшить конкретно его.
Что я вынес из этих 17 промптов
Не пытаться описать всё сразу. Разбить задачу на 4-5 шагов, где каждый шаг - одна конкретная фича. После каждого шага - запустить и убедиться, что работает. Только потом следующий.
Конкретность промпта важна. “Добавь прокси” и “добавь прокси-ротацию из файла proxies.txt с round-robin по модулю” - это принципиально разные промпты с принципиально разными результатами.
Strict mode violations - это не баги, это Playwright говорит “твой селектор неоднозначен”. Лучше поймать это здесь, чем когда скрипт тихо кликает не туда.
Рекурсия для retry бывает чище exponential backoff - зависит от задачи. Если нужно просто попробовать снова с другими данными (другой email), рекурсивный вызов читается понятнее.
Вайб-кодинг в 2026 - это не “написал один хороший промпт и готово”. Это диалог, где каждый следующий вопрос чуть сложнее предыдущего. AI хорошо держит контекст, хорошо добавляет конкретную фичу к работающему коду, хорошо объясняет почему что-то сломалось. Плохо справляется с “сделай всё сразу и чтобы работало”.
Если сейчас начинаешь автоматизационный скрипт - напиши базовую версию за один промпт, запусти, убедись что работает. Потом по одной фиче. Это занимает больше времени в начале и кратно меньше - в конце.