Перейти к содержимому
Борис Новичков
РезюмеGitHub ↗
ENRU
Все работы

Мост YouGile → агент

Упомяните агента в чате задачи, и он начнёт работать в вашем репозитории

Приёмник вебхуков, превращающий обсуждение в трекере в сессию разработки. Упоминание агента в задаче YouGile поднимает Claude Code в заданном рабочем каталоге, причём чат каждой задачи отображается один в один на постоянную сессию, поэтому агент помнит нить, когда его упоминают снова.

В работе
Роль
Автор
Период
май 2026 — н. в.
путь запроса
YouGile ──POST──▶ https://your.domain/yougile/webhook                      ▼  FRP / cloudflared / ngrok / nginx — your choice                  127.0.0.1:9100   (this service)                      ▼  first matching rule in rules.toml                  claude --dangerously-skip-permissions                  cwd = rule.workdir                  --session-id <chatId>   (first time on this chat)                  --resume     <chatId>   (subsequent)

Полный путь от упоминания в чате до работающего агента, как он описан в README проекта.

Идея

Расстояние между «надо бы это починить» в трекере задач и сессией разработки — это в основном копирование: текст задачи, репозиторий, контекст уже сказанного. Мост его закрывает. Упомяните агента в чате задачи YouGile — и он поднимет Claude Code в том рабочем каталоге, на который указывает правило этой задачи.

Пригодным к работе, а не демонстрацией, это делает отображение сессий. Чат каждой задачи получает идентификатор сессии Claude, выведенный из идентификатора чата, поэтому первое упоминание сессию начинает, а каждое следующее её продолжает. Разговор в трекере и разговор с агентом — это один и тот же разговор.

Маршрутизация — это конфигурация, а не код

Какой репозиторий ведёт задача, решает первое подошедшее правило в rules.toml, рядом с шаблоном промпта для этого триггера. Добавить в схему новый проект — изменение конфига; никакой логики диспетчеризации править не нужно.

Большая часть работы — обработка отказов

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

Поведение выше — результат. Отдельно стоит принудительный IPv4: сломанный или полуоткрытый маршрут IPv6 выдавал SSL handshake timed out на хосте, который в остальном был совершенно здоров, тогда как curl подключался мгновенно. У urllib нет Happy Eyeballs, поэтому он сидел на мёртвом AAAA-адресе до таймаута. Отбрасывание AAAA-ответов — с запасным вариантом для хостов, публикующих только их, — заставило целый класс отказов исчезнуть.

Второе — /healthz. Он намеренно никогда не ходит в API YouGile, потому что проверка здоровья, зависящая от того, о чём она должна докладывать, перестаёт отвечать ровно тогда, когда ответ нужен. Он возвращает разобранный набор правил, последний известный снимок подписки от фонового наблюдателя и то, как давно тикал цикл событий.

что держит его живым в плохой сети
Forced IPv4
Полуоткрытый маршрут IPv6 подвешивает urllib до таймаута — Happy Eyeballs там нет. Отбрасывание AAAA-записей убирает целый класс отказов.
Capped exponential backoff
Каждый вызов API и каждая загрузка вложения повторяются при сетевых ошибках, таймаутах и 429/5xx.
Permanent vs transient
4xx не повторяется никогда — повтор отказа просто прячет его.
Self-healing subscription
Наблюдатель оживляет отключённую на той стороне подписку и повторяет неудавшийся цикл через 60 секунд, а не ждёт следующего прохода.
Event-loop watchdog
Если цикл asyncio заклинило, процесс перезапускается, а не остаётся молча «живым».
Non-blocking /healthz
Возвращает разобранный набор правил и возраст удара сердца цикла, не обращаясь к YouGile, — поэтому остаётся правдивым, когда сети нет.

Каждый из этих пунктов появился из конкретного сбоя, увиденного на практике.