Files
skills/skills/session-handoff/SKILL.md
vitya 194cb1d0a4 feat(session-handoff): v1.0.0 — NEXT_SESSION.md → handoff-сущность mappa (#983)
mcp__mappa__handoff_write (per-project, append-only, versioned-история,
поля session_id/date/status/summary/open_treks/ask_user/guards/recent_commits,
решение 14/гриллинг Q5). Чтение — entity_search(type=handoff). Без лиза,
без файлов, без git-стеджинга. Ритуал закрытия сохранён (propose-only).
2026-08-24 16:43:20 +03:00

114 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: session-handoff
author: ours
version: 1.0.0
description: "Sliding handoff между сессиями через handoff-сущность Mappa (решение 14, гриллинг Q5): per-project, versioned-история, замена .tasks/NEXT_SESSION.md. Read on session start: orient agent, ask user before action. Write on session-end phrase or substantive commit. On session-end the agent ALSO runs the closing ritual on its own (idea 7: no invitation needed): handoff write + PROPOSE wiki-ingest + PROPOSE task-board closes — mutations only after user confirmation. Session-end phrases: «завершаем сессию», «сворачиваемся», «закругляемся», «wrap up session», «end session», «we're done for now». Trigger-line in AGENTS.md: `session handoff: read on start, write on end`. Skip task-zone phrases: «закрываем эту таску», «pause», «отбой», «разбегаемся»."
---
# session-handoff
Sliding handoff между сессиями. Канал — **handoff-сущность Mappa** (`mcp__mappa__handoff_write`, тип `h:`, per-project): поля `session_id`/`date`/`status`/`summary`/`open_treks[]`/`ask_user[]`/`guards[]`/`recent_commits[]`. Каждый write = **новая версия** (append-only, versioned-история) — файлового `.tasks/NEXT_SESSION.md` больше нет, git-история не нужна.
На старте — читает последний handoff проекта, ориентирует агента и спрашивает user'а перед действиями. При substantive commit'е или session-end фразе — пишет новый handoff для следующей сессии.
Forward-looking, не timeline: handoff = связка новых вещей конкретно для следующего разворота, не overview всего проекта. STATUS.md-эквиваленты (борд mappa) / вики остаются авторитетными для своего scope'а.
## MCP-поверхность
| Операция | Тул | Примечание |
|---|---|---|
| Запись handoff | `mcp__mappa__handoff_write(project, session_id, status, summary, open_treks?, ask_user?, guards?, recent_commits?)` | append-only; без лиза (как инбокс) |
| Чтение последнего | `mcp__mappa__entity_search(q, type='handoff', project=<имя>, limit=1)` | ORDER BY created_at DESC → первый = последний |
| Полное чтение версии | `mcp__mappa__entity_get(id)` | id internal из search |
`status``active | paused | done`. Поля-массивы (open_treks/ask_user/guards/recent_commits) — строковые массивы; пустые секции передавать как `[]` (аналог пометки «(нет на этом раунде)» — next агент видит: пусто, не забыто).
## When to use
**Read mode (session start):**
- AGENTS.md проекта содержит trigger-строку `session handoff: read on start, write on end`.
- В mappa есть handoff-сущности проекта (search не пуст).
**Write mode (session end / substantive commit):**
- User'ская фраза из whitelist:
- русский: «завершаем сессию», «сворачиваемся», «закругляемся»
- английский: «wrap up session», «end session», «we're done for now»
- ИЛИ — agent только что сделал substantive commit. Эвристика:
- prefix НЕ в (`meta:`|`docs:`|`style:`|`chore:`|`fix typo`)
- AND (body length > 200 символов OR files changed > 3)
- Плюс: **первый** non-trivial commit сессии — всегда триггерит, даже если ниже порога (старт работы = context shift).
**Skip (false-positive guards):**
- «закрываем эту таску» — task close, не session. Это зона using-tasks.
- «pause», «приостанови» — task-pause, не session-end.
- «отбой», «разбегаемся» — слишком broad.
- «сейчас завершу одну задачу и тогда поговорим» — частичное завершение.
- Проект не в mappa / нет handoff-сущностей — silent exit.
- AGENTS.md проекта НЕ содержит trigger-строку — silent exit.
При неоднозначности — **ASK**, не угадывать: «закрываем сессию или таску?»
## Steps
### Read mode
1. **Detect.** `mcp__mappa__entity_search(q='', type='handoff', project=<имя проекта>, limit=1)` — если пусто, silent exit (первая сессия проекта).
2. **Staleness check.** `meta.date` последнего handoff'а. Возраст > 7 дней → отметить user'у:
```
handoff от <date> (N дней назад) — возможно устарел.
Оверрайдить или продолжить?
```
Дождаться ответа перед продолжением.
3. **Summarize.** Прочитать мета последнего: summary / open_treks / ask_user / guards / recent_commits.
4. **Orient.** Пересказать user'у одним блоком: «прошлая сессия предложила X (open треки + ask-items + guards). Делаем?»
5. **Wait.** Не делать никаких действий до подтверждения user'ом. Default = orient + ask, **никакого auto-execute**.
### Write mode
1. **Scope check.** Это текущий проект (cwd). Никаких global мутаций, никаких других проектов.
2. **Mid-task capture.** Если есть 🔴 active таска проекта (борд mappa / `.tasks/`) — захватить в summary:
```
left mid-task: <slug>
where_stopped: <одна строка>
```
3. **Compose content.** Собрать поля handoff:
- `session_id` — `<ISO дата>` или идентификатор сессии;
- `status` — `active` (работа продолжается) / `paused` (заморожено) / `done` (завершено);
- `summary` — связка: где остановились, mid-task, ключевые решения;
- `open_treks` — массив открытых треков (готовность + entry-point);
- `ask_user` — pending решения / ожидаемые разрешения;
- `guards` — «не делать» (preemptive guards);
- `recent_commits` — 35 последних коммитов (`<slug>: <subject>`).
4. **Append.** `mcp__mappa__handoff_write(project=<имя>, ...)` — сервис создаёт новую версию `h:N` (versioned-история; предыдущие версии остаются, `entity_search` вернёт свежую).
5. **Closing ritual (idea 7).** На session-end фразе (НЕ на substantive commit) после handoff-write агент сам, без приглашения, предлагает закрытие:
- **(2) Propose wiki-ingest.** Если за сессию появилось durable-знание — ПРЕДЛОЖИТЬ ingest (using-wiki v2: mappa wiki_create/update под лизом), перечислив кандидатов. Ничего не писать без подтверждения.
- **(3) Propose task-board closes.** Если есть задачи, выглядящие закрытыми — ПРЕДЛОЖИТЬ закрытия (using-tasks / mappa task_close под лизом). Уважать ralph-loop: verifier-задачи закрывать только через verifier.
- Формат — один блок: «Ритуал закрытия: (а) заингестить X в вики? (б) закрыть Y? (в) ничего.» Ждать ответа. Отказ = пропуск.
## Failure modes
- **AGENTS.md без trigger-строки** → silent exit. Скил project-opt-in.
- **Проект не в mappa / нет handoff-сущностей** → silent exit.
- **Stale handoff (> 7 дней)** в read mode → не silent, **спросить** user'а оверрайдить или продолжить.
- **Неоднозначная фраза** → ASK «закрываем сессию или таску?», не угадывать.
- **Secret detected.** Контент матчит паттерны секретов (`AKIA...`, `sk-...`, `ghp_...`, `ssh-rsa`, `BEGIN PRIVATE KEY`, `password=`/`token=`) → **abort write**. Сообщить user'у с указанием подозрительной строки.
- **Mid-task без борда** → писать handoff без mid-task секции, не блокировать.
- **Ритуал: user отказал** → пропустить, не настаивать, не повторять в этой сессии.
## Side effects
- Пишет handoff-сущность проекта (append-only, versioned-история). Никаких файлов, никаких git-коммитов за handoff.
- Ритуал закрытия предлагает wiki-ingest и закрытия тасок — но НЕ пишет их.
- Никаких global мутаций, никаких других проектов, никаких user-level config writes.
## What NOT to do
- **Не auto-execute** действия из read handoff'а. Default = orient + ask.
- **Не писать в вики / не закрывать таски по ритуалу молча.** Ритуал = предложения. Каждая мутация — после явного «да».
- **Не гонять ритуал на substantive commit.** Только session-end фраза.
- **Не писать секреты** в handoff. Если контент матчит secret-patterns — abort.
- **Не на каждом commit'е.** Только substantive (см. эвристику).
- **Не дублировать борд / вики.** Handoff = forward-looking связка, не overview.
- **Не cross-project.** Per-project scope.
- **Не считать handoff авторитетным** на стороне читателя. Это рекомендация прошлой сессии, не директива. User может override любую её часть.