← Назад
Журнал

Gas Town: разбор оркестратора кодящих агентов

Оркестратор для случая, когда кодящих агентов больше, чем человек успевает вести вручную. В разборе — роли и цепочка надзора, путь задачи от постановки до слияния, хранилище на Dolt и git, расхождения документации с кодом и идеи, которые стоит забрать себе без установки.

Разбор репозитория · gastownhall/gastown · версия 1.2.1

Какую проблему решает Gas Town

Gas Town — программа командной строки gt, которая запускает много сессий кодящих агентов и следит за ними. Она отвечает на вопрос, что делать, когда агентов больше, чем человек успевает вести вручную.

README называет четыре трудности:

  • агент теряет контекст при перезапуске;
  • человек координирует агентов вручную;
  • 4–10 агентов превращаются в хаос;
  • состояние работы живёт в памяти агента и пропадает вместе с ней.

Ответ проекта — одна причинная цепочка. Задача записана в базе данных, а не в контексте модели. На записи агента стоит отметка «эта задача твоя». Хук запуска сессии показывает агенту эту отметку. Поэтому любая новая сессия находит свою задачу и продолжает её, а сессии становятся расходным материалом: упавшую или переполненную сессию заменяют новой.

Второй довод — подотчётность. Каждый агент получает имя вида gastown/polecats/toast, и этим именем подписаны его коммиты и записи в базе. По why-these-features.md это нужно, чтобы найти агента, который внёс ошибку, и сравнивать модели на похожих задачах.

Тот же документ помечает автоматический подбор исполнителя по навыкам как запланированный. Сейчас исполнителя выбирает тот, кто вызывает команду назначения gt sling: координирующий агент или человек.

Словарь проекта: Town, Rig, Bead, Hook, Convoy, Formula

Gas Town использует собственные названия, часть — из «Безумного Макса». Ниже каждое объяснено через его функцию. «Рантаймом» в проекте и в этом тексте называется консольный агент, который исполняет работу: Claude Code, Codex и другие.

  • Town — рабочий каталог, по умолчанию ~/gt/. В нём лежат настройки, каталоги общегородских агентов и все проекты.
  • Rig — контейнер одного проекта внутри Town. Он оборачивает один git-репозиторий и содержит каталоги агентов этого проекта. Сам Rig git-клоном не является: клон лежит внутри него, в mayor/rig/.
  • Bead — запись в трекере задач Beads (команда bd): задача, ошибка, группа задач, письмо, запрос на слияние или карточка агента. Карточка агента хранит его роль, состояние и текущее назначение. Идентификатор состоит из префикса проекта и короткого кода: gt-abc12, hq-x7k2m. Префикс hq- означает уровень Town.
  • Hook — отметка «эта работа назначена этому агенту». Технически это поле hook_bead в карточке агента и статус hooked у задачи. Назначение переживает перезапуск сессии и сжатие контекста; на этом свойстве держится вся система.
  • GUPP (Gas Town Universal Propulsion Principle) — правило для агентов: «если на твоём Hook есть работа, выполняй её сразу». Агент не ждёт подтверждения: в системе нет звена, которое его даст, и ожидание останавливает всех, кто зависит от результата.
  • Convoy — запись, которая отслеживает группу задач, возможно из разных Rig. Когда закрыты все задачи, Convoy закрывается и уведомляет подписчиков. gt sling создаёт Convoy автоматически даже для одной задачи.
  • Formula — шаблон процедуры в TOML: шаги с зависимостями. В бинарь встроено 47 формул.
  • Molecule — экземпляр формулы, привязанный к конкретной работе.
  • Wisp — экземпляр формулы, который не хранится долго: старые Wisp удаляет уборка базы. Так оформляются обходы и работа исполнителей. По умолчанию создаётся одна корневая запись, а шаги агент читает из встроенной формулы. Причина по документации: запись каждого шага давала больше 6000 строк в день, с корневой записью выходит около 400.
  • Sling — команда назначения: gt sling <задача> <rig> вешает задачу на Hook и запускает исполнителя.

Слово «hook» в репозитории значит три разные вещи, и их легко спутать:

  • Hook как назначение работы — запись в базе (глоссарий, gt hook, схема таблицы);
  • хуки рантайма — команды, которые Claude Code вызывает на событиях сессии (docs/HOOKS.md, команда gt hooks);
  • Hook как «хранилище на git worktree» — так пишет README, но в коде и глоссарии такого значения нет.
