v1.7.0 — Reliable async jobs · token-lean result handoff · deterministic stack detection
LatestLanguages: 🇬🇧 English · 🇷🇺 Русский
🇬🇧 English
Reliability + token-efficiency release. Async
agyjobs no longer report false deaths, the worker result handoff is fully structured (no transcript mining), and the planner now plans on the project's real stack instead of guessing. Verified end-to-end with 3 coders running in parallel — 0 false-deaths, 0 retries, 192/192 tests green.
🚀 Highlights
| Area | Before | After |
|---|---|---|
| Async job death detection | Jobs that succeeded were reported failed → wasted retries |
Grace window + sidecar authority → recovered as success |
| Result handoff | Mined from the raw transcript (regex, brittle, token-heavy) | Strict result.yaml sidecar + YAML.parse validation |
| Polling cost | async_status + sleep poll loop re-billed the whole conversation |
Blocking async_wait + slim _status (Layer 0/1) |
| Planner stack | Guessed .js / node:test on a TS/bun project (2 of 3 runs) |
Orchestrator injects a stack_profile → correct .ts / bun test, first try |
🐛 Reliability — the agy false-death arc (fixed)
Root cause (confirmed via docs/plans/agy-process-lifecycle/SPEC.md): agy --print spawns an internal engine grandchild that inherits the stdout pipe and outlives the tmux pane. The session vanishes (tmux has-session → false) while the grandchild is still flushing its output and its result.yaml a few seconds later — so declaring death the instant the session disappeared reported a succeeded job as failed, and sometimes triggered a wasteful retry.
Three layered fixes:
- Run
agydirectly in the pane — removed thesetsid -wwrapper that detachedagyinto its own session (it survived the pane'sSIGHUPand ran orphaned, widening the false-death window).45572c4 - Grace window — on “session gone + no exit code + no sidecar yet” the job stays
running(deathSuspectedAtstamped) forAGY_DEATH_GRACE_MS(default 30 s, ~2× the observed ~14 s flush gap), then the sidecar fallback marks itsuccessonceresult.yamllands. Bounded by the wall-clockAGY_TIMEOUT_MS.f53fa2b - Late sidecar recovery — a job already marked
failedonly via the premature-death path is re-checked againstresult.yamland upgraded tosuccessif the envelope parses (strictly scoped — never a real non-zero exit, parse error, or crash-monitor137).45572c4
Before: session gone @50s ──▶ FAILED ──▶ retry (work was already done)
After: session gone @50s ──▶ running (grace) ──▶ result.yaml @64s ──▶ SUCCESS
⚡ Token efficiency — structured result handoff
- Layer 0 — envelope only.
async_resultreturns just the worker'sresult:envelope, never the raw transcript.c7676c5 - Layer 1 — blocking wait + slim status. New
async_waitblocks server-side until the batch settles;async_statusslimmed. Kills thestatus-poll-sleeploop.179fcaf·f33dd6e result.yamlsidecar. The worker writes its envelope to a file as its last action; the server reads that file instead of scraping stdout.d8e230a- Strict validation. Server-side
YAML.parse(top-levelresult:mapping required).54571b7
📉 A monitored run went from ~158 antigravity calls + 10
sleeps to 6 calls, 0 sleeps.
🎯 Planner — deterministic stack detection
The planner runs on graph-only tools (gitnexus / serena), and package.json scripts.test is not in the code graph — so it couldn't see bun test vs node --test and fell back to a wrong guess. Fix (2b9564e):
- Orchestrator injects a
stack_profile— before dispatch itReadspackage.json+ls-es the target dir and passes authoritative facts (language,file_ext,test_command,test_file) into the contract. - Planner reads the manifest first — stack detection is now Step 1; the
NOT raw greprule was narrowed to repo-wide grep only (targeted single-file reads allowed any time).
✅ Verified live: planner produced
src/utils/*.ts+bun test+dependencies: []on the first try, no correction round.
🧰 Other improvements
- Skills catalog auto-generated from the runtime skill dir, 12 categories, + sync test.
a3430e3·a3c181d·5733777 - MCP config isolation into the per-session
agyworker home.ab80f2b - Usage metric — average successful-job duration.
d87eca2 async_waitadded to thedev-orchestrator-agytools allowlist + made the universal await.f33dd6e- 📚 Docs — comprehensive bilingual README (architecture, async engine, worker roster, full tool & env reference).
9c7c4c3
✅ Verification
bun run build— clean ·bun test— 192 pass / 0 fail (24 files).- End-to-end parallel run (
takeWhile/dropWhile/partition): 3 coders dispatched concurrently, planner emitted correct.ts/bun testwith no correction round, 2 of 3 coders hit the grandchild detach and were recovered assuccess— 0 false-deaths, 0 retries, clean fast-forward push.
🇷🇺 Русский
Релиз про надёжность и экономию токенов. Async-джобы
agyбольше не отчитываются ложной смертью, передача результата воркера полностью структурирована (без выскребания транскрипта), а планировщик теперь планирует на реальном стеке проекта, а не угадывает. Проверено сквозным прогоном с 3 кодерами параллельно — 0 ложных смертей, 0 ретраев, 192/192 теста зелёные.
🚀 Главное
| Область | Было | Стало |
|---|---|---|
| Детект смерти async-джобы | Успешные джобы отчитывались как failed → лишние ретраи |
Grace-окно + авторитет сайдкара → восстановление в success |
| Передача результата | Выскребалась из сырого транскрипта (регексп, хрупко, дорого по токенам) | Строгий сайдкар result.yaml + валидация YAML.parse |
| Стоимость поллинга | Петля async_status + sleep перебиливала весь диалог |
Блокирующий async_wait + слим _status (Layer 0/1) |
| Стек планировщика | Угадывал .js / node:test на TS/bun-проекте (2 из 3 прогонов) |
Оркестратор инжектит stack_profile → корректные .ts / bun test с первого раза |
🐛 Надёжность — арк ложной смерти agy (исправлено)
Корень (подтверждён через docs/plans/agy-process-lifecycle/SPEC.md): agy --print порождает внутренний engine-внук, который наследует stdout-pipe и переживает tmux-pane. Сессия исчезает (tmux has-session → false), пока внук ещё дописывает вывод и result.yaml через несколько секунд — поэтому объявление смерти в момент исчезновения сессии отчитывало успешную джобу как failed и иногда запускало лишний ретрай.
Три слоя фикса:
- Запуск
agyпрямо в pane — убран обёрткаsetsid -w, отвязывавшаяagyв свою сессию (он переживалSIGHUPpane и работал «сиротой», расширяя окно ложной смерти).45572c4 - Grace-окно — при «сессия исчезла + нет exit-кода + нет сайдкара» джоба остаётся
running(deathSuspectedAt) наAGY_DEATH_GRACE_MS(по умолчанию 30 с, ~2× от наблюдаемых ~14 с задержки записи), затем сайдкар-фолбэк помечает еёsuccess, как толькоresult.yamlприлетит. Ограничено wall-clockAGY_TIMEOUT_MS.f53fa2b - Позднее восстановление по сайдкару — джоба, помеченная
failedтолько через путь преждевременной смерти, перепроверяется противresult.yamlи апгрейдится доsuccess, если конверт парсится (строго — никогда для реального ненулевого кода, parse-error или kill-137 краш-монитора).45572c4
Было: сессия исчезла @50с ──▶ FAILED ──▶ ретрай (работа уже сделана)
Стало: сессия исчезла @50с ──▶ running (grace) ──▶ result.yaml @64с ──▶ SUCCESS
⚡ Экономия токенов — структурированная передача результата
- Layer 0 — только конверт.
async_resultвозвращает только конвертresult:воркера, никогда сырой транскрипт.c7676c5 - Layer 1 — блокирующее ожидание + слим-статус. Новый
async_waitблокирует на сервере до завершения батча;async_statusужат. Убивает петлюstatus-sleep.179fcaf·f33dd6e - Сайдкар
result.yaml. Воркер пишет конверт в файл последним действием; сервер читает файл, а не выскребает stdout.d8e230a - Строгая валидация. Серверный
YAML.parse(нужен top-levelresult:).54571b7
📉 Один прогон ушёл со ~158 вызовов antigravity + 10
sleepдо 6 вызовов, 0 sleep.
🎯 Планировщик — детерминированный детект стека
Планировщик работает на только графовых инструментах (gitnexus / serena), а scripts.test из package.json нет в графе кода — поэтому он не видел bun test против node --test и скатывался к неверной догадке. Фикс (2b9564e):
- Оркестратор инжектит
stack_profile— перед раздачей онRead-итpackage.json+ls-ит целевую папку и передаёт авторитетные факты (language,file_ext,test_command,test_file) в контракт. - Планировщик читает манифест первым — детект стека теперь Шаг 1; правило
NOT raw grepсужено до repo-wide grep (точечное чтение одного файла разрешено в любой момент).
✅ Проверено в живую: планировщик выдал
src/utils/*.ts+bun test+dependencies: []с первого раза, без круга коррекции.
🧰 Прочие улучшения
- Авто-генерация каталога скиллов из рантайм-папки, 12 категорий, + sync-тест.
a3430e3·a3c181d·5733777 - Изоляция MCP-конфига в per-session домашку воркера
agy.ab80f2b - Метрика usage — средняя длительность успешной джобы.
d87eca2 async_waitдобавлен в allowlist инструментовdev-orchestrator-agy+ сделан универсальным ожиданием.f33dd6e- 📚 Документация — подробный двуязычный README (архитектура, async-движок, реестр воркеров, полная справка по инструментам и env).
9c7c4c3
✅ Проверка
bun run build— чисто ·bun test— 192 pass / 0 fail (24 файла).- Сквозной параллельный прогон (
takeWhile/dropWhile/partition): 3 кодера раздались одновременно, планировщик выдал корректные.ts/bun testбез круга коррекции, 2 из 3 кодеров словили детач внука и были восстановлены вsuccess— 0 ложных смертей, 0 ретраев, чистый fast-forward push.
📦 Full commit log (v1.6.1...v1.7.0)
2b9564e fix(planner): deterministic stack detection — orchestrator injects stack_profile + planner reads manifest first
f53fa2b fix(jobs): grace window for agy grandchild — stop false-death before sidecar flush
45572c4 fix(jobs): eliminate false-death of agy jobs — run agy in pane, recover via sidecar
0f58594 fix(jobs): stop intermittent "tmux died before echo" false-crashes + planner stack detection
f33dd6e fix(orchestrator-agy): add async_wait to the agent tools allowlist + make it the universal await
54571b7 feat(result): strict server-side YAML.parse validation of result envelopes
d8e230a feat(result): result.yaml sidecar — strict, file-based result handoff (no transcript mining)
179fcaf perf(polling): Layer 1 — blocking batch wait + slim _status (cut polling token burn)
c7676c5 feat(result): Layer 0 — return only the result envelope, never the raw transcript
a3430e3 feat(skills): generate catalog from the runtime skill dir, grouped by category
a3c181d refactor(skills): drop the per-role DEFAULT table from the catalog
5733777 feat(skills): described auto-generated catalog + de-dup defaults + sync test
ab80f2b fix(isolation): propagate MCP config to agy worker home (gitnexus/serena/postgres/perplexity)
d87eca2 feat(usage): add average successful job duration metric
3c5a9ec test(usage): cover average successful job duration metric
ad25053 chore: remove test-run artifacts (validate, debounce, zod dep)
9c7c4c3 docs: comprehensive bilingual README (GitNexus-grade)
Test fixtures (small sample utilities added while validating the orchestrator end-to-end, each with unit tests + public export): chunk, clamp, uniqueBy, flatten, takeWhile, dropWhile, partition.
Compare: v1.6.1...v1.7.0
🤖 Generated with Claude Code