Вернуться к блогу

Сортировка заблокированных задач в параллельной разработке

Теперь вы можете запускать 10 ИИ-агентов параллельно. Дайте каждому задачу, направьте их на общую базу данных beads и пусть работают. Агенты создают подзадачи, регистрируют обнаруженные баги, обновляют статусы и закрывают задачи по завершении. Это действительно продуктивно.

Пока что-то не заблокируется.

Когда человек заблокирован, он сообщает. Пишет в Slack, отмечает на стендапе, подходит к чьему-то столу. Агенты ничего из этого не делают. Агент натыкается на зависимость, которую не может разрешить, и либо тихо останавливается, либо начинает обходить проблему способами, которые создают ещё больше проблем. Три агента могут застрять на одной и той же неразрешённой вышестоящей задаче, и вы не узнаете, пока не удивитесь, почему за четыре часа ничего не выкатилось.

Это проблема сортировки для агентной разработки. Не "как проводить лучшие стендапы", а "как видеть, что застряло, среди флота автономных работников, которые не жалуются." Вот что мы узнали, создавая Beadbox, панель реального времени для beads, которая показывает, что именно делают ваши агенты, на чём они заблокированы и что только что стало доступным.

Перейти к нужному разделу:

Как агенты создают блокирующие цепочки

Агенты порождают проблемы с зависимостями иначе, чем человеческие команды. Понимание режимов отказа важно, потому что реакции при сортировке различаются.

Агенты не моделируют зависимости заранее. Человек-архитектор декомпозирует фичу на задачи и думает о порядке. Агент получает задачу, начинает работать и обнаруживает в процессе реализации, что ему нужно что-то, чего ещё не существует. Он может создать новую задачу для этой зависимости. Может попытаться реализовать её на месте и создать хаос. Может просто остановиться. Ни один из этих исходов не виден, если вы не наблюдаете за базой данных задач.

Агенты работают быстрее, чем обновляются графы зависимостей. Agent-3 закрывает задачу, которую ждал Agent-7, но Agent-7 не знает об этом, потому что проверял блокеры 10 минут назад. Тем временем Agent-7 по-прежнему простаивает или работает над чем-то менее приоритетным. Разблокировка произошла, но информация не распространилась.

Циклические зависимости возникают из параллельной декомпозиции. Когда несколько агентов одновременно декомпозируют работу, они могут создать циклы, которые ни один агент по отдельности не видит. Agent-1 создаёт Задачу A, зависящую от Задачи B. Agent-2 создаёт Задачу B, зависящую от Задачи C. Agent-3 создаёт Задачу C, зависящую от Задачи A. Каждая зависимость имела смысл локально. Цикл виден только сверху.

Конкуренция за ресурсы невидима. Два агента должны изменить один и тот же файл, или обоим нужна staging-среда, или обоим нужна та же разделяемая библиотека в стабильном состоянии. Зависимость не зафиксирована, потому что ни один агент не знает о существовании другого. Оба просто замедляются, и ни один не сообщает почему.

Общая нить: агенты создают блокирующие ситуации быстрее, чем сообщают о них. Супервайзеру (вам) нужны инструменты, которые автоматически выявляют блокировки, а не инструменты, которые ждут, пока кто-то подаст сигнал.

Автоматическое обнаружение зависимостей

Решение -- явные, запрашиваемые данные о зависимостях, создаваемые при создании задач и проверяемые непрерывно. Вот как это выглядит с beads, Git-нативным трекером задач, на котором мы запускаем наш флот агентов.

Агенты фиксируют зависимости при создании задач:

# Агент создаёт задачу и обнаруживает, что нужен ещё не существующий API
API_TASK=$(bd create \
  --title "Implement /api/v2/orders endpoint" \
  --type task --priority 2 --json | jq -r '.id')

# Агент создаёт свою задачу и объявляет зависимость
UI_TASK=$(bd create \
  --title "Build order history page" \
  --type task --priority 2 --json | jq -r '.id')

bd dep add "$UI_TASK" "$API_TASK"

Этот bd dep add -- один вызов CLI. Любой ИИ-агент (Claude Code, Cursor, Copilot Workspace) может его выполнить. Без клиентской библиотеки API, без танцев с аутентификацией. Зависимость теперь -- структурированные данные, запрашиваемые любым другим агентом или скриптом.

