← Claude Code: Agentic Development in the Terminal
05 / 08 · 50 min

The worktree pipeline: background agents that stay out of the way

A protocol for autonomous background work: worktree by default, one root and naming scheme, separate executor and merger roles, and cleanup as part of the definition of done.

Lesson content is currently available in Russian.

What you will learn

  • →Заводить любую фоновую или автономную задачу в отдельном worktree с веткой — по протоколу, а не по настроению.
  • →Держать все worktree в едином предсказуемом корне и находить любой прогон за секунды.
  • →Разделять роли исполнителя и мёржера и принимать работу агента только по доказательствам.
  • →Закрывать задачу полностью: мёрж с верификацией, удаление worktree и ветки, чистый git worktree list.

Дефолт: фоновая работа — в worktree

Прошлый урок показал параллельные интерактивные сессии: два терминала, два worktree, вы видите оба. Этот — про следующий уровень автономии: задачи, которые вы «кидаете и забываете». Фоновый агент чинит флапающий тест, пока вы правите платёжный модуль; ночной прогон обновляет зависимости; субагент с isolation переписывает документацию. Общее у них одно: в момент работы агента на него никто не смотрит.

Именно это делает общий каталог не риском, а гарантированной аварией — вопрос лишь времени. Типовой инцидент выглядит так: вы в середине рефакторинга, в рабочем дереве полуготовый WIP. Фоновый агент закончил свою мелочь, услужливо сделал git add . и закоммитил — ваш недописанный код уехал в его коммит под его сообщением. Второй вариант того же инцидента: агент переключил ветку или запустил форматтер по всему дереву — и файлы поменялись у вас «под ногами» посреди вашей правки. В интерактиве вы бы это заметили за секунду. В фоне — обнаружите вечером, разгребая смешанный дифф двух задач.

Поэтому правило формулируется как дефолт, а не как опция: любая фоновая, автономная или параллельная задача начинается с создания worktree и ветки. Исключение ровно одно — одиночная интерактивная правка в 1–3 шага в уже открытой сессии, где вы смотрите агенту «на руки». Всё остальное — изоляция сначала, работа потом.

Важно понимать, почему это не лечится промптом. «Будь аккуратен, не трогай чужие файлы» — просьба, а не гарантия: агент не видит, какие изменения в дереве ваши, а какие его, у него нет способа отличить чужой WIP от собственного черновика. Гонка за общий изменяемый ресурс — свойство архитектуры, и решение архитектурное: у каждого потока работы свой каталог, свой индекс, своя ветка. Ровно то, что даёт git worktree за одну команду и почти бесплатно.

Единый корень и протокол создания

Worktree, разбросанные по файловой системе, — вторая по частоте авария после общего каталога: через месяц вы не помните, что за каталог ../myapp-fix2, жив ли там процесс и влита ли ветка. Лекарство — конвенция из трёх пунктов, которая окупается с первого же десятка прогонов.

Первый пункт: один предсказуемый корень для всех worktree всех репозиториев — и общий для всех агентных инструментов, которыми вы пользуетесь (Claude Code, другие CLI-агенты, ручные ветки). Один взгляд на каталог — полная картина параллельной работы на машине. Второй: имя каталога собирается из репозитория, слага задачи и штампа времени — оно уникально, сортируется хронологически и читается без контекста. Третий: ветка создаётся вместе с worktree, от свежего HEAD.

# протокол создания: корень, имя, ветка — одной привычкой
REPO=$(basename "$(git rev-parse --show-toplevel)")
WT=~/worktrees/${REPO}-flaky-auth-test-$(date +%Y%m%d%H%M%S)
git worktree add "$WT" -b fix/flaky-auth-test HEAD

# фоновая сессия работает там, основной каталог остаётся вашим
cd "$WT" && claude -p "почини флапающий тест auth, отчёт с выводом прогона"

# в любой момент: где что живёт
git worktree list
# /repo                                  abc1234 [dev]
# ~/worktrees/repo-flaky-auth-test-…     abc1234 [fix/flaky-auth-test]

Два свойства git здесь работают на вас. База объектов общая — worktree создаётся за секунды и почти не занимает места, поэтому «жалко заводить» — ложная экономия. И git сам не позволит выдать одну ветку двум worktree: попытка завершится ошибкой — это встроенная страховка от двух агентов на одной ветке.

Бытовые мелочи, которые становятся важными при параллельных прогонах: dev-серверы соседних worktree — на разных портах; проверка «я там, где думаю» — git rev-parse --show-toplevel перед разрушительными командами; у каждого прогона — потолок по времени и итерациям, чтобы зависший агент не жил в worktree вечно.

Исполнитель и мёржер: разделение властей

Зрелый worktree-конвейер разделяет две роли, как их разделяет любая инженерная команда: исполнитель делает работу, принимающий — решает, попадёт ли она в общую историю.

Исполнитель — агент в worktree. Его контракт жёсткий: все правки только внутри своего каталога; коммиты только поимённо — git add src/auth/token.ts src/auth/token.test.ts, никогда git add .; отчёт обязан содержать доказательства — вывод прогона тестов, git status, список изменённых файлов. «Тесты зелёные» без вывода прогона — не факт, а гипотеза; в прошлом уроке этот принцип звучал для субагентов, здесь он становится воротами конвейера.

