mandrock-files / ai

handoff-skills

Родина скілів handoff / handoff-prompt / handoff-pickup — як я передаю контекст між чатом, раном і наступним чатом, коли сесія добігає кінця, і що з v2 ще не обкатане в бою.

Сесія має властивість закінчуватись не там, де закінчена робота. Контекст добіг ліміту, компакція зжерла половину встановленого, headless-ран відпрацював і вийшов — а задача ще відкрита. Наступний чат стартує з нуля і першим ділом перепитує те, що я вже з'ясував годину тому. Це і є дірка, яку затуляє родина handoff: не «збережи чат», а «дай наступному продовжити, не переводячи вдруге ті самі факти».

Скілів три, і поділ між ними — не косметика. handoff — сам контракт: що таке хендофф, яка в нього схема, де межа між durable-контекстом і session-станом. Він нічим не володіє і нічого не пише. handoff-prompt — той, хто пише, і єдиний власник сховища. handoff-pickup — той, хто читає і одразу продовжує. Кожен знає рівно свою частину, і це головне, що я переробив у другій версії.

Задача

Хендофф корисний рівно настільки, наскільки успішник може НЕ повторювати мою роботу. Тому документ ділиться по осях, які легко переплутати й дорого злити в купу: durable-контекст проти session-стану, verified-факти проти гіпотез, зроблене проти невирішеного, і один Next action, з якого наступний починає, не думаючи. Гіпотеза, записана як факт, — це міна: успішник бере її на віру й будує зверху.

Складне тут не схема — схему видно в будь-якому шаблоні. Складна дисципліна на двох краях. З одного боку — не звалити в файл увесь транскрипт: дамп сесії це не передача контексту, а відкладений re-read, і наступний чат усе одно перечитує все з нуля, лише тепер з диска. З іншого — не вірити рядку RESULT: ok на слово: для рану це означає піти в run-dir, глянути out.log і exit_code, прогнати Verify з task.md, а не переписати чужий вердикт собі в актив.

Що змінилось у v2

v1 (09.09) була парою handoff-prompt + handoff-pickup, спакованою разом. Producer писав HANDOFF-{slug}-{дата}.md у docs/ проєкту — але тільки якщо там уже був docs/-конвент; інакше віддавав pickup-промпт просто в чат. Consumer читав той файл напряму. Робоче, але шлях до сховища producer фактично вгадував з імені проєкту, а consumer знав фізичне місце файлу — тобто був прибитий до чужої приватної деталі.

Що було (v1) Що стало (v2) Навіщо
шлях виводився з конвенту проєкту, часом вгадувався handoff-prompt — єдиний owner, шукає канонічне сховище discovery-єм із доказів на вузлі (config/registry понад усталене місце) нема доказів — повертає storage_unresolved, а не вигаданий каталог; шлях перестав бути здогадом
pickup читав файл напряму з диска pickup ходить лише через public interface owner-а (latest / read / format), у сховище руками — ніколи фізичне місце стало приватним; консюмер не знає і не мусить знати, де лежить файл
два скіли, контракт розлитий між ними зверху чистий батько handoff — сам контракт документа, без володіння станом правила можна прочитати, нічого не записуючи; producer і consumer лишаються тонкими

Плюс те, чого в v1 не було зовсім: read-back. Після запису handoff-prompt одразу читає файл назад і звіряє з тим, що збирався записати. Розбіжність або відсутній read-back — це провал, не «записалось, мабуть, ок». Дешева паранойя, яка ловить heredoc, що проковтнув $, і напівзаписаний файл, поки він ще не став чиїмось верифікованим контекстом.

Ставка

Беру — зчіпку чат↔ран↔чат саме під власні cc-рани. Headless-ран вийшов, наступна сесія піднімає його з run-dir (out.log, exit_code, Verify із task.md), і я не переказую вручну, на чому спинився. Конкретна задача, під яку це: багатосесійна робота на touchviz і nightshift, де контекст рветься посеред таска. Умова, за якої рішення зміниться: якщо discovery почне частіше помилятись у виборі канонічного сховища, ніж я ловлю це оком, — вертаю жорсткий per-project docs/ і не вдаю, що вивів шлях чесно.

Не беру — хендофф як дослівний транскрипт. Це найдорожча спокуса жанру: здається, що більше збережеш — тим безпечніше, а насправді роздутий дамп лише переносить re-read у наступну сесію. Беру рівно verified-факти з коротким evidence і один Next action; решту скидаю свідомо.

Переоцінене — discovery замість хардкод-шляху. У контракті виглядає стрункіше, ніж коштує: ціна — зайвий раунд пошуку на вузлі при кожному записі, а виграш проявляється тільки коли в проєкта два конкуруючі місця — локальний docs/HANDOFF-* і спільний /root/references/handoffs/. Для проєкту з одним місцем це церемонія заради церемонії. Тримаю її, бо в мене саме два місця й вони реально розходяться, — але не продаю це як загальну перемогу над хардкодом.

Що з цього мацане

Чесно розмежую, бо тон упевненого голосу легко видати за досвід, якого нема.

v1 має задокументований живий цикл. touchviz: docs/HANDOFF-recv-mode-20260909.md → наступна сесія підхопила, закрила суперечність (auto-rejoin прибрано) і написала docs/HANDOFF-code-pairing-20260909.md. Це працювало руками, не на папері.

Спільне сховище — теж не гіпотеза. /root/references/handoffs/ тримає 23 хендофи від 11.09 до 23.09; місце, яке v2-discovery і має знаходити, реально заповнене. Але писав його попередній механізм, не нова родина.

А от сам v2 я інтегрував у свій skills-репо сьогодні — комітами за кілька годин до цієї статті. Жодного повного циклу «написав контрактом v2 → підхопив контрактом v2 → закрив» я ще не прогнав. Кажу прямо: на папері контракт стрункий, у бою — нуль пробігів. Перша реальна передача через нього буде першим тестом, і це точно не ця стаття.

P.S. — рівні гарантії
        ЧОМУ НАСТУПНИЙ ЧАТ УСЕ ЗНАЄ
        (рівні гарантії передачі контексту)

   ┌──────────────────────────────────────┐
   │ [1] Канонічна схема на 13 заголовків │
   │ durable/session, verified/hypo       │
   └──────────────────┬───────────────────┘
                      │ owner пише один документ
                      ▼
   ┌──────────────────────────────────────┐
   │ [2] Discovery канонічного сховища    │
   │ з доказів на вузлі, не хардкод       │
   └──────────────────┬───────────────────┘
                      │ read-back
                      ▼
   ┌──────────────────────────────────────┐
   │ [3] Звірка записаного з наміром      │
   │ розбіжність = провал, не «ок»        │
   └──────────────────┬───────────────────┘
                      │ pickup лише через public interface
                      ▼
   ┌──────────────────────────────────────┐
   │ [4] «Продовж роботу над …» —         │
   │ вставляю в новий чат руками          │
   └──────────────────────────────────────┘

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