Town · ~/gt/
один на Town
Mayor

Координатор, собеседник человека

один на Town
Deacon

Общий надзиратель

помощники
Dogs · Boot

Служебные задания Deacon

не LLM
Daemon

Процесс Go

Rig · проект A
один на Rig
Witness

Надзор за Polecat

один на Rig
Refinery

Очередь слияния

много
Polecats

У каждого свой worktree

человек
Crew

Полный клон

mayor/rig — канонический клон

Rig · проект B
Witness
Refinery
Polecats
Crew

mayor/rig

hq-cv-…
Convoy

Живёт на уровне Town и отслеживает задачи из разных Rig

Карта сущностей. Town вмещает общегородских агентов и проекты; у каждого Rig свой набор ролей.

Роли: кто работает и кто за кем следит

В Gas Town восемь ролей агентов — по числу шаблонов ролей в бинаре — и один процесс без LLM. Роли делятся на исполнителей и надзор.

Исполнители делают работу в проекте:

  • Polecat — исполнитель одной задачи. Работает в отдельном git worktree на своей ветке и в основную ветку сам не пишет.
  • Crew — долгоживущее рабочее место с полным клоном репозитория. Им управляет человек; за Crew никто не следит, и он пишет в основную ветку напрямую.

Надзор и координация:

  • Mayor — координатор уровня Town и основной собеседник человека. Создаёт Convoy, назначает задачи командой gt sling, получает эскалации — обращения агентов за помощью, о них ниже.
  • Witness — один на Rig. Обходит Polecat своего проекта, будит остановившихся, перезапускает упавшие сессии, оформляет завершение. Кода не пишет.
  • Refinery — один на Rig. Обрабатывает очередь слияния: только он переносит ветки Polecat в основную ветку.
  • Deacon — один на Town. Крутит цикл обхода из 26 шагов: проверяет Witness и Refinery, закрытие Convoy, здоровье базы, раздаёт служебные задания.
  • Dogs — помощники Deacon для служебных заданий: резервные копии, сжатие базы, чистка. Задачами проекта они не занимаются.
  • Boot — помощник с отдельным шаблоном роли. Daemon запускает его, чтобы решить, что делать с неотвечающим Deacon.
  • Daemon — обычный процесс Go. Каждые 3 минуты (значение по умолчанию в коде) он проверяет сервер базы и свежесть отметки активности, которую Deacon обновляет на каждом обходе.

Надзор выстроен цепочкой. Daemon следит за Deacon и при сбое привлекает Boot. Deacon следит за Witness и Refinery каждого проекта. Witness следит за Polecat. Есть и обратная проверка: Witness смотрит на отметку активности Deacon и пишет Mayor, если Deacon не запущен, а отметка старше 5 минут. За Crew не следит никто.

Ключевое свойство цепочки: из её звеньев только Daemon — детерминированный код. Остальные звенья — LLM-сессии, которые выполняют формулу обхода как чек-лист. Расчёт авторов такой: отдельный шаг может сорваться, но повторные обходы доводят работу до конца.

Polecat разделён на три слоя с разным временем жизни. Из-за этого потеря сессии не означает потери работы:

  • личность — карточка агента и история работ; живёт постоянно;
  • песочница — так проект называет worktree и ветку; изоляции от системы это слово не означает. Песочница живёт от назначения до уборки (так в справке gt done; формула Witness говорит иное, см. раздел о расхождениях);
  • сессия — окно tmux с контекстом модели; меняется после шага, при сжатии контекста, при сбое.
единственный без LLM
Daemon

Проверка каждые 3 минуты

следит за · при сбое зовёт Boot
Deacon

Обход всего Town, 26 шагов

следит за
на каждый Rig
Witness

Сам проверяет отметку Deacon, порог 5 минут

на каждый Rig
Refinery
Witness следит за
Polecats
сбоку
Boot

Решает судьбу неотвечающего Deacon

эскалации
Mayor

Получает их от Deacon и Witness

эскалация
Человек

Overseer

вне цепочки
Crew

Никто не следит

