From 146fbdb1071e4fefa896ceb339d1f0d1a902c9e3 Mon Sep 17 00:00:00 2001 From: vitya Date: Mon, 24 Aug 2026 15:19:27 +0300 Subject: [PATCH] =?UTF-8?q?feat(skills):=20mail=20on=20Mappa=20=E2=80=94?= =?UTF-8?q?=20inter-session-messaging=20v2.0.0=20+=20session-inbox-monitor?= =?UTF-8?q?=20v1.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - inter-session-messaging v2.0.0: channel switched from file inbox (.agents/inbox/) to Mappa inbox.send/inbox.monitor/entity_get; letters are entities i:N, delivery is a lease carve-out; address book + project-exists check via admin_status; replies via entity_get(id).meta.from; subject carries [event: ...] instead of frontmatter. - session-inbox-monitor v1.0.0: monitor now polls GET /inbox?project= (HTTP, dedup by letter id, no .read/ move); hook inbox-monitor.ps1 rewritten to inject the mappa poll command (sweep sentinel + project dir). - delegate-task v0.5.1: covering letter goes through inbox_send, not file path. Part of #983 (mappa-skills). --- dist/delegate-task.skill | Bin 6007 -> 6157 bytes dist/inter-session-messaging.skill | Bin 5346 -> 6112 bytes dist/session-health.skill | Bin 0 -> 3416 bytes dist/session-inbox-monitor.skill | Bin 7155 -> 6450 bytes skills/delegate-task/SKILL.md | 29 +-- skills/inter-session-messaging/SKILL.md | 147 +++++++------ skills/session-inbox-monitor/SKILL.md | 208 +++++++----------- .../hooks/inbox-monitor.ps1 | 71 +++--- 8 files changed, 208 insertions(+), 247 deletions(-) create mode 100644 dist/session-health.skill diff --git a/dist/delegate-task.skill b/dist/delegate-task.skill index 1559428a29d509da66a65ae5b6c351cb9f760115..b27f40aebc06f48b9986a5fad2236d077890cbd8 100644 GIT binary patch delta 6131 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 PLX*uGItCpV00000^)`T8 diff --git a/dist/inter-session-messaging.skill b/dist/inter-session-messaging.skill index 58daf2ac73f103c09054bf8ba97b1c6fec0f6681..cda07fa87a715003923f7c69fb4fa98097cdafdc 100644 GIT binary patch delta 6065 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 literal 0 HcmV?d00001 diff --git a/dist/session-inbox-monitor.skill b/dist/session-inbox-monitor.skill index 8a067507d9074d5b48fa87c146a997b12d09f08c..162bd2331673679db0be8b438e95d9c693b4f717 100644 GIT binary patch delta 6314 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 literal 7155 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 Z>pw6vRRBD~zt&;?$%=m}FUh~U{{oHvxq|=z diff --git a/skills/delegate-task/SKILL.md b/skills/delegate-task/SKILL.md index 7b17ece..c3b3713 100644 --- a/skills/delegate-task/SKILL.md +++ b/skills/delegate-task/SKILL.md @@ -1,7 +1,7 @@ --- name: delegate-task author: ours -version: 0.5.0 +version: 0.5.1 description: > Use when delegating a task to another agent or project via mcp__projects-meta__tasks_create. Every cross-project delegation is a @@ -112,19 +112,21 @@ description: > ### 5. Сопроводительное письмо — обязательно при кросс-проектной делегации После создания **каждая кросс-проектная делегация** дублируется письмом в -инбокс получателя (канон — `inter-session-messaging`, адрес из адресной -книги `~/projects/.wiki/concepts/projects-address-book.md`): +инбокс получателя (канон — `inter-session-messaging` v2: канал Mappa, адрес +из адресной книги `~/projects/.wiki/concepts/projects-address-book.md`): ``` -<адрес-получателя>/.agents/inbox/Z-<своя-папка>.md ---- -from: <своя-папка> -event: created -slug: ---- -Тело: 1-2 строки — что за задача, почему, slug; «разбери и возьми». +mcp__mappa__inbox_send( + project: <адрес-получателя>, # имя папки, из адресной книги + from: <своя-папка>, + subject: "[event: created] #n slug", + body: "1-2 строки — что за задача, почему, slug; «разбери и возьми»" +) ``` +(Мутация тасок гейтится лизом проекта — `task_claim_next`; доставка письма — +карв-аут, лиза не требует.) + Причина: таска на борде **не пингует живую сессию** получателя. Поллер подхватит по `Weight`/`Notify`, но живая интерактивная сессия узнаёт только через inbox-монитор — т.е. через письмо. Правило «task + letter, не только @@ -147,7 +149,7 @@ task» — общий случай (шаг 7 — его частность дл ### 7. Downstream-задача для ЖИВОЙ сессии → требовать task + inbox-письмо -Если тело задачи **поручает агенту самому создать downstream-задачу** для другого проекта, где работает **живая интерактивная сессия** (напр. прог сам ставит deploy-таску админу), — в ТЗ **явно потребуй И `tasks_create`, И inbox-письмо** тому проекту (`/.agents/inbox/-.md`). +Если тело задачи **поручает агенту самому создать downstream-задачу** для другого проекта, где работает **живая интерактивная сессия** (напр. прог сам ставит deploy-таску админу), — в ТЗ **явно потребуй И `tasks_create`, И inbox-письмо** тому проекту (`mcp__mappa__inbox_send(project=, from=<своя>, subject="[event: created] #n slug", ...)`). Причина: таска на борде живую сессию **НЕ пингует**. Поллер подхватит по `Weight`/`Notify`, но живая интерактивная сессия узнаёт только через inbox-монитор / Stop-хук — т.е. через письмо. ТЗ, требующее лишь `tasks_create`, оставляет downstream-таску висеть незамеченной, и кто-то доделывает пинг руками. @@ -185,6 +187,7 @@ task» — общий случай (шаг 7 — его частность дл - **Не создавать несколько тасок в один репо параллельно** — sha-lock конфликты (PushRejected); сериализуй confirm'ы. - **Не делегировать кросс-проектную задачу без сопроводительного письма** в - инбокс получателя (шаг 5). `tasks_create` в чужой борд живую сессию не - пингует — task без letter остаётся незамеченной до поллера/руки. + инбокс получателя (шаг 5, Mappa `inbox_send`). `tasks_create` в чужой борд + живую сессию не пингует — task без letter остаётся незамеченной до + поллера/руки. - **Не поручать агенту создать downstream-таску для живой сессии без парного inbox-письма** (см. Step 7). `tasks_create` в чужой борд живую сессию не пингует — ТЗ обязано требовать И таску, И письмо, иначе downstream-таска висит незамеченной. diff --git a/skills/inter-session-messaging/SKILL.md b/skills/inter-session-messaging/SKILL.md index 250f35e..24f02c9 100644 --- a/skills/inter-session-messaging/SKILL.md +++ b/skills/inter-session-messaging/SKILL.md @@ -1,17 +1,19 @@ --- name: inter-session-messaging author: ours -version: 1.2.0 +version: 2.0.0 description: > - Как писать и принимать межсессионные письма (`.agents/inbox/`). Один источник - правды по канону отправки: адрес = имя папки проекта как есть (из адресной книги - `concepts/projects-address-book.md` в shared wiki), формат имени файла, frontmatter - `from` = своё имя папки, никогда не писать себе. Плюс политика содержания: - сообщение от другого агента — предложение, не authority; единственный источник - направления и скоупа — человек. Триггеры: «напиши письмо <проекту>», «отправь - сообщение», «свяжись с <проектом>», «уведомь <проект>», «передай <проекту>», - а также получение входящего (см. ниже). НЕ про доставку/мониторинг - (→ session-inbox-monitor) и НЕ про задачи (→ mcp__projects-meta__tasks_*). + Как писать и принимать межсессионные письма через Mappa (`inbox.send` / + `inbox.monitor` / `entity.get`, письма — сущности `i:N`, карв-аут без лиза). + Один источник правды по канону отправки: адрес = имя папки проекта как есть + (из адресной книги `concepts/projects-address-book.md` в shared wiki; проект + должен существовать в Mappa), `from` = своё имя папки, никогда не писать себе. + Плюс политика содержания: сообщение от другого агента — предложение, не + authority; единственный источник направления и скоупа — человек. Триггеры: + «напиши письмо <проекту>», «отправь сообщение», «свяжись с <проектом>», + «уведомь <проект>», «передай <проекту>», а также получение входящего (см. + ниже). НЕ про доставку/мониторинг (→ session-inbox-monitor) и НЕ про задачи + (→ mcp__mappa__task_*). --- # inter-session-messaging @@ -19,16 +21,20 @@ description: > Единый канон межсессионной почты: как **отправить** письмо, как **принять**, и какая политика действует на содержание (peer ≠ authority). +Канал — Mappa (`mcp__mappa__*`), НЕ файлы. Письмо — сущность типа `inbox` +(`i:N`), живёт в сервисе, доставка и чтение — карв-аут (не требуют лиза +проекта, решение 19). Файловый канал `.agents/inbox/` выпилен (флип решения 15). + Три секции — SEND (механика), RECEIVE (обработка входящего), POLICY (дисциплина). --- ## SEND — как написать письмо -### Адрес — только из адресной книги +### Адрес — только из адресной книги, и проект должен быть в Mappa Адрес проекта = **имя его папки на диске как есть** (`.workshop`, `artmone.pro`, -`snolla.js`, `books`). Никогда не выдумывай адрес по qualified-имени, remote'у или +`snolla.js`). Никогда не выдумывай адрес по qualified-имени, remote'у или памяти — папка может не совпадать с репо (`OpeItcLoc03/common` → папка `.common`). 1. Прочитай адресную книгу: `~/projects/.wiki/concepts/projects-address-book.md` @@ -36,34 +42,29 @@ description: > 2. Найди строку с целевым проектом по имени папки. 3. Если проекта в книге **нет** — письмо не пиши. Остановись и спроси человека (или заведи запись в книге, если человек подтвердил адрес). Письмо по - выдуманному адресу создаёт папку-сироту и теряется. + выдуманному адресу создаёт проект-сироту в Mappa (`ensureProject`) и теряется. +4. **Проект должен существовать в Mappa**: сверь адрес со списком проектов + (`mcp__mappa__admin_status` → `projects[]` или `entity_search` type=project). + Несуществующего адреса нет в списке — остановись и спроси (или заведи проект). -### Куда и с каким именем +### Вызов отправки ``` -~/projects/<адрес>/.agents/inbox/Z-<адрес-отправителя>.md +mcp__mappa__inbox_send( + project: <адрес получателя>, # имя папки проекта (из адресной книги) + from: <адрес отправителя>, # СВОЁ имя папки (только имя, без owner/темы) + subject: <тема>, # опционально — короткая тема + body: # свободный markdown +) ``` -- `` — `YYYY-MM-DDTHH-MM-SSZ`, **без миллисекунд**, без двоеточий - (Windows-safe). Пример: `2026-08-20T10-30-00Z`. -- `<адрес-отправителя>` — **только имя своей папки**. Без owner, без темы, - без описания. `-workshop.md`, `-common.md`, `-books.md`. НЕ - `-reviewer-command-index-done-ack.md` (тема письма — не slug). -- Write-тул создаёт директорию автоматически — но это не отменяет проверку - адреса по книге выше. - -### Frontmatter - -```markdown ---- -from: <адрес-отправителя> # своё имя папки, не qualified, не описание -ts: # с двоеточиями здесь можно, без миллисекунд -in_reply_to: <имя-файла-письма> # опционально — при ответе -event: <тип> # опционально — created/closed/blocked/done-report -slug: # опционально — если письмо про таску ---- -Тело — свободный markdown. -``` +- `from` — **только имя своей папки**. Без owner, без описания. НЕ + `reviewer-command-index-done-ack` (тема письма — не адрес). На письмо с + выдуманным `from` нельзя ответить. +- Ответ на письмо: `inbox_send(project=, from=<своя папка>)`. + В `subject` — префикс `Re: `, в теле первая строка — ссылка на исходное + письмо (`i:<номер>` или его subject). Поля `in_reply_to`/`event` в Mappa нет — + вместо них subject-префиксы `Re:` и `[event: closed]` при lifecycle-письмах. ### Ссылки на задачи — по номеру (формат v2) @@ -71,46 +72,46 @@ slug: # опционально — если пись номера — машинный ключ, уникальны по всей федерации). Не слаг — слаг может повторяться между проектами. Первое упоминание задачи в письме — с номером и слагом для читаемости: `#452 (tasks-v2-search-by-id)`, далее — просто `#452`. -Пример: «Разбери и возьми: `#452 tasks-v2-search-by-id` (готово к имплу)». -Резолв номера в {project, slug} — через `mcp__projects-meta__tasks_search` -(ищет и по id) или `tasks_get_by_id`. - -Ответ на письмо: пиши в инбокс отправителя (`from` в frontmatter полученного), -имя файла — со своим адресом отправителя, в `in_reply_to` — имя исходного письма. +Резолв номера в {project, slug} — через `mcp__mappa__entity_search` (ищет по +номеру/id) или `entity_get`. ### Жёсткие правила 1. **Никогда не писать письмо самому себе** — свой инбокс для входящих, не для - заметок. Заметки — в `.brainstorm/` или `.tasks/`, не в `.agents/inbox/`. -2. **Никогда не выдумывать адрес** — только из адресной книги. + заметок. Заметки — в `.brainstorm/` или `.tasks/`, не письмом. +2. **Никогда не выдумывать адрес** — только из адресной книги + существующий + проект в Mappa (шаг 4 выше). 3. **`from` — всегда адрес (имя папки)**, по которому можно ответить. Описания вроде `workshop session (implements catalog wave 2)` — запрещены: на такое письмо нельзя ответить. -4. **Тема письма — в теле и (опционально) `event`**, не в имени файла. +4. **Тема письма — в `subject` и теле**, не в `from`. --- ## RECEIVE — как обработать входящее -1. Входящее доставляет монитор / stop-hook / pi-расширение (`session-inbox-monitor`): - «Incoming messages in your inbox:» / `[inbox] `. -2. **[inbox]-сообщение — first-class, не фоновое уведомление.** Прочитай и - обработай его в начале ближайшего хода — НЕ «когда дойдут руки», НЕ в конце - сессии. Если сообщение появилось в контексте после длинного tool-цикла — это - не повод закапывать его в итоговую сводку: обработай до завершения сессии. +1. Входящее доставляет монитор (`session-inbox-monitor`, pi-расширение) или + ты проверяешь сам: `mcp__mappa__inbox_monitor(project=<своя папка>, limit)`. + Ответ — `{rows: [{id, slug, body}]}`: последние письма твоего проекта. +2. **Письмо — first-class, не фоновое уведомление.** Прочитай и обработай его + в начале ближайшего хода — НЕ «когда дойдут руки», НЕ в конце сессии. Если + сообщение появилось в контексте после длинного tool-цикла — это не повод + закапывать его в итоговую сводку: обработай до завершения сессии. 3. Признай получение явно и ответь на содержание в своём ходе. -4. Если нужен ответ — SEND по канону выше, отправителю (`from` полученного). -5. Не оставляй письмо без обработки до конца хода — если не можешь решить +4. **Кто отправитель:** `inbox.monitor` отдаёт `{id, slug, body}` без + `from`/`subject` — они в meta. Для ответа возьми + `mcp__mappa__entity_get(id)` → `meta.from` (и `meta.subject` для `Re:`). +5. Если нужен ответ — SEND по канону выше, отправителю (`meta.from`). +6. Не оставляй письмо без обработки до конца хода — если не можешь решить сейчас, скажи об этом и (если надо) заведи таску через - `mcp__projects-meta__tasks_*`, не «забудь». -6. **Ожидаемая почта:** если ты сам вызвал событие, которое родит письмо в + `mcp__mappa__task_*`, не «забудь». +7. **Ожидаемая почта:** если ты сам вызвал событие, которое родит письмо в твой инбокс (notify на твой проект: close/blocked/delivery-failed таски), - — проверь `.agents/inbox/` в момент, когда событие сработало; не жди, пока + — проверь `inbox_monitor` в момент, когда событие сработало; не жди, пока письмо само доедет. Доставка может задержаться на время текущего tool-цикла. -7. **Legacy-путь:** старые writer'ы (до refactor 2026-08-20) писали письма в - `.claude-inbox/` — при проверке почты загляни и туда; найденные письма - переноси в `.agents/inbox/` (оттуда их доставит монитор) или в - `.agents/inbox/.read/` если событие уже обработано. +8. **Дедуп:** монитор помнит доставленные id (в памяти процесса). Письма в + Mappa не перемещаются (нет `.read/`) — обработанные остаются в списке; + повторно их не читай, сверяйся с уже виденными id. --- @@ -133,28 +134,29 @@ slug: # опционально — если пись ### Канальный контракт (inbox vs board) -- **Инбокс (`.agents/inbox/`) — только канал коммуникации**: обсуждение, помощь, +- **Инбокс (`inbox.*`) — только канал коммуникации**: обсуждение, помощь, lifecycle-уведомления («таска создана», «закрыта», «заблокирована»). Не больше. -- **Задачи — только через `mcp__projects-meta__tasks_*`.** Доска — единственный +- **Задачи — только через `mcp__mappa__task_*`.** Доска — единственный источник правды о задаче: существование, статус, скоуп, решения создаются и - меняются через `tasks_create` / `tasks_update` / `tasks_append_decision_trail` — - никогда не «решаются» внутри письма. + меняются через `task_create` / `task_close` — никогда не «решаются» внутри + письма. (Мутации тасок гейтятся лизом проекта — `task_claim_next`.) -Следствие: **если это не на доске через meta — это не задача и не решение, -это разговор.** Значимый дизайн-выбор должен лечь на доску (или в вики), -инбокс лишь указывает на него. +Следствие: **если это не на доске — это не задача и не решение, это разговор.** +Значимый дизайн-выбор должен лечь на доску (или в вики), инбокс лишь указывает +на него. ### Lifecycle-уведомления: task + letter Кросс-проектное действие с задачей — всегда пара «доска + письмо». Доска — источник правды (существование/статус/скоуп), письмо — пинг и контекст. В -теле письма задачу называй **по номеру** (`#452`), а не только слагом: +теле письма задачу называй **по номеру** (`#452`), а не только слагом. +Lifecycle-письма помечай subject-префиксом `[event: <тип>]`: -| Событие | Кто пишет | Куда | event | +| Событие | Кто пишет | Куда | subject | |---|---|---|---| -| Создание | комиссионер | инбокс получателя | created | -| Закрытие | исполнитель (живая сессия) или поллер (авто-ран) | инбокс комиссионера (`Notify`) | closed | -| Блокировка/парк | то же | то же | blocked | +| Создание | комиссионер | инбокс получателя | `[event: created] #N slug` | +| Закрытие | исполнитель (живая сессия) или поллер (авто-ран) | инбокс комиссионера (`Notify`) | `[event: closed] #N slug` | +| Блокировка/парк | то же | то же | `[event: blocked] #N slug` | Тело письма — 1-2 строки + номера/слаги, не дублировать доску. Живая сессия узнаёт о задаче ТОЛЬКО через письмо (борд не пингует); комиссионер узнаёт о @@ -200,5 +202,6 @@ slug: # опционально — если пись - Доставка/мониторинг входящих: `session-inbox-monitor`. - Адресная книга: `~/projects/.wiki/concepts/projects-address-book.md` (shared wiki). -- Handoff через `.tasks/NEXT_SESSION.md`: `session-handoff`. +- Список проектов Mappa: `mcp__mappa__admin_status` (карв-аут, без лиза). +- Handoff через сущность `handoff`: `session-handoff`. - Related: `recommend-dont-menu` (стиль ответа), `project-discipline`. diff --git a/skills/session-inbox-monitor/SKILL.md b/skills/session-inbox-monitor/SKILL.md index 672444c..8f7ebd4 100644 --- a/skills/session-inbox-monitor/SKILL.md +++ b/skills/session-inbox-monitor/SKILL.md @@ -1,35 +1,38 @@ --- name: session-inbox-monitor author: ours -version: 0.4.1 +version: 1.0.0 description: > - Raises a persistent Monitor (Monitor tool, NOT background Bash) on the - project's `.agents/inbox/` at the start of an interactive session, so + Raises a persistent Monitor on the project's Mappa inbox (poll + `mcp__mappa__inbox_monitor` / HTTP `GET /inbox?project=`), so inter-session messages page the session in real time; the monitor dies on - session end on its own. A paired SessionStart hook injects the - raise-instruction and first sweeps orphaned monitors of this inbox (a - `/clear` leaves them running → re-raise would stack duplicates). Triggers: + session end on its own. Pi (pi-coding-agent) sessions: a global extension + polls the same HTTP endpoint, session-scoped (own project only). Triggers: AGENTS.md line `inbox monitor: raise on start`, or «подними монитор почты», «настрой авто-монитор инбокса», «raise inbox monitor», «auto-arm inbox - watcher». Headless (`claude -p`): does NOT raise — Monitor doesn't work - there; rely on the Stop-hook inbox pickup + Notify/ntfy. Pi (pi-coding-agent) - sessions: a global extension delivers the session's own project inbox - messages (own directory only, see the Pi section). NOT for how to - handle a received message (→ inter-session-messaging) nor the - multi-machine inbox backend (→ cross-machine-inbox design). + watcher». Headless (`claude -p` / `pi -p`): does NOT raise — rely on the + Stop-hook / agent_settled pull pickup. File channel `.agents/inbox/` is + gone (flip, решение 15) — letters live in Mappa as entities `i:N`, delivery + is a carve-out (no lease, решение 19). NOT for how to handle a received + message (→ inter-session-messaging). --- # session-inbox-monitor -Auto-raises a session-length Monitor on `.agents/inbox/` at interactive-session -start (via a paired SessionStart hook that injects the instruction and sweeps -orphans), so inter-session messages page the session in real time. Tears down -for free on session end. Headless sessions skip it and rely on the pull-model -(Stop-hook pickup + Notify). +Auto-raises a session-length Monitor on the project's **Mappa inbox** at +interactive-session start, so inter-session messages page the session in real +time. Tears down for free on session end. Headless sessions skip it and rely +on the pull-model (Stop-hook / agent_settled pickup). + +Канал — Mappa, НЕ файлы: письма — сущности `inbox` (`i:N`) в сервисе, читаются +через `mcp__mappa__inbox_monitor(project, limit)` (или HTTP `GET +/inbox?project=<имя-папки>&limit=N`). Доставка/чтение — карв-аут (решение 19): +не блокируются лизом, работают всегда. Файловые `.agents/inbox/` и `.read/` +выпилены. ## When to use -- **Automatic (the common path).** The paired SessionStart hook injects an +- **Automatic (the common path).** A paired SessionStart hook injects an instruction at the start of every interactive session of an opted-in project. You act on that injection — raise the monitor as your first action — without a user phrase. @@ -37,142 +40,85 @@ for free on session end. Headless sessions skip it and rely on the pull-model монитор почты», «настрой авто-монитор инбокса», «raise inbox monitor», «auto-arm inbox watcher». - **NOT for** handling the content of a received message (→ - `inter-session-messaging`), nor the multi-machine delivery backend (→ - `cross-machine-inbox`). This skill is only the monitor's *lifecycle* on one - machine. + `inter-session-messaging`). This skill is only the monitor's *lifecycle*. ## Inputs -- `/.agents/inbox/` — the watched directory. Direct-child `*.md` files - are inbox messages (the Stop-hook moves them to `.read/` once handled). -- The SessionStart hook supplies the **exact Monitor command** to run, with the - sweep sentinel (`CLAUDE_INBOX_MONITOR`) and the absolute inbox path baked in. - Use it verbatim — do not hand-author a different poll command, or the sweep - won't recognise the process it spawns. +- `` — своё имя папки (cwd basename), адрес в Mappa. +- Письма: `mcp__mappa__inbox_monitor(project=<своя папка>, limit)` → + `{rows: [{id, slug, body}]}` (последние N). `from`/`subject` — в meta, через + `entity_get(id)` при ответе. +- Мопitor-команда при CC — HTTP-опрос `GET /inbox?project=...` (без токена на + текущем проде; если `MAPPA_API_TOKEN` задан — `x-api-token` header). ## Steps -1. **Mode check.** If this is a headless / non-interactive run (`claude -p`), - **STOP — do not raise a monitor.** The Stop-hook inbox pickup plus `Notify:`/ - ntfy cover delivery there; a Monitor can't idle-watch in headless and is - killed ~5s after the run. There is no hook-level headless signal, so this is - your judgement call from the run context. -2. **Raise exactly one persistent Monitor** using the command the hook injected: - the **Monitor tool** with `persistent: true`, `description: "inbox watcher"`. - The hook already swept any orphan before injecting, so you start from a clean - slate — raise one, not more. +1. **Mode check.** Headless / non-interactive (`claude -p`, `pi -p`, + `ctx.hasUI === false`): **STOP — do not raise a monitor.** The pull pickup + (CC Stop-hook / pi `agent_settled`) plus `Notify:` cover delivery there; a + Monitor can't idle-watch in headless. +2. **Raise exactly one persistent Monitor** on the Mappa inbox: + `mcp__mappa__inbox_monitor(project=, limit=50)`, poll + interval ~15s, `description: "inbox watcher"`. Dedup by письменному id: + новое письмо — это id, которого ещё не было в предыдущих ответах. 3. **Do not sweep yourself.** Killing orphans is the hook's job (it runs before - you, at SessionStart, when no other session activity is live). -4. **On an event** (`New inter-session message in inbox: `), read - `.agents/inbox/` and handle the message per `inter-session-messaging`. - The Stop-hook also force-delivers any inbox messages at end of turn as a - backstop, so nothing is lost if the monitor missed a beat. + you, at SessionStart). +4. **On an event** (новый id в ответе inbox_monitor), прочитай письмо (body) и + обработай per `inter-session-messaging`. Для ответа — `entity_get(id)` → + `meta.from`. Письма не перемещаются (нет `.read/`) — обработанные остаются + в списке; дедуп по id в памяти монитора. 5. **Teardown is automatic.** The Monitor dies at session end. Do **not** add a - SessionEnd teardown — and note `/clear` does not fire SessionEnd anyway - (that's why the sweep lives in SessionStart, not SessionEnd). - -## Deployment (machine-local) - -- Hook script: `skills/session-inbox-monitor/hooks/inbox-monitor.ps1` (versioned - here) → deploy to `~/.claude/hooks/inbox-monitor.ps1`. -- Register in `~/.claude/settings.json` under `hooks.SessionStart` (no matcher → - fires on startup/resume/clear/compact), e.g.: - ```json - { "hooks": [ { "type": "command", - "command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"C:\\Users\\\\.claude\\hooks\\inbox-monitor.ps1\"", - "timeout": 15, "statusMessage": "inbox-monitor" } ] } - ``` -- Twin pattern: `poller-interactive-lock-writer` (`interactive-lock.ps1`). -- Opt-in per project: the hook fires only when the project has a `.agents/inbox/` - directory **or** an AGENTS.md line `inbox monitor: raise on start`. - -## Failure modes - -- **No inbox, no opt-in line** → the hook injects nothing; no monitor. Expected - for projects that don't use inter-session messaging. -- **Two live interactive sessions on the same project** → the second session's - SessionStart sweep kills the first session's monitor (the match is - per-inbox-path, not per-session). Known limitation; the deliberate invariant is - "exactly one monitor per inbox per machine." If the first session is still - active, its next Stop-hook turn still delivers inbox mail — only the real-time - paging is lost until it re-raises. See `inter-session-messaging`. -- **Sweep over-match** → any *live* process whose command line contains both the - sentinel `CLAUDE_INBOX_MONITOR` and the inbox path is killed. At a real - SessionStart no agent/tool processes are running yet, so only the orphaned - monitor matches. Don't echo or run a command carrying that sentinel+path during - a session's startup. -- **Headless didn't skip** → a monitor raised in headless is a harmless no-op, - killed ~5s after the run ends. The default errs toward raising because a - false-skip in an interactive session would silently lose the feature. -- **Monitor auto-stopped** → the harness stops monitors that emit too many - events. The injected poll command de-dups by filename (pages once per message, - not every 15s) to stay under that bar. -- **Mojibake on force-delivery** → the Stop-hook (`stop-dispatcher.ps1`) injects - message bodies to stdout; WinPS 5.1 must set `[Console]::OutputEncoding = - [System.Text.Encoding]::UTF8` or non-ASCII (Cyrillic) bodies arrive mangled - (it emits in the OEM code page under a harness-spawned redirected pipe). Inbox - messages must be written as **no-BOM UTF-8, LF** — the Write tool does this; - PowerShell writers must use - `[IO.File]::WriteAllText($p,$t,[Text.UTF8Encoding]::new($false))`, NOT - `Set-Content`/`Out-File -Encoding utf8` (which adds a BOM under 5.1). Same - WinPS-5.1 encoding class as the hook-source em-dash gotcha. Fixed + in-situ - verified 2026-06-17. The SessionStart injector (`inbox-monitor.ps1`) carries - the **same `[Console]::OutputEncoding` UTF-8 guard** as a forward-protection - (v0.2.2): it interpolates the inbox path into the injected JSON, so a non-ASCII - path or `additionalContext` would otherwise mangle the same way — the guard is - preventive (today's `$ctx` is ASCII) but cheaper than an "ASCII-only" invariant. - -## Side effects - -- Spawns one Monitor (and its backing Git-Bash poll process) per interactive - session; both die at session end. -- Force-kills orphaned monitor processes of this inbox at every SessionStart. -- **No repo writes.** The hook and its `~/.claude/settings.json` registration are - machine-local; only this skill (docs) and `.agents/inbox/` activity are in play. + SessionEnd teardown. ## Pi (pi-coding-agent) support — session-scoped global extension -Same contract, pi-native, and **session-scoped**: the extension watches ONLY the -current session's project inbox (`/.agents/inbox/`) — it never reads +Same contract, pi-native, session-scoped: the extension polls ONLY the current +session's project inbox (`GET /inbox?project=`); it never reads other projects' inboxes (vitya's rule: an agent may only read its own -directory's inbox). Installed globally so *every* pi session has the -capability, but each session only ever touches its own project's inbox. +project's inbox). Installed globally so *every* pi session has the capability, +but each session only ever touches its own project. - **Source of truth:** `~/projects/pi-extensions/extensions/inbox-monitor.ts` (репо `OpeItcLoc03/pi-extensions`, Gitea — дом pi-расширений). Deploy: `just install` в клоне репо — копирует с затираанием в `~/.pi/agent/extensions/inbox-monitor.ts` (global → every pi, every - directory), hot-reload with `/reload`. Test: - `node --experimental-strip-types .common/lib/pi-extensions/inbox-monitor.test.mjs` - (incl. decoy check — another project's inbox is never touched). -- **Opt-in per project** — same as CC: `.agents/inbox/` dir exists OR AGENTS.md - line `inbox monitor: raise on start`. -- **PUSH:** 15s poll of the session's own inbox (interactive only). **PULL:** - `agent_settled` sweep — the pi equivalent of the CC Stop-hook pickup. Both - share one dedup set per process; the `.read/` move is the cross-process - guard — first sweeper (CC hook or pi) claims the message, the other skips it. + directory), hot-reload with `/reload`. +- **Opt-in per project:** AGENTS.md / CLAUDE.md line + `inbox monitor: raise on start`. (Файловой директории `.agents/inbox/` больше + нет — триггер только строка.) +- **PUSH:** ~15s poll of the session's own Mappa inbox (interactive only). + **PULL:** `agent_settled` sweep — same poll, backstop. Both share one dedup + set per process (by letter id). - **Headless (`pi -p`, `ctx.hasUI === false`):** NO delivery — no watcher, no - sweep. Messages sit in the inbox until an interactive session picks them up. - Mirrors CC headless (external Notify there, nothing in-run) and avoids - hijacking one-shot scripted runs or consuming messages nobody processes. + sweep. Messages sit in Mappa until an interactive session picks them up. - **Delivery:** `pi.sendUserMessage(body, { deliverAs: "followUp", triggerTurn: true })` — paged into the transcript as a user message; the agent handles it - per `inter-session-messaging`. Partial writes (empty file) are skipped - and retried next poll. -- **Failure mode — cross-harness double-pickup:** CC and pi both sweep; the - `.read/` move makes it first-wins, not double-processing. Two live pi sessions - in one process tree share the dedup set; two pi *processes* on one machine - race like two CC sessions (known limitation, see Failure modes above). + per `inter-session-messaging`. + +## Failure modes + +- **Нет opt-in строки** → монитор не поднимается; ожидаемо. +- **Сервис mappa недоступен** → poll-запрос падает; монитор ретраит следующий + тик. Письма в сервисе не теряются (они — сущности), доставятся когда сервис + вернётся. НЕ дублируй в файлы — фолбэк-канал выпилен. +- **Two live interactive sessions on the same project** → оба поллят один + инбокс; дедуп по id делает доставку first-wins (кто первый прочитал id — + тот и доставил; второй пропускает). Real-time paging теряет только тот, кто + опоздал; письма не теряются (pull-свип в конце хода). +- **Monitor auto-stopped** → harness останавливает мониторы с переизбытком + событий; дедуп по id держит частоту пейджинга под баром. +- **Обработанное письмо вернулось в списке** — не баг: в Mappa нет `.read/`, + письма не перемещаются. Сверяйся с уже виденными id, не перечитывай. ## What NOT to do +- **Don't watch the file inbox** (`.agents/inbox/`) — канал выпилен; пиши и + читай через Mappa. - **Don't watch the inbox with a background Bash** (`run_in_background`) — it leaks across `/clear` and accumulates zombies. Use the Monitor tool. -- **Don't add a SessionEnd teardown hook** — the Monitor self-terminates, and - `/clear` never fires SessionEnd. -- **Don't raise more than one monitor.** The hook guarantees a clean slate before - you raise. +- **Don't add a SessionEnd teardown hook** — the Monitor self-terminates. +- **Don't raise more than one monitor.** The hook guarantees a clean slate + before you raise. - **Don't handle message content here** — that's `inter-session-messaging`. -- **Don't rely on this in headless** — use the pull model (Stop-hook + Notify). - Active headless polling, if ever needed, is a separate cron Routine, not this - skill. +- **Don't rely on this in headless** — use the pull model (Stop-hook + + Notify). diff --git a/skills/session-inbox-monitor/hooks/inbox-monitor.ps1 b/skills/session-inbox-monitor/hooks/inbox-monitor.ps1 index dcc4c70..eac16e0 100644 --- a/skills/session-inbox-monitor/hooks/inbox-monitor.ps1 +++ b/skills/session-inbox-monitor/hooks/inbox-monitor.ps1 @@ -1,17 +1,20 @@ -# SessionStart inbox-monitor injector hook (session-inbox-monitor skill). +# SessionStart inbox-monitor injector hook (session-inbox-monitor skill, v1.0.0). # +# Channel is Mappa, NOT files (flip, решение 15): letters are entities `inbox` +# (`i:N`) in the mappa service, read via HTTP `GET /inbox?project=`. # Two jobs, run on every SessionStart (startup / resume / clear / compact): # (a) SWEEP - kill orphaned inbox-monitor OS processes of THIS project. # A `/clear` does NOT fire SessionEnd, so a Monitor's underlying # poll process can outlive the session it belonged to. Without a # sweep, re-raising would stack duplicates. Match is by a sentinel # string (CLAUDE_INBOX_MONITOR) baked into the poll command PLUS -# this project's inbox path - so we never touch unrelated processes. +# this project's directory - so we never touch unrelated processes. # (b) INJECT - additionalContext telling the agent to raise a persistent -# Monitor (Monitor TOOL, not background Bash) on /.agents/inbox. +# Monitor (Monitor TOOL, not background Bash) polling the Mappa +# inbox of this project (HTTP GET /inbox). # -# Opt-in per project: fires only when the project has a `.agents/inbox/` dir OR a -# CLAUDE.md line `inbox monitor: raise on start`. +# Opt-in per project: AGENTS.md or CLAUDE.md line `inbox monitor: raise on start`. +# (The `.agents/inbox/` dir trigger is gone - no file channel anymore.) # # Headless (`claude -p`): there is NO reliable hook-level signal to detect it # (verified 2026-06-17 - `source` and CLAUDE_* env vars don't distinguish it). @@ -20,62 +23,68 @@ # run ends); a false-skip in an interactive session would silently lose the # feature - so the default errs toward raising. # -# Twin pattern: poller-interactive-lock-writer (interactive-lock.ps1). # Machine-local deploy target: ~/.claude/hooks/inbox-monitor.ps1 (registered in # ~/.claude/settings.json SessionStart). Versioned here for multi-machine rollout. param( - [string]$ProjectDir = $env:CLAUDE_PROJECT_DIR + [string]$ProjectDir = $env:CLAUDE_PROJECT_DIR, + [string]$Endpoint = $env:MAPPA_CORE_URL ) if (-not $ProjectDir) { exit 0 } +if (-not $Endpoint) { $Endpoint = 'https://mappa.vds.kzntsv.site' } # UTF-8 stdout guard. This hook emits JSON (additionalContext) to a redirected -# pipe under WinPS 5.1 - the same context that mojibaked stop-dispatcher output -# (see session-inbox-monitor-stophook-utf8-fix). $ctx is ASCII today, but the -# inbox path ($inboxFwd) is user-data interpolated into stdout, so set UTF-8 as a -# forward-guard: a non-ASCII path or content never mangles the inject. Idempotent. +# pipe under WinPS 5.1 - the same context that mojibaked stop-dispatcher output. +# The project name (user-data) is interpolated into stdout, so set UTF-8 as a +# forward-guard. Idempotent. [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $OutputEncoding = [System.Text.Encoding]::UTF8 -$inbox = Join-Path $ProjectDir '.agents/inbox' -$claudeMd = Join-Path $ProjectDir 'CLAUDE.md' +$projectName = Split-Path $ProjectDir -Leaf +$agentsMd = Join-Path $ProjectDir 'AGENTS.md' +$claudeMd = Join-Path $ProjectDir 'CLAUDE.md' -# --- opt-in gate ----------------------------------------------------------- +# --- opt-in gate (line in AGENTS.md or CLAUDE.md) --------------------------- $optedIn = $false -if (Test-Path $inbox) { - $optedIn = $true -} elseif (Test-Path $claudeMd) { - if (Select-String -Path $claudeMd -SimpleMatch 'inbox monitor: raise on start' -Quiet -ErrorAction SilentlyContinue) { - $optedIn = $true +foreach ($md in @($agentsMd, $claudeMd)) { + if (Test-Path $md) { + if (Select-String -Path $md -SimpleMatch 'inbox monitor: raise on start' -Quiet -ErrorAction SilentlyContinue) { + $optedIn = $true + break + } } } if (-not $optedIn) { exit 0 } -# Forward-slash inbox path: the Monitor poll command (Git Bash) uses this form, +# Forward-slash project dir: the Monitor poll command (Git Bash) uses this form, # so both the sweep match and the injected command share one literal. -$inboxFwd = ($inbox -replace '\\', '/') +$dirFwd = ($ProjectDir -replace '\\', '/') -# --- (a) sweep orphaned monitors of THIS inbox ----------------------------- -# Match = sentinel AND this inbox's path in the same process command line. +# --- (a) sweep orphaned monitors of THIS project ---------------------------- +# Match = sentinel AND this project's dir in the same process command line. try { Get-CimInstance Win32_Process -ErrorAction Stop | Where-Object { $_.CommandLine -and $_.CommandLine -match 'CLAUDE_INBOX_MONITOR' -and - $_.CommandLine -like "*$inboxFwd*" + $_.CommandLine -like "*$dirFwd*" } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } } catch { } -# --- (b) build the canonical Monitor poll command -------------------------- +# --- (b) build the canonical Monitor poll command --------------------------- # `: CLAUDE_INBOX_MONITOR` is a bash no-op carrying the sweep sentinel in the -# process command line without polluting the event stream. De-dups by filename -# so a sitting message pages once, not every 15s (a noisy monitor is auto-stopped). -$cmd = @' -: CLAUDE_INBOX_MONITOR; d='__INBOX__'; s=' '; while true; do for f in "$d"/*.md; do [ -e "$f" ] || continue; n=$(basename "$f"); case "$s" in *" $n "*) continue;; esac; s="$s$n "; echo "New inter-session message in inbox: $n - read .agents/inbox/ and handle it now"; done; sleep 15; done -'@ -$cmd = $cmd.Trim().Replace('__INBOX__', $inboxFwd) +# process command line without polluting the event stream. Polls the Mappa +# inbox of this project over HTTP, extracts letter ids via node (present on +# every machine that runs the mappa MCP), de-dups by id so a sitting letter +# pages once, not every 15s (a noisy monitor is auto-stopped). +$auth = '' +if ($env:MAPPA_API_TOKEN) { $auth = "-H 'x-api-token: $($env:MAPPA_API_TOKEN)'" } +$cmd = @" +: CLAUDE_INBOX_MONITOR; s=' '; while true; do ids=`$(curl -s -m 10 $auth '__ENDPOINT__/inbox?project=__PROJECT__&limit=50' | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{try{const r=JSON.parse(d).rows||[];for(let i=r.length-1;i>=0;i--)console.log(r[i].id)}catch(e){}})"); for id in `$ids; do case "`$s" in *" `$id "*) continue;; esac; s="`$s`$id "; echo "New inter-session message in Mappa inbox (letter id `$id) - read it via inbox_monitor and handle now"; done; sleep 15; done +"@ +$cmd = $cmd.Trim().Replace('__ENDPOINT__', $Endpoint.TrimEnd('/')).Replace('__PROJECT__', $projectName) # --- (c) inject the raise-instruction -------------------------------------- $ctx = @"