Мёржер — отдельный шаг и, в идеале, отдельная пара глаз: другой агент со свежим контекстом или вы сами. Он читает дифф ветки целиком — свежий взгляд находит то, что автор уже «не видит»; вливает в рабочую ветку; и обязательно повторяет typecheck и тесты на результате мёржа. Последнее — не перестраховка: две ветки, зелёные порознь, вместе бывают красными — одна переименовала функцию, вторая добавила вызов по старому имени; текстового конфликта нет, семантический есть, и ловится он только прогоном после слияния. Конфликт, который нельзя разрешить однозначно, — повод остановиться и спросить человека, а не гадать.

Два действия в конвейере остаются за человеком всегда: push в общий remote и всё необратимое. Автономность агента заканчивается на границе его worktree; публикация результата — явное решение владельца.

И последний элемент — ёмкость. Кодинг-агент гоняет сборки и тесты, каждый прогон ест ядра и память; практический потолок на рабочей машине — два-четыре одновременных прогона, остальные задачи ждут в очереди. Резать фронт работ нужно по непересекающимся областям файлов: worktree изолирует процесс, но не смысл — две задачи, правящие один модуль, конфликтуют при мёрже, и такие задачи ставятся последовательно. Как строить очередь, verify-gate и арбитраж поверх этого — отдельный разговор в курсе про мультиагентную оркестрацию.

Уборка — часть definition of done

Забытый worktree — это занятая ветка, гигабайты node_modules и каталог, в котором через месяц страшно что-либо удалять, потому что «а вдруг там что-то нужное». Поэтому финал задачи в конвейере определён списком, а не ощущением «вроде готово»:

# после вливания (или после отказа от результата)
git worktree remove --force ~/worktrees/repo-flaky-auth-test-…
git branch -d fix/flaky-auth-test   # ветку — только после успешного мёржа
git worktree prune                  # подчистить висячие регистрации
git worktree list                   # финальная проверка: только основной каталог

Удалять worktree нужно командой git worktree remove, а не rm -rf: после ручного удаления в репозитории остаются висячие записи, которые потом чистит prune. Отвергнутый результат убирается точно так же — отказ от ветки не отменяет уборку каталога. Полезная привычка на масштабе — периодическая чистка сирот: worktree без незакоммиченных правок и без живого процесса можно удалять смело.

Сведём красные флаги конвейера — каждый из них когда-то был чьим-то реальным инцидентом:

  • фоновый агент работает в общем каталоге «потому что задача мелкая»;
  • git add . или авто-коммит при живой параллельной работе — захват чужого WIP;
  • два агента правят один файл параллельно;
  • мёрж или push сделаны самим исполнителем без ревью и без прогона после слияния;
  • «готово» без вывода команд в отчёте;
  • worktree остался висеть после вливания или отказа.

Если ни один флаг не горит — у вас не набор трюков, а протокол: фоновые агенты делают работу тихо, основная сессия ничего не замечает, история остаётся чистой, а git worktree list в конце дня выглядит так же, как утром.

Practice

Фоновая задача, которая не перебивает

Выберите реальную мелкую задачу (флапающий тест, обновление README, мелкий рефакторинг). Создайте worktree с веткой по протоколу именования, отдайте задачу фоновой сессии агента и продолжайте свою работу в основном каталоге. Примите результат как мёржер: прочитайте дифф, влейте, прогоните тесты после слияния, уберите worktree и ветку.

Deliverable

Вывод git worktree list во время прогона (основной каталог + worktree задачи), отчёт агента с выводом тестов, лог мёржа с повторным зелёным прогоном и чистый git worktree list в конце.

Checkpoint

Опишите ваш протокол фоновой задачи от постановки до чистого git worktree list: в каких точках чужая работа могла бы пострадать и что именно каждую из них закрывает?

  • ✓ Фоновая задача заведена в отдельном worktree с веткой от HEAD; общий каталог не тронут.
  • ✓ Коммиты исполнителя собраны поимённо, отчёт содержит вывод тестов и git status.
  • ✓ Мёрж выполнен отдельным шагом с чтением диффа и повторным прогоном после слияния; push оставлен человеку.
  • ✓ Worktree и ветка удалены, git worktree prune выполнен, финальный git worktree list чист.

Check yourself

Почему фоновой задаче нужен отдельный worktree, даже если она «мелкая»?

01Почему фоновой задаче нужен отдельный worktree, даже если она «мелкая»?

Что даёт единый корень для всех worktree?

02Что даёт единый корень для всех worktree?

Почему мёрж — отдельный шаг, а не финальное действие агента-исполнителя?

03Почему мёрж — отдельный шаг, а не финальное действие агента-исполнителя?

Задача завершена. Что означает «уборка — часть definition of done»?

04Задача завершена. Что означает «уборка — часть definition of done»?

Sources

The worktree pipeline: background agents that stay out of the way · Claude Code: Agentic Development in the Terminal · VORCL