Цепочка надзора. Кто кого проверяет и куда уходят обращения за помощью.

Путь одной задачи от постановки до слияния

Задача проходит восемь этапов, и на каждом всё нужное для продолжения записано вне контекста модели.

  1. Постановка. Человек подключается к Mayor командой gt mayor attach и описывает цель словами. Mayor создаёт задачи в Beads и объединяет их в Convoy.
  2. Назначение. Mayor вызывает gt sling. Команда выделяет имя из пула, создаёт worktree с новой веткой, запускает сессию tmux с агентом, вешает задачу на Hook и прикрепляет формулу mol-polecat-work.
  3. Вход в контекст. Хук начала сессии вызывает gt prime. Команда определяет роль по текущему каталогу и печатает шаблон роли, чек-лист формулы и назначенную задачу.
  4. Работа. Polecat идёт по чек-листу из восьми шагов.
  5. Сдача. Polecat выполняет gt done. Команда отправляет ветку в удалённый репозиторий, создаёт Bead запроса на слияние, записывает итог в карточку агента, будит Refinery и Witness и завершает сессию.
  6. Оформление. Witness находит завершение по карточке агента, создаёт запись об уборке и повторно сообщает Refinery о готовности ветки. Сигнал от gt done и сигнал от Witness дублируют друг друга.
  7. Слияние. Refinery проверяет, что ветка сливается с целевой, запускает проверки, просматривает разницу, сливает и отправляет результат, затем уведомляет Witness.
  8. Закрытие. Когда закрыты все задачи Convoy, Convoy закрывается и уведомляет подписчиков.

Команды первых этапов из README:

gt convoy create "Feature X" gt-abc12 gt-def34 --notify --human
gt sling gt-abc12 myproject
gt convoy list

Восемь шагов формулы mol-polecat-work:

  1. загрузить контекст и проверить назначение;
  2. подготовить рабочую ветку;
  3. реализовать решение;
  4. закоммитить изменения;
  5. проверить собственную работу;
  6. собрать проект и убедиться, что он запускается;
  7. перебазировать ветку на свежую основную и повторить проверку;
  8. сдать работу и завершить сессию.

Три ограничения видны только в коде:

  • gt done отправляет ветку до создания запроса на слияние. Комментарий в internal/cmd/done.go объясняет порядок: Refinery начинает обработку, увидев запрос в базе, а ветки на этот момент может не оказаться.
  • gt sling отказывается запускать одну и ту же задачу после трёх попыток перезапуска, чтобы зависшая задача не плодила исполнителей.
  • gt done принимает три статуса выхода: COMPLETED, ESCALATED и DEFERRED. Два последних пропускают слияние.

Если ветка конфликтует с основной, Refinery создаёт отдельную задачу на разрешение конфликта, и её получает новый Polecat. Исходной сессии к этому моменту уже нет.

Если агент упёрся в препятствие, он вызывает gt escalate -s HIGH "описание". Эскалация — тоже Bead. По настройкам по умолчанию средняя важность уходит письмом Mayor, высокая добавляет письмо человеку, критическая — ещё и SMS. Неразобранной эскалации через 4 часа повышают важность, не больше двух раз.

Человек → Mayor

Описывает цель словами

Mayor → Dolt

Создаёт задачи и Convoy

Mayor → Polecatgt sling

Worktree, ветка, сессия tmux, Hook

Polecat ← Doltgt prime

Читает Hook и чек-лист

Polecat

Восемь шагов формулы; сессии сменяются, состояние остаётся в Dolt и worktree

Polecat → git, Doltgt done

Push ветки, затем Bead запроса на слияние

Witness → Refinery

Ветка готова

Refinery → git

Проверки, merge, push в основную ветку. Конфликт → новая задача → новый Polecat

Dolt → Человек

Convoy закрыт, уведомление

Путь одной задачи. Кто кому передаёт ход и какой командой.

Хранилище: Dolt, git и файлы

Состояние Gas Town разложено по четырём хранилищам.

Dolt — SQL-база с версионированием в духе git. В ней лежит всё, что является Bead. Один сервер Dolt обслуживает весь Town по протоколу MySQL на порту 3307; данные лежат в ~/gt/.dolt-data/, по отдельной базе на Rig и одна база hq для уровня Town. Встроенного режима нет: если сервер недоступен, bd сразу сообщает об ошибке и указывает на gt dolt start. Все агенты пишут в ветку main базы, и каждая запись оборачивается в транзакцию с коммитом Dolt. Поэтому изменение одного агента сразу видят остальные.

