Перейти до змісту

Керування циклом

ЦільЗапустити, поставити на паузу, відновити й зупинити цикл і розуміти його коди виходу.

Як побудований цикл

Цикл — це дві програми, вкладені одна в одну. Supervisor працює годинами; runner виконує один юніт і виходить.

ШарЖивеРобить
supervisorвесь запускбере лок, запускає батчі юнітів, читає PAUSE і STOP між юнітами, реагує на коди виходу, пересиджує ліміти
runnerодин юнітбере задачу, робить знімок, запускає координатора, перевіряє контракти, записує результат, виходить з кодом
координатородин юнітпроцес claude -p: читає задачу і викликає спеціалістів
спеціалістичастину юнітакожен робить одну вузьку роботу і лишає вердикт
контрактикінець юнітаscope, task file, trace, gate, closing: код, який вирішує, чи зараховується юніт

Пройди п'ять запусків, щоб побачити, який шар зайнятий, що лежить у теці трейсу і як відпрацьовують пауза, стоп, жорстка зупинка і ліміт.

Цикл: supervisor, runner, координатор, спеціалісти і контракти
supervisorвесь запускпрацює
runnerодин юніт
координаторclaude -p
спеціалістипо одній роботі
контрактиперевірки кодом

Юніти

    .harness/trace/

    • supervisor.lock
    harness run запускає supervisor. Він бере лок .harness/trace/supervisor.lock, тож другий цикл на цьому checkout відмовиться стартувати.
    Крок 1 з 6

    Кожна команда нижче приймає --project: шлях або id чи назву, під якою проєкт зареєстровано. Без нього команда бере поточну теку, і в ній має бути тека .harness/. Приклади використовують зразковий проєкт демо, створений і зареєстрований командою harness example ~/code/bookmarks; назва проєкту за замовчуванням — назва теки.

    Старт

    У дашборді натисни Start. Він запускає harness run --project <path> як відв'язаний процес з оточенням самого дашборду, а його вивід іде в .harness/trace/supervisor.out. Кнопки Pause, Resume і Stop у дашборді пишуть ті самі файли, що й CLI; дашборд ніколи не шле сигналів і не вбиває процесів. Його док показує supervisor як Running, Paused, Stopping (STOP записано, юніт доробляє) або Not running. Кнопка називає, кого запускає Start: Start · claude або Start · stand-in, коли задано AGENT_CMD чи agent.command; перший рядок дашборду в терміналі каже те саме.

    З термінала:

    harness run --project bookmarks
    

    За замовчуванням запуск не закінчується, коли черга порожня: він перевіряє нову роботу кожні supervisor.idlePollSeconds (30 секунд за замовчуванням), доки ти його не зупиниш. Людська дія будить його одразу: подання, відповідь чи схвалення — з CLI або з дашборду — потрапляє в журнал людських записів, а supervisor у простої перевіряє цей файл кожні supervisor.pausePollSeconds (2 секунди). Ці опції це змінюють, а harness unit запускає один юніт, щоб спробувати:

    harness run --project bookmarks --deadline 120   # a time limit for the run, in minutes
    harness run --project bookmarks --max-units 5    # at most five units
    harness run --project bookmarks --once-through   # exit as soon as nothing is left to take
    harness unit --project bookmarks                 # exactly one unit; exits with the runner's code
    

    Дві команди варто запустити спершу, і жодна не витрачає токенів:

    harness agents --check --project bookmarks   # the registry, standing-rules drift, the model split
    harness preview T-002 --project bookmarks    # the exact command and prompt of the next unit
    

    Перед першим юнітом supervisor перевіряє дві речі й відмовляється стартувати, якщо хоч одна не виконана:

    • На цьому checkout не працює інший цикл. Весь запуск він тримає лок-файл .harness/trace/supervisor.lock.
    • Базова гілка чиста. Він відмовляється працювати на брудному дереві, яке забруднив не він, бо контракт scope повісив би твої зміни на агента.

    Одразу після рядка старту він пише рядок supervisor · billing: … — як тарифікується запуск, за оточенням, у якому він стартує:

    РядокКоли
    billing: subscription login — usage limits, not a per-token bill; costs shown are API-equivalentclaude залогінений через підписку
    billing: ANTHROPIC_API_KEY is set — claude -p bills the API per tokenв оточенні є ANTHROPIC_API_KEY
    billing: a stand-in replaces claude — no tokensзадано AGENT_CMD або agent.command

    На підписці вартість у дашборді й у harness stats — це те, скільки ті самі токени коштували б через API. Це не рахунок.

    Пауза і відновлення

    harness pause --project bookmarks
    harness resume --project bookmarks
    

    harness pause створює файл .harness/trace/PAUSE. harness resume видаляє його. Кнопки Pause і Resume у дашборді пишуть той самий файл.

    Пауза не перериває юніт, що зараз працює. Supervisor читає файл між юнітами, тож поточний юніт доробляє, його контракти проганяються, і лише тоді цикл чекає.

    Стоп

    harness stop --project bookmarks
    

    harness stop створює .harness/trace/STOP. Supervisor доробляє поточний юніт, виходить і не повертається, доки ти не запустиш його знову.

    Якщо треба зупинити негайно, зупини процес supervisor, який ти запустив, за його PID. Оскільки стан живе на диску, втратиш лише юніт, що працював. Ніколи не вбивай процеси за шаблоном (pkill -f, killall): шаблон зачіпає значно більше, ніж здається, включно з іншими сесіями Claude.

    Коди виходу

    Кожен юніт завершується кодом виходу від runner. Supervisor читає його і вирішує, що робити далі.

    Код runnerЗначенняЩо далі
    0юніт готовийsupervisor бере наступний юніт
    1жорстка зупинка: scope, файл задачі, trace, gate або падіння агентаробота юніта йде в іменований stash, задачу запарковано, supervisor продовжує
    2конфігурація зламана: config.json, постійні правила, що розійшлися, або суддя на моделі implementer чи testersupervisor зупиняється: чекання не допоможе
    3брати більше нічогоsupervisor чекає нову роботу; з --once-through завершує запуск
    4агент не зміг запуститися: ліміт, мережа, логінsupervisor чекає й пробує знову

    Жорстка зупинка нічого не викидає. Runner переносить зміни юніта в git stash з назвою harness quarantine: T-NNN unit N, відновлює дерево і записує причину в задачу. Можеш переглянути stash, перш ніж перевідкрити задачу.

    У supervisor є власні коди виходу — для моменту, коли закінчується весь запуск. Числа ті самі, а значення інші: код 3 від runner — порожня черга, а код 3 від supervisor — застряглий цикл.

    Код supervisorЧому запуск закінчився
    0його зупинили, черга спорожніла під --once-through, або вичерпано дедлайн чи --max-units
    2конфігурація зламана, або увімкнено deliver.pr, а бракує remote, gh, входу в нього чи базової гілки на remote
    3безплідний: три юніти поспіль нічого не зрушили
    4він здався, чекаючи на агента

    Правило безплідності не дає застряглому циклу крутитися вхолосту: три юніти поспіль, які нічого не зрушили, зупиняють його. Прогрес — це нові коміти або нові handoff, а не щось одне.

    Ліміти і збої

    Код 4 означає, що агент так і не взявся до роботи, тож задачу не зачеплено. Supervisor чекає і пробує знову: перевіряє мережу кожні 30 секунд, а коли мережа в порядку, але агенту все одно відмовляють, наприклад через ліміт, бере 30-хвилинну перерву перед наступною спробою. Коли відмова називає час скидання, наприклад «You've hit your session limit · resets 9:10pm (Europe/Kiev)», він чекає до цього часу плюс одна хвилина і пише в лог agent could not run (…) — waiting until <time>. Ліміти сесії й тижневі ліміти теж рахуються як ліміти використання. Після шести годин очікування здається і зупиняється з кодом 4. Ці інтервали — supervisor.usageProbeSeconds, supervisor.usageNapSeconds і supervisor.usageCeilingSeconds у config.json.

    Проєкт може додати власну команду probe: у config.json, наприклад перевірку, що dev-сервер відповідає. Коли probe падає, юніт завершується з кодом 4 і нічого не чіпає.

    Не редагуй, поки працює юніт

    Контракт scope порівнює все робоче дерево до і після юніта. Він не відрізнить твою правку від правки агента. Якщо ти збережеш файл у проєкті, поки працює юніт, юніт впаде, а задачу запаркують за те, що зробив ти.

    Безпечний порядок:

    1. Постав на паузу.
    2. Дочекайся, поки поточний юніт завершиться. Дашборд показує, коли нічого не в роботі.
    3. Зроби правку і закоміть її.
    4. Віднови.

    Виняток — дії над задачами. Approve, answer, revise та інші, з дашборда чи з CLI, проходять через журнал: harness записує кожен людський запис у файл задачі в .harness/trace/human-writes.jsonl, а контракт scope пропускає файл задачі, вміст якого збігається з цим записом. Схвалення, зроблене, поки працює юніт іншої задачі, зберігається. Усередині юніта людські команди CLI відмовляються працювати, тож агент не може видати себе за тебе. Журнал зупиняє помилки, а не агента, який підробить сам журнал.

    З тієї ж причини на один checkout дозволено лише один цикл. Щоб запускати задачі паралельно, потрібен окремий git worktree на кожну задачу — це заплановано після першої версії.

    Як стежити за запуском

    harness status --project bookmarks
    harness status --project bookmarks --json   # the same, for scripts
    harness stats --project bookmarks           # units, time, tokens and API-equivalent cost per stage and task
    harness stats --project bookmarks --json    # the same, for scripts
    

    Вигляд Live у дашборді показує більше: стан supervisor, юніт у роботі, його агентів з роллю, часом і поточним інструментом, темп і лог supervisor. Знімок, з якого він будується, містить лише назви ролей, інструментів і файлів — ніколи аргументи інструментів чи текст повідомлень.

    Live trace під час юніта 12. Тривалості справжні, вартість — демо-цифри. Розбір на сторінці «Дашборд» →
    Екран Live trace: список юнітів, qa-юніт у роботі з агентами і лог supervisor.

    Сповіщення в Telegram

    Harness може написати тобі в Telegram, коли задача чекає на тебе (harness/notify.ts). Йому потрібні два ключі, TELEGRAM_BOT_TOKEN і TELEGRAM_CHAT_ID, і він шукає їх у такому порядку. Вирішує перше місце, де задано токен:

    1. змінні оточення;
    2. <project>/.env;
    3. $HARNESS_HOME/.env, за замовчуванням ~/.harness/.env.

    Порожній токен вимикає сповіщення. harness projects add додає .env у .gitignore проєкту, тож ключі не потрапляють у git.

    ПодіяКоли спрацьовує
    needs-inputзадача чекає твоїх відповідей
    plannedплан чекає твого схвалення (лише з autonomy.mode: gated)
    prototypeраунд прототипу чекає твого рев'ю (лише з gated)
    parkedзадачу запарковано, з причиною
    doneзадачу підтверджено
    deliveredpull request відкрито, з посиланням
    supervisorзапуск закінчився сам, або почалося перше очікування ліміту

    Усі події увімкнені за замовчуванням; notify.events у config.json звужує список. Повідомлення містить назву проєкту, id і назву задачі, подію і посилання на pull request. Посилань на локальний дашборд у ньому немає. Сповіщення односторонні: harness лише надсилає. Невдале надсилання ніколи не валить юніт — воно додає один рядок notify · … not sent у progress.log, без токена.

    Кожне повідомлення в Telegram надходить один раз. Повтор — той самий проєкт і текст, якщо не зважати на id і час — затримується на шість годин, а весь чат отримує щонайбільше шість повідомлень за хвилину. Затримане повідомлення пише в лог notify · <event> held back: <why>, а записи лежать у $HARNESS_HOME/notify-sent.json. Тека проєкту, якої вже немає, нічого не надсилає, а про збій агента приходить одне повідомлення.

    harness notify --project bookmarks          # where the keys come from; never prints the token
    harness notify --project bookmarks --test   # send one test message
    

    Що лежить у теці трейсу

    Усе, що цикл знає про себе, — у .harness/trace/. .gitignore проєкту не пускає в git trace/, artifacts/, tasks/ і JOURNAL.md; версіонується лише config.json. Файли задач ігноруються навмисно: runner переписує їх, коли перемикається між базовою гілкою і гілкою задачі, а версіонований файл задачі, що відрізняється між гілками, зламав би checkout. Історія задачі живе в її ## Log і в handoffs.jsonl.

    ФайлЩо це
    supervisor.lockтримає запущений supervisor; другий цикл відмовляється стартувати
    PAUSEє файл = пауза на наступній межі юнітів
    STOPє файл = стоп на наступній межі юнітів
    running.jsonзадача, над якою зараз працює юніт
    progress.logлог supervisor
    supervisor.outвивід supervisor, коли запуск стартував дашборд
    handoffs.jsonlщо кожен юніт передав наступному: час старту, вердикт, токени, вартість і відмови в дозволах
    unit-seqлічильник, що нумерує юніти
    unit-NNNN.jsonlодин файл на юніт: stream-json вивід агента, кожен рядок з позначкою harness_ts; тут контракт трейсу шукає вердикт
    human-writes.jsonlкожен людський запис у файл задачі з його хешем; контракт scope пропускає файл, що збігається
    unit-NNNN.agents.jsonспеціалісти, яких передали цьому юніту через --agents
    unit-NNNN.app.jsonзастосунок, який runner запустив для цього юніта: його pid, порт і власник; зникає, коли застосунок зупинено
    unit-NNNN.app.logвивід цього застосунку
    unit-NNNN.mcp.jsonMCP-конфіг, який отримав юніт із браузером: сервер Playwright і його прапорці
    preview.mcp.jsonтой самий конфіг, який пише harness preview для етапу із застосунком
    ДаліКонтракти→
    Гайд10 розділів · ~55 хвилин
    1. 1Поняття
    2. 2Ролі
    3. 3Координація
    4. 4Життя задачі
    5. 5Керування цикломти тут
    6. 6Контракти
    7. 7Дашборд
    8. 8Швидкий старт
    9. 9Під свій проєкт
    10. 10Уроки
    ОглядДемоПрикладGitHub