Обнаружение циклов запускается автоматически:

# beads проверяет полный граф зависимостей на циклы
bd dep cycles

# Вывод при наличии циклов:
# CYCLE DETECTED: beads-a1b -> beads-c3d -> beads-e5f -> beads-a1b

На графе из 5 000 зависимостей это занимает ~70 мс. Запускайте как post-commit hook или по 5-минутному cron. Когда три агента независимо создают цикл зависимостей, вы обнаруживаете его за минуты, а не через часы, когда все трое застряли.

Все заблокированные задачи одной командой:

bd blocked --json | jq -r '.[] |
  "BLOCKED: \(.id) \(.title)\n  waiting on: \(.blocked_by | join(", "))\n  assignee: \(.owner // "unassigned")\n"'

Вывод:

BLOCKED: beads-x7q Build order history page
  waiting on: beads-m2k Implement /api/v2/orders endpoint
  assignee: agent-3

BLOCKED: beads-r4p Deploy staging environment
  waiting on: beads-j9w Fix Docker build, beads-n1c Update TLS certificates
  assignee: agent-7

Теперь вы знаете, что Agent-3 и Agent-7 застряли, на чём именно, и что нужно сделать для разблокировки. Весь запрос занял 30 мс на базе из 10K задач.

Обнаружение заблокированных PR через соглашения об именовании веток:

#!/bin/bash
# blocked-prs.sh: find PRs whose dependencies haven't merged

for pr in $(gh pr list --json number,headRefName --jq '.[].headRefName'); do
  ISSUE_ID=$(echo "$pr" | grep -oE 'beads-[a-z0-9]+')
  [ -z "$ISSUE_ID" ] && continue

  BLOCKERS=$(bd show "$ISSUE_ID" --json | jq -r '.blocked_by[]' 2>/dev/null)
  for blocker in $BLOCKERS; do
    BLOCKER_STATUS=$(bd show "$blocker" --json | jq -r '.status')
    if [ "$BLOCKER_STATUS" != "closed" ]; then
      echo "PR ($pr) blocked: $ISSUE_ID waiting on $blocker ($BLOCKER_STATUS)"
    fi
  done
done

Двадцать строк shell. Запускается локально, читает локальные данные, сообщает, какие PR от ваших агентов ещё не могут быть смержены и почему.

CLI-first рабочий процесс сортировки

Triage в агентном рабочем процессе -- это не встреча. Это скрипт, запускаемый в цикле. Супервайзер (человек или агент) смотрит, что застряло, и принимает решение по каждому пункту.

Вот скрипт сортировки, который мы реально запускаем:

#!/bin/bash
# triage.sh: agentic fleet blocker triage

echo "========================================="
echo "TRIAGE REPORT: $(date +%Y-%m-%d %H:%M)"
echo "========================================="

