Подагенты
Подагент — отдельная сессия snens отдельным процессом: свой журнал, свой рабочий каталог, свой ящик. Живёт, пока родитель ждёт или уже вышел.
Команды
agent start "задача" # → id в stdout
agent wait <id> [--timeout S] [--progress S]
agent status <id> # снимок без ожидания
agent result <id> # финальный текст
agent ask [<id>|--parent] [--timeout S] "вопрос" # только из подагента
agent send <id> "текст"
agent peers # id братьев построчно
agent broadcast "текст"
agent list # дерево
agent kill <id>
start печатает id и сразу выходит. wait ждёт Done в журнале ребёнка, раз в --progress секунд (по умолчанию 30, минимум 5) печатает снимок в stderr; --timeout по умолчанию 3600. status — неблокирующий снимок: жив ли, сколько ходов, последний вызов, сколько секунд назад была запись. result отдаёт последний ответ ассистента без вызовов инструментов.
Коды возврата wait
| код | что |
|---|---|
| 0 | Done в журнале: ребёнок закончил |
| 1 | процесс снят (OOM, SIGKILL), а Done нет |
| 3 | истёк таймаут: «ещё работает», это не ошибка |
| 4 | в моём ящике вопрос от ребёнка |
Код 3 повторять бессмысленно только если процесс мёртв; status различает. Код 4 — штатный разрыв дедлока «родитель ждёт ребёнка, ребёнок ждёт родителя»: wait печатает вопрос в stdout и выходит, вопрос остаётся в ящике и доедет до ближайшего хода. Ответить — agent send <id> "...", затем продолжать ждать.
Конец определяет харнесс
Done{status, turns} пишет цикл на всех путях выхода: нормальный финал, лимит ходов, ошибка. Модель к этой записи непричастна, и её словам веры нет: ребёнок может не отчитаться, отчитаться дважды или забыть после ошибки. Итог — последний ответ ассистента без вызовов, его тоже пишет цикл.
Родитель читает конец из журнала ребёнка. Единственный неразличённый случай — процесс убили наглухо: Done нет, pid мёртв; pid лежит в mail/<родитель>/children/<ребёнок>, это и есть источник признака.
Пока есть живые дети, родитель после своего финального ответа не выходит: supervisor крутится до их завершения (лимит 30 минут), иначе вопрос ребёнка некому прочитать. Дальше дети доработают отсоединёнными, но их вопросы уже никто не увидит.
ask и канал
ask — блокирующий вызов с таймаутом (по умолчанию 900 с). Вопрос уходит адресату, ответ приходит в ящик как steer не раньше момента вопроса. Родитель мёртв или таймаут — «ответа нет, действуй сам», не зависание.
Адресат: --parent (по умолчанию родитель), ребёнок, брат. Первый позиционный аргумент считается адресатом, только если за ним идёт ещё текст или такой ящик существует на диске. Канал — файлы на диске: mail/<id>/new/*.json, запись атомарная (временный файл + rename), чтение переносит в read/, ровно один потребитель. Впрыск в диалог — на границе хода, после записи всех результатов предыдущего шага.
steer человека из TUI идёт тем же каналом: строки, набранные во время хода, уезжают в ящик сессии и впрыскиваются на ближайшей границе.
Задача
Подагент не видит твой контекст — только текст задачи. Формулировка должна быть самодостаточной: что сделать, где искать, по какому признаку считать готовым. «Разберись с этим» вернётся пересказом твоего же вопроса.
Поручай то, что параллелизуется и где важен результат, а не процесс: несколько вариантов сразу, независимые проверки, разбор незнакомого кода.
Дерево и ограничения
Дерево одноуровневое: у сессии есть родитель и братья, дети — не внуки. list печатает дерево:
^ P: работает, ходов 4, запись 12 с назад
= C2: готов, ходов 1, запись 6 мин назад
> C1: работает, ходов 2, запись 1 мин назад
- G: работает, ходов 3, запись 4 с назад — проверяю сборку
Лимита на число детей и на их суммарную цену нет. Постоянный демон и сокет тоже не сделаны — впрыск уже проверен файловым ящиком.
Дальше: контекст · файлы инстанса