Git хранит код. В Rig лежит голый репозиторий .repo.git/ и канонический клон mayor/rig/. Каталоги Polecat и Refinery — worktree от канонического клона, поэтому новый исполнитель создаётся быстро и делит объекты с остальными. У Crew полные клоны.

Файлы хранят настройки и служебное состояние:

  • mayor/town.json, mayor/rigs.json, mayor/daemon.json — настройки Town, реестр проектов, параметры обхода;
  • settings/escalation.json — маршруты эскалации;
  • .beads/routes.jsonl — таблица «префикс идентификатора → каталог проекта»;
  • ~/.gt/hooks-base.json и ~/.gt/hooks-overrides/ — хуки рантайма;
  • ~/.gt/costs.jsonl — журнал стоимости сессий.

tmux хранит живые сессии. Это единственное состояние, которое намеренно считается теряемым.

Таблица маршрутов делает работу с несколькими проектами прозрачной: bd show gt-xyz сам находит базу нужного Rig по префиксу. Рабочие каталоги агентов своей базы не имеют. В них лежит файл .beads/redirect с путём к каталогу .beads канонического клона, поэтому все агенты проекта работают с одной базой.

Удалять старые строки и сжимать историю базы должны Dogs; по architecture.md эту автоматику авторы ещё вводят. Раз в 15 минут Dog выгружает снимок базы в JSONL и кладёт его в git-архив как резервную копию.

Dolt · порт 3307
hq

Карточки Mayor и Deacon, Convoy, почта, эскалации

на каждый Rig
База Rig

Задачи, запросы на слияние, карточки агентов, Wisp

Git

.repo.git — голый
mayor/rig — канонический клон

worktree

polecats/<имя>/
refinery/rig/

полный клон

crew/<имя>/

Файлы