# 1. Что заблокировано?
echo -e "\n--- BLOCKED TASKS ---"
bd blocked --json | jq -r '.[] |
  "[\(.priority)] \(.id) \(.title)
    blocked by: \(.blocked_by | join(", "))
    assignee: \(.owner // "unassigned")\n"'

# 2. Что доступно для агентов?
echo -e "\n--- READY (unblocked, open) ---"
bd ready --json | jq -r '.[] |
  "[\(.priority)] \(.id) \(.title) (\(.owner // "unassigned"))"'

# 3. Какие агенты замолчали?
echo -e "\n--- STALE IN-PROGRESS (no update in 2h) ---"
CUTOFF=$(date -v-2H +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -d '2 hours ago' --iso-8601=seconds)
bd list --status=in_progress --json | jq -r --arg cutoff "$CUTOFF" '.[] |
  select(.updated_at < $cutoff) |
  "STALE: \(.id) \(.title) (last update: \(.updated_at), assignee: \(.owner // "unknown"))"'

# 4. Здоровье зависимостей
echo -e "\n--- DEPENDENCY CYCLES ---"
bd dep cycles 2>&1 || echo "No cycles detected."

echo -e "\n--- FLEET STATS ---"
bd stats

Для человеческих команд "устаревшая" означает 48 часов без обновления. Для агентов 2 часа тишины при задаче в работе -- красный флаг. Либо агент застрял и не сообщает, либо упал. В любом случае нужно проверить.

Дерево решений для каждого заблокированного пункта:

  1. Может другой агент разблокировать? Повысить приоритет блокирующей задачи, назначить свободного агента.
  2. Зависимость ложная? Агенты иногда создают перестраховочные зависимости при планировании. Если блокировка нереальная, удалите: bd dep remove beads-x7q beads-m2k (удаляет зависимость x7q от m2k, мгновенно разблокируя x7q).
  3. Можно разделить работу? Пусть заблокированный агент делает части, не требующие зависимости. Создать follow-up задачу для остального.
  4. Внешняя блокировка? Что-то, что может решить только человек (API-ключ, дизайн-решение, доступ). Пометить, записать ожидаемое решение, переназначить агента на другую доступную работу.

Вариант 2 с агентами случается постоянно. Они моделируют зависимости на основе понимания кодовой базы в момент планирования. Как только начинается реализация, реальная форма работы показывает, что половина этих зависимостей была лишней.

Видимость работы агентов в реальном времени

Запуск скрипта сортировки каждые 30 минут оставляет пробелы. Когда агенты работают быстро, между проверками происходит многое. Вопрос: можно ли видеть формирование блокировок в реальном времени?

Как это делает Beadbox:

База данных beads живёт в директории .beads/ на вашей файловой системе. Каждый bd update, bd create или bd close от агента пишет в эту директорию. Beadbox следит за ней через fs.watch() и передаёт изменения в UI через WebSocket за миллисекунды.

Практический эффект: Agent-5 выполняет bd update beads-x7q --status=closed в терминале. Панель Beadbox немедленно показывает задачу закрытой, и любая задача, которая была ей заблокирована, подсвечивается как только что доступная. Вы видите каскад без выполнения команды.

Это важно, потому что агентная работа идёт всплесками. Агент может закрыть три задачи за 90 секунд, каждая разблокирует разные последующие работы. Polling-панель с 30-секундным интервалом обновления показала бы запутанное промежуточное состояние. Передача менее чем за секунду показывает полную картину в момент её формирования.

Если вы не используете Beadbox, наблюдение за файловой системой всё равно работает:

# Watch the beads database for changes, alert on new blocks
# Note: fswatch fires on every write. In production you'd debounce this
# (e.g., sleep 2 after each trigger) to avoid noise during burst writes.
fswatch -o .beads/ | while read; do
  BLOCKED_COUNT=$(bd blocked --json | jq length)
  if [ "$BLOCKED_COUNT" -gt 0 ]; then
    echo "$(date): $BLOCKED_COUNT tasks currently blocked"
    # Pipe to ntfy, Slack webhook, or any notification system
  fi
done

Замкнуть цикл через CI:

# In your CI post-build step: auto-close the issue when the build passes
if [ "$BUILD_STATUS" = "success" ]; then
  ISSUE_ID=$(echo "$BRANCH_NAME" | grep -oE 'beads-[a-z0-9]+')
  if [ -n "$ISSUE_ID" ]; then
    bd update "$ISSUE_ID" --status=closed
    bd comments add "$ISSUE_ID" --author ci \
      "Build passed. Commit: $COMMIT_SHA. Closing automatically."
  fi
fi

Когда CI закрывает эту задачу, всё, что она блокировала, разблокируется. Если агент следит за bd ready на предмет новой работы, он подхватывает разблокированную задачу автоматически. Без человека в цикле для рутинных разблокировок.

Это разница между инструментами, которые отслеживают статус, и инструментами, которые его распространяют. Большинство ПО для управления проектами делает первое: вы обновляете карточку, карточка меняет цвет. Распространение означает, что последующие эффекты (разблокировка зависимых, показ доступной работы, обновление сводки прогресса) происходят без единого клика.

Оценка инструментов сортировки для агентных рабочих процессов

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

Обязательно: CLI, которую агенты могут вызывать. Если ваш трекер имеет только веб-интерфейс, агенты не смогут им пользоваться. Им нужны shell-команды. bd create, bd update, bd blocked -- однострочники, которые любой агент уже умеет выполнять. REST API тоже работают, но требуют auth-токенов, HTTP-клиентов и обработки ошибок. Unix-каналы проще.

Обязательно: запрашиваемый граф зависимостей. "Заблокирован" как метка статуса бесполезен для автоматизации. Вам нужно A зависит от B как структурированные данные, чтобы скрипты могли обходить граф, обнаруживать циклы и вычислять, что готово.

Обязательно: локальное чтение менее чем за секунду. Когда агенты запрашивают доступную работу, время отклика критично. 2-секундный API round-trip на запрос, умноженный на 10 агентов, опрашивающих каждую минуту, создаёт измеримые накладные расходы. beads возвращает результаты bd ready за 30 мс на базе из 10K задач, потому что всё локально.

Желательно: распространение изменений в реальном времени. Если агенты создают и разрешают 50 задач в час, вам нужно видеть состояние по мере изменения, а не по интервалу обновления.

Красный флаг: "ИИ-обнаружение блокеров." Инструменты, которые утверждают, что обнаруживают блокеры анализом описаний задач, генерируют ложные срабатывания и пропускают реальные блокеры, которые никогда не были записаны. Явные объявления bd dep add лучше вывода.

Красный флаг: инструменты, требующие браузер для сортировки. Разблокировка одной задачи через веб-интерфейс занимает 5-15 секунд кликов. Через CLI bd dep remove занимает 18 мс. На 50 заблокированных задачах это 1 минута против 12 минут. Когда вы наблюдаете за быстро работающими агентами, скорость сортировки -- ваше узкое место.

Как популярные инструменты обрабатывают блокировки

Возможность Jira Linear GitHub Issues beads + Beadbox
Отслеживание зависимостей Плагин (Advanced Roadmaps) Relations (частично) Ссылки Tasklist First-class bd dep add
Автостатус "заблокирован" Вручную Вручную Вручную Автоматически из deps
Обнаружение циклов Нет Нет Нет Встроено (bd dep cycles)
CLI для агентов Jira CLI (сторонний) Linear CLI (ограничен) gh (без deps) Полный (bd blocked, bd ready)
Распространение в реальном времени Webhook (серверный) Webhook (серверный) Webhook (серверный) fs.watch (менее секунды, локально)
Работа офлайн/локально Нет Нет Нет Да (embedded-режим)
Скриптуемый агентами API + auth-токены API + auth-токены gh CLI bd CLI (Unix-каналы)

Цикл супервайзера

Вот рабочий процесс, который мы выполняем ежедневно, управляя 10+ ИИ-агентами на одном проекте:

  1. Агенты объявляют зависимости при создании задач. Каждый bd create, имеющий зависимость, сразу получает bd dep add. Это один дополнительный вызов CLI на задачу.

  2. Агент-супервайзер запускает bd blocked каждые 30 минут. Если что-то новое заблокировано, он либо разрешает блокер сам (переприоритизировать, переназначить), либо сигнализирует человеку.

  3. Beadbox работает на экране человека. Панель показывает полный граф зависимостей с заблокированными задачами, подсвеченными в реальном времени. Обычно автоматизация справляется с рутинными разблокировками. Когда не может (внешняя зависимость, архитектурное решение, доступ), человек видит проблему немедленно и вмешивается.

  4. Устаревшие задачи отмечаются агрессивно. Агент, не обновлявший свою задачу в работе 2 часа, либо застрял, либо упал. Супервайзер проверяет и либо подталкивает агента, переназначает работу, либо исследует проблему.

  5. Ложные зависимости непрерывно подчищаются. Агенты избыточно объявляют зависимости при планировании. По мере того как реализация показывает реальную форму работы, супервайзер (или сами агенты) удаляют зависимости, оказавшиеся ненужными. Чистый граф -- полезный граф.

Основной принцип: агенты быстрые, но не обладают самосознанием. Они не знают, что делают другие агенты, не замечают, когда блокеры разрешаются, и не жалуются, когда застряли. Задача супервайзера -- быть нервной системой, которая всё это связывает. Структурированные данные о зависимостях, автоматически запрашиваемые и визуально отображаемые -- вот что делает это возможным.


Beadbox бесплатен в период бета-тестирования. Он показывает, что делают ваши агенты, что заблокировано и что только что стало доступным, в реальном времени.

brew tap beadbox/cask && brew install --cask beadbox

Если вы уже используете beads, Beadbox читает вашу существующую директорию .beads/ без шага импорта. Попробуйте.