snens

Подагенты

Подагент — отдельная сессия 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

кодчто
0Done в журнале: ребёнок закончил
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 с назад — проверяю сборку

Лимита на число детей и на их суммарную цену нет. Постоянный демон и сокет тоже не сделаны — впрыск уже проверен файловым ящиком.

Дальше: контекст · файлы инстанса