mayor/*.json
settings/escalation.json
.beads/routes.jsonl
~/.gt/hooks-base.json
~/.gt/costs.jsonl

tmux
теряемое

Живые сессии агентов

Бинарь gt

Шаблоны ролей, 47 формул, проверки gt doctor

Что где хранится. Нужное для продолжения работы лежит в Dolt и Git; .beads/redirect сводит рабочие каталоги к одной базе на Rig.

tmux, хуки и рантаймы

Gas Town не обращается к API моделей. Он запускает готовые консольные агенты в сессиях tmux и управляет ими снаружи. Отсюда три механизма.

Хуки рантайма вносят контекст. Gas Town генерирует файл настроек Claude Code в родительском каталоге роли, например <rig>/polecats/.claude/settings.json, и передаёт его флагом --settings. Клиентский репозиторий при этом остаётся без служебных файлов Gas Town. Реестр хуков содержит семь записей. Три из них — защитные проверки перед вызовом инструмента, остальные четыре переносят состояние:

  • session-prime на событии SessionStart вызывает gt prime;
  • pre-compact-prime на событии PreCompact повторяет контекст перед сжатием;
  • mail-check на событии UserPromptSubmit подмешивает непрочитанную почту;
  • costs-record на событии Stop записывает стоимость сессии.

Сообщения доставляются командой gt nudge. У неё три режима:

  • wait-idle (по умолчанию) ждёт, пока агент остановится на приглашении ввода, и только тогда доставляет;
  • queue пишет в файловую очередь, которую хук читает перед следующим запросом к модели;
  • immediate шлёт текст через tmux send-keys и прерывает текущее действие.

Длинные сообщения идут почтой gt mail: это Bead типа «сообщение», который переживает перезапуск получателя.

Рантаймы подключаются предустановками. В internal/config/agents.go их тринадцать: claude, gemini, codex, kiro, cursor, auggie, amp, opencode, copilot, pi, omp, vibe, groq-compound. Глубина интеграции разная. Claude Code и Gemini получают хуки через settings.json, OpenCode — плагин на JavaScript, Copilot — JSON-хуки в .github/hooks/gastown.json. Для Codex и остальных хуков нет: после старта Gas Town сам вводит в сессию команду gt prime, а очередь сообщений разбирает фоновый процесс gt.

Предустановки запускают агентов без запросов подтверждения. У Claude Code это флаг --dangerously-skip-permissions, у Codex — --dangerously-bypass-approvals-and-sandbox, у Copilot — --yolo.

Смена сессии встроена в обычную работу. gt handoff завершает сессию и стартует новую с чистым контекстом; новая находит ту же работу на Hook.

Wasteland и Gas City: федерация и планы

Wasteland — общая доска заказов между разными Town, построенная на DoltHub. Участник делает форк общей базы hop/wl-commons, берёт заказ, сдаёт ссылку на результат и получает от проверяющего «штамп» — оценку по нескольким измерениям.

gt wl join hop/wl-commons
gt wl browse
gt wl claim w-abc123
gt wl done w-abc123 --evidence <url>

Документация описывает текущее состояние как «Phase 1 (wild-west mode)». Из этого следуют три ограничения:

  • заявка на заказ пишется только в локальный форк, поэтому два участника могут взять один заказ;
  • уровни доверия есть в схеме, но никто их не проверяет;
  • команды выхода из Wasteland нет — конфигурацию удаляют вручную.

Gas City в клоне существует только как проектный документ docs/gas-city/crew-specialization-design.md. Он описывает планируемый декларативный слой: роли, зашитые сейчас в код, превращаются в переносимые схемы, а задачи распределяются по заявленным способностям агентов. Кода под этим названием в репозитории нет.

Где документация расходится с кодом

Документация проекта описывает сразу несколько поколений системы. Ниже расхождения, которые меняют понимание.

  • Очередь слияния. README описывает очередь как пакетную: Refinery собирает запросы в пачку и при падении тестов делит её пополам в поисках виновника. Функции ProcessBatch и bisectBatch есть в internal/refinery/batch.go, но вне этого файла и тестов их никто не вызывает. architecture.md помечает этот этап как заблокированный. Формула обхода Refinery обрабатывает ветки по одной.
  • Команды из README. gt hooks repair, gt convoy refresh, gt convoy show и gt mayor detach в коде не определены.
  • Судьба Polecat после сдачи. По polecat-lifecycle.md сдавший работу Polecat повторно не используется, а песочницу убирают. Формула обхода Witness, которую агент получает как инструкцию, говорит обратное: Polecat переходит в ожидание, песочница сохраняется для следующей задачи.
  • Федерация. why-these-features.md называет Gas Town системой одного Town с запланированной федерацией, а Wasteland уже работает.
  • Учёт стоимости. Справка gt costs digest говорит, что суточную сводку запускает Deacon. В формуле Deacon этот шаг помечен [DISABLED].
  • Защитные хуки. docs/HOOKS.md помечает защиту от опасных команд включённой и там же пишет, что её команды ещё не существует.
  • Масштаб. README обещает комфортную работу с 20–30 агентами, а проектный документ об изоляции пишет, что ноутбук не выдерживает 10–20 одновременных сессий Claude.
  • Мелочи. Overview ссылается на отсутствующий docs/design/watchdog-chain.md. README перечисляет 11 предустановок рантаймов при 13 в коде.

Вывод: README годится для знакомства, а факты лежат в docs/design/, встроенной справке команд и формулах.

Чего это стоит и кому нужно

Gas Town оправдан, когда есть поток однородных, хорошо описанных задач и человек, готовый стать оператором системы. Для одного-двух агентов расходы на надзор превышают выгоду.

Масштаб кода. По подсчёту на клоне:

  • 663 файла Go без тестов, около 249 тысяч строк;
  • 568 файлов тестов, около 226 тысяч строк;
  • 111 команд верхнего уровня у gt;
  • 47 формул, 13 плагинов, 8 шаблонов ролей;
  • 27 версий в CHANGELOG.md — от 0.1.0 (2026-01-02) до 1.2.1 (2026-06-06).

Цена в токенах. Mayor, Deacon, Witness и Refinery — постоянно работающие LLM-сессии; Witness и Refinery свои у каждого проекта. Они расходуют токены и тогда, когда задач нет. Авторы это учитывают: Witness между обходами ждёт события, и предел ожидания растёт от 30 секунд до 5 минут, а формула требует, чтобы холостой обход стоил около 10 % полного. Измеренных цифр расхода в репозитории нет. gt costs считает стоимость по журналам Claude Code, то есть только для этого рантайма.

Цена в сложности. Обязательные зависимости: Dolt, Beads (bd), tmux, git, для сборки ещё Go 1.26 и заголовки ICU. Постоянно работают сервер базы и Daemon. Оператору нужно усвоить около двадцати терминов, а диагностика настолько объёмна, что вынесена в команду gt doctor.

Безопасность. Агенты запускаются без подтверждений, на машине пользователя и с его правами. Проектный документ об изоляции говорит прямо: агент может читать файлы вне своего каталога и обращаться к сети. У документа статус «Proposal». Прокси-сервер для работы Polecat в контейнере в репозитории есть (cmd/gt-proxy-server), но путь по умолчанию — без изоляции. Сервер Dolt по умолчанию слушает 127.0.0.1 и принимает пользователя root без пароля.

Зрелость. CONTRIBUTING.md называет Gas Town экспериментальным ПО. Журнал изменений состоит из исправлений гонок, зависших сессий, осиротевших веток и накопления записей. Пример из версии 1.0.1: незакрытые служебные письма раздували контекст Deacon до 60–70 % и останавливали его. Судя по журналу, основные отказы системы — в координации, а не в написании кода.

Предела числа одновременных Polecat по умолчанию нет: scheduler.max_polecats равен -1. Чтобы не упереться в лимиты API, предел задают командой gt config set scheduler.max_polecats 5.

Кому Gas Town не нужен:

  • тем, кто ведёт одного-двух агентов и читает каждый дифф;
  • командам, где запуск агентов без подтверждений на рабочей машине недопустим;
  • проектам без автоматических тестов: очередь слияния опирается на проверки.

Что забрать себе

Пять идей и три мелких приёма переносятся в обычную работу с агентами без установки Gas Town.

  1. Держите состояние задачи вне контекста. Заведите файл или запись в трекере с назначением, шагами и заметками. Требуйте от агента записывать находки туда до завершения сессии. В Gas Town это правило звучит как bd update <задача> --notes "...".
  2. Восстанавливайте контекст хуком. Хук SessionStart в Claude Code может печатать текущую задачу и чек-лист, а PreCompact — повторять их перед сжатием.
  3. Разделите личность, песочницу и сессию. Одна задача — один worktree и одна ветка; сессий на эту ветку может быть сколько угодно. Тогда сбой или переполнение контекста стоят одного перезапуска.
  4. Запретите агентам писать в основную ветку. Пусть агент сдаёт ветку, а сливает её отдельный шаг с проверками. Из gt done стоит взять порядок: сначала отправить ветку, потом создавать запрос на слияние.
  5. Давайте процедуру чек-листом. Формула из шагов с зависимостями, показанная агенту целиком, дешевле записи каждого шага в базу. Отдельные записи шагов оставьте для долгих процедур, где потерять прогресс после сбоя дорого.

Три приёма помельче:

  • ограничивайте число перезапусков одной задачи, как делает gt sling с пределом в три попытки;
  • по умолчанию доставляйте агенту сообщение, когда он ждёт ввода, а прерывание оставьте для аварий;
  • подписывайте коммиты именем конкретного агента, чтобы сравнивать исполнителей и модели.

Оговорка к заимствованию: надзор из LLM-сессий расходует токены постоянно. При малом числе агентов его заменяет детерминированный скрипт, который проверяет, что сессия жива и в ветке появляются коммиты.

Источники

Разбор сделан по коммиту 649b832 ветки main; версия в коде — 1.2.1. Утверждения о проекте проверены по клону, исключения оговорены на месте. Код не запускался, поэтому поведение под нагрузкой здесь не оценивается. За рамками остались пошаговая установка, полный справочник команд и устройство трекера задач Beads.

Коммит 649b832 совпадает с вершиной main в удалённом репозитории на дату слепка и датирован 2026-07-23. По GitHub API у репозитория около 18,3 тысячи звёзд и последний push 2026-10-08. В какую ветку шёл этот push, по клону установить нельзя; число звёзд и история появления проекта по клону тоже не подтверждаются. Модуль Go и часть инструкций установки ссылаются на прежний адрес github.com/steveyegge/gastown.