Compare commits
105 Commits
0c97ed973a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4964849397 | |||
| c5eee95460 | |||
| 79adaf928d | |||
| b51657bfe4 | |||
| 48fa29e9dc | |||
| 65a2518a5e | |||
| 84e28c5d1c | |||
| 607a475e28 | |||
| 252e22ec80 | |||
| ac0c41feb8 | |||
| 314b15ea25 | |||
| c310ada38d | |||
| 5c726eb5ec | |||
| d2059b42bd | |||
| 2707ba48b5 | |||
| 9c969cefb9 | |||
| 37f617a461 | |||
| ccac87200f | |||
| b1cc0439a7 | |||
| 3f78c54dd2 | |||
| ddcb552601 | |||
| 74fdbe8070 | |||
| 973e59b083 | |||
| c09901f9a6 | |||
| e2f2e3a342 | |||
| b529503def | |||
| 031268333e | |||
| e499a69bd0 | |||
| 247abbbf12 | |||
| e3f20193f0 | |||
| 1b0118d254 | |||
| 4f8e12aedf | |||
| 7504b09b87 | |||
| 5301e853f7 | |||
| cf8d574c9f | |||
| 621eacc808 | |||
| 4b4339733c | |||
| 90861fc197 | |||
| 6fcb8a8adb | |||
| cbba01f1e1 | |||
| 931330bf31 | |||
| e81217388e | |||
| c6dfa9349d | |||
| 3ea7e53f99 | |||
| dd9e38b2ee | |||
| d0b8041891 | |||
| 5675da52a7 | |||
| 5b5085eb80 | |||
| b6b8560fc0 | |||
| 1ca1f2f868 | |||
| d1adf7806d | |||
| cb65d377eb | |||
| 8cfd46eb09 | |||
| 195de4b8e6 | |||
| 0177d46101 | |||
| bf807f232b | |||
| 76ff6ad3fc | |||
| e91eb701aa | |||
| 271fcfae93 | |||
| 41a805d66c | |||
| b7ac5cd5a6 | |||
| 8c19294a28 | |||
| 805077902d | |||
| 0ed7060116 | |||
| 3806b0407b | |||
| dc2cd0e522 | |||
| a1f12fcdd4 | |||
| aabf8da806 | |||
| e31921b7a7 | |||
| 65330605d8 | |||
| 7cd1384c98 | |||
| d96af7f737 | |||
| 197007f21e | |||
| 564adb140e | |||
| 9b606f79bb | |||
| c213997e1d | |||
| ae45a51420 | |||
| aa80e9faa5 | |||
| 2115e2cd50 | |||
| 44ac3be5b7 | |||
| a7144f6523 | |||
| 3c311427c8 | |||
| 422fb84664 | |||
| 60f317ace0 | |||
| 3dff74d584 | |||
| 1f29e60b51 | |||
| 9bddab1836 | |||
| 0efd8cd814 | |||
| 525a10048b | |||
| 6d087f96a2 | |||
| cbd12fb3bc | |||
| 0d8bda1714 | |||
| 9c7d256fe5 | |||
| 62ec047241 | |||
| c688a60b2a | |||
| bf6d529ea2 | |||
| 2cd12ae321 | |||
| bc7b00fa21 | |||
| b9c13a0aaf | |||
| fe8484bb2b | |||
| 37ecc1f8e5 | |||
| 437cc85e30 | |||
| 74c407dc73 | |||
| e2077ec062 | |||
| b5024703f8 |
5
.agents/inbox/README.md
Normal file
5
.agents/inbox/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# ⛔ Файловый инбокс закрыт
|
||||||
|
|
||||||
|
**Не читать. Не править.** Канал почты — mappa (`mcp__mappa__inbox_*`): письма = inbox-сущности проекта. Скилы: `mappa-messaging`, `mappa-session-orient` (raise on start).
|
||||||
|
|
||||||
|
Файлы ниже — легаси-история (файловый канал закрыт решением 2026-08-25).
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -90,3 +90,6 @@ coverage/
|
|||||||
# Missing here made `git status` see `?? .tasks/claims/` → poller skipped every
|
# Missing here made `git status` see `?? .tasks/claims/` → poller skipped every
|
||||||
# claim with "working tree dirty". Mirrors .common/.gitignore.
|
# claim with "working tree dirty". Mirrors .common/.gitignore.
|
||||||
.tasks/claims/
|
.tasks/claims/
|
||||||
|
|
||||||
|
# mappa bootstrap cache (генерируется, не в репо)
|
||||||
|
.mappa/share/
|
||||||
|
|||||||
9
.mappa/config.yaml
Normal file
9
.mappa/config.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# mappa project marker — machine-readable identifier of a mappa project folder
|
||||||
|
schema_version: 1 # версия схемы файла (bump при изменении структуры)
|
||||||
|
protocol_version: 1 # версия протокола интерпретации маркера
|
||||||
|
project: skills
|
||||||
|
tenant: vitya
|
||||||
|
url: https://mappa.vds.kzntsv.site
|
||||||
|
git_provider: gitea
|
||||||
|
git: OpeItcLoc03/skills
|
||||||
|
git_host: git.kzntsv.site
|
||||||
@@ -17,4 +17,16 @@ Rewrite inter-session-messaging → **mappa-messaging** (редизайн mappa-
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-messaging/SKILL.md v1.0.0 — rewrite inter-session-messaging v2.2.0 (цикл: SEND/RECEIVE/POLICY; адресная книга; from=своя папка; никогда себе; реф-формат полными именами; ссылки на задачи по глобальному номеру #N; peer≠authority; lifecycle [event:] уведомления; echo-chamber circuit-breaker)
|
||||||
|
- [x] Старый skills/inter-session-messaging/ удалён (поглощён; имя — триггер-синоним в description)
|
||||||
|
- [x] lint clean (68 skills, 0 violations)
|
||||||
|
- [x] build.sh → dist/mappa-messaging.skill (старый .skill удалён)
|
||||||
|
- [x] install.sh → ~/.claude/skills + ~/.agents/skills; старый удалён из обоих живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на триггере «отправить письмо .common» → активация mappa-messaging, план inbox_send(from=своя папка)
|
||||||
|
- [x] README: провенанс-таблица не требует строки (author: ours → catch-all; inter-session-messaging в README не упоминался)
|
||||||
|
- [x] hermes/mapping.yaml: не трогал (inter-session-messaging был unmapped; build-hermes уже падает на 15+ unmapped — pre-existing)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- RED-базис: триггер-поверхность унаследована из inter-session-messaging v2.2.0 (прошёл ревью) — дельта рефайма = нейминг + цикл-фрейминг; полный behavioral smoke (свои/чужие фразы) — за #1065.
|
||||||
|
- Cross-refs в теле: названы будущие члены suite (mappa-task-work, mappa-closing-ritual, mappa-delegation, mappa-brainstorm-promote) — лягут по мере импла; до их появления старые скилы (using-tasks, session-handoff, delegate-task) продолжают существовать.
|
||||||
|
|||||||
@@ -17,4 +17,14 @@ Relational/структурные вопросы (связи, backlinks, сир
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-knowledge/SKILL.md v1.0.0 — слияние using-wiki v2.2.0 + using-wiki-graph v1.1.0 в один цикл-скил (ingest/query/lint + граф-слой для реляционных/структурных вопросов)
|
||||||
|
- [x] Старые skills/using-wiki/ + skills/using-wiki-graph/ удалены (поглощены; имена — триггер-синонимы в description)
|
||||||
|
- [x] lint clean (67 skills, 0 violations)
|
||||||
|
- [x] build.sh → dist/mappa-knowledge.skill; install.sh → dual targets; старые удалены из живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на реляционном вопросе (связь таска↔спека) → активация mappa-knowledge, граф-слой (graph_path→no-path, backlinks), корректная семантика рёбер
|
||||||
|
- [x] Писано нейтрально (summaries/#1026 не упоминается); реф-конвенция полными именами (#1028, уже была в исходниках)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- RED-базис: триггер-поверхность унаследована из using-wiki/using-wiki-graph (прошли ревью); дельта = слияние + цикл-фрейминг + guarded failure-mode графа. Полный behavioral smoke — за #1065.
|
||||||
|
- Побочная lint-находка GREEN-теста: рефы в прозе (не [[викилинки]]) рёбер не дают → спека может быть сиротой, «таска↔спека» в графе теряется. Это известная семантика решения 4 (рёбра только из [[refs]]), не баг скила — отмечено как наблюдение, кандидат в follow-up, если понадобится проставлять [[викилинки]] при создании тасок-промоушена.
|
||||||
|
|||||||
@@ -15,4 +15,14 @@ Fold-in 1: mappa-service target. Промоут в mappa-сервисные бо
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-brainstorm-promote/SKILL.md v1.2.0 (MINOR) — UPDATE workshop-promote-brainstorm: добавлена 4-я ветка маршрутизации **mappa-service** (fold-in 1: лиз через task_claim_next, спека через mcp__mappa__wiki_create, импл-таски через mcp__mappa__task_create, pointers-таска НЕ нужна если спека в вики w:NNNN, review-umbrella сервисная таска, covering-письмо в инбокс цели)
|
||||||
|
- [x] NB (2026-08-24, инцидент): tasks_create ПОСЛЕДОВАТЕЛЬНО, не батчем (гонка sha-CAS счётчика agenda; при промоуте mappa-skill-suite 6/7 упали) — в шаге 8 + failure modes + what-not-to-do
|
||||||
|
- [x] File channel (projects-meta → .tasks/STATUS.md) сохранён; шаги перенумерованы (вставлен шаг 4)
|
||||||
|
- [x] Старое имя workshop-promote-brainstorm — триггер-синоним в description; каталог git mv
|
||||||
|
- [x] lint clean (67 skills, 0 violations); build.sh → dist/mappa-brainstorm-promote.skill (старый .skill удалён); install.sh → dual; старый удалён из живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на «промоутни брейнсторм… таргет mappa» → активация mappa-brainstorm-promote, service channel (лиз/task_create последовательно/wiki_create/без pointers/review-umbrella/covering-письмо)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- RED-базис: UPDATE существующего скила (триггеры не менялись); дельта = fold-in 1 + NB последовательности. Полный behavioral smoke — за #1065.
|
||||||
|
- Актуальность шага 3 (определение канала): сервисные борды — mappa, .common (доска в mappa-сущностях); обычные проекты — файловая доска. Определение по наличию .tasks/STATUS.md.
|
||||||
|
|||||||
@@ -17,4 +17,13 @@ Rewrite delegate-task → **mappa-delegation** (редизайн mappa-skill-sui
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-delegation/SKILL.md v1.0.0 — rewrite delegate-task v0.5.1 (цикл: pre-flight gate → шаблон → preview → confirm → covering-письмо → review-umbrella → downstream)
|
||||||
|
- [x] Старый skills/delegate-task/ удалён (поглощён; имя — триггер-синоним в description)
|
||||||
|
- [x] Suite-ссылки: using-tasks→mappa-task-work, inter-session-messaging→mappa-messaging, using-wiki→mappa-knowledge; нота лизинговой модели #1054 (create-без-лиза — опционально, контракт работает на текущих тулах)
|
||||||
|
- [x] lint clean (67 skills, 0 violations); build.sh → dist/mappa-delegation.skill (старый .skill удалён); install.sh → dual; старый удалён из живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на «создать задачу на агента… common» → активация mappa-delegation, обязательная пара tasks_create + covering-письмо (адрес из адресной книги, [event: created]), review-umbrella с наследованием weight
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- RED-базис: тело унаследовано из delegate-task v0.5.1 (прошёл ревью + smoke); дельта = rename, suite-ссылки, цикл-фрейминг, нота #1054. Полный behavioral smoke — за #1065.
|
||||||
|
- Поглощает delegate-task без потери контента (все шаги 1–7 сохранены, включая weight-наследование review и downstream-правило task+letter).
|
||||||
|
|||||||
@@ -17,4 +17,15 @@ Rewrite using-tasks + task-format + task-loop + priority-due → **mappa-task-wo
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-task-work/SKILL.md v1.0.0 — центральный цикл: ориентация → выбор работы (claim, priority/due) → исполнение → сдача (close + review-umbrella) + пауза/переключение
|
||||||
|
- [x] Loop-mode ВНУТРИ (вариант A, отдельный скил не создаётся): «поработай очередь»/«work the queue» → цикл claim→work→close→claim; пустая очередь = стоп, без демона/CronCreate; session_break gate; consult gate (human-only/strict-human → STOP перед close/commit)
|
||||||
|
- [x] Priority/Due-раздел: приоритет = территория человека, агент ставит только при создании, дефолт P1, просрочка → admin_overdue_scan notify однократно, без авто-бампа
|
||||||
|
- [x] Формат таски (из task-format): mappa task_create схема (priority/due при создании) + legacy STATUS.md блок (переходный, Weight/Notify обязательны)
|
||||||
|
- [x] Поглощены: using-tasks (борд/лиз/close/notify/рефы [[task:N]]), task-format (формат), task-loop (loop-mode), task-priority-due (раздел). Старые имена — триггер-синонимы в description
|
||||||
|
- [x] lint clean (65 skills, 0 violations); build.sh → dist/mappa-task-work.skill (старые .skill удалены); install.sh → dual; старые удалены из живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на «поработай очередь» → активация mappa-task-work, loop-mode, стоп-гейты, пустая очередь = стоп без поллинга
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- RED-базис: контент унаследован из трёх скилов (все прошли ревью/smoke); дельта = слияние + цикл-фрейминг + priority/due раздел. Полный behavioral smoke (вкл. loop-mode, session-break, empty-stop) — за #1065.
|
||||||
|
- Убраны: task-loop ссылки на projects-meta claim (primary — mappa task_claim_next; file channel — переходный, описан в секции legacy).
|
||||||
|
|||||||
@@ -17,4 +17,14 @@ Handoff: sliding, per-project, versioned-история; read на старте
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-closing-ritual/SKILL.md v1.0.0 — НОВЫЙ скилл (финиш-фаза): scope check → mid-task capture → compose handoff → handoff_write (версия h:N) → PROPOSE wiki-ingest → PROPOSE task closes → один блок-предложение; мутации только после «да»
|
||||||
|
- [x] mode=light для ad-hoc: явный вопрос «Сделать handoff?», НЕ автоматический sweep; решение за человеком
|
||||||
|
- [x] Поглощает session-handoff (write-часть); read-часть уходит в mappa-session-orient (#1064); старое имя — триггер-синоним
|
||||||
|
- [x] Старый skills/session-handoff/ удалён (включая hooks/commit-detector — новый дизайн: ритуал на session-end, не на substantive commit)
|
||||||
|
- [x] lint clean (65 skills, 0 violations); build.sh → dist/mappa-closing-ritual.skill; install.sh → dual; старый удалён из живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на «завершаем сессию» → активация mappa-closing-ritual, полный ритуал (7 шагов), мутации только после «да», mode=light «Сделать handoff?»
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- RED-базис: write-процедура унаследована из session-handoff v1.0.0 (прошёл ревью); дельта = split read/write + mode=light + confirm-гейт. Полный behavioral smoke (триггеры свои + false-positive на task-зоне) — за #1065.
|
||||||
|
- commit-detector hooks удалены осознанно: suite проектирует closing-ritual как session-end-driven, а не commit-driven.
|
||||||
|
|||||||
@@ -17,4 +17,15 @@
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] skills/mappa-session-orient/SKILL.md v1.0.0 — старт-фаза: контракт → pull (--ff-only, полный цикл) → handoff read (staleness >7д → ask; orient+ask, без auto-execute) → inbox raise+sweep → liveness-сводка (meta_health/admin_status/snapshot, «живо/мертво») → live-ingest query (session_list, stale-active краш-детект, «другая связка → предложить»)
|
||||||
|
- [x] Граница orient/ops (w:2605 round 3): «живо/мертво»; проблема на старте → эскалация человеку/диагностической сессии, не углубление
|
||||||
|
- [x] Поглощены: pulling-before-work, session-handoff(read), session-inbox-monitor(raise), using-system-snapshot (liveness); старые имена — триггер-синонимы
|
||||||
|
- [x] Live-ingest 404-skip задокументирован (роуты /session не задеплоены — сервер #1022 в репо, деплой ждёт #1055); контракт — w:2604
|
||||||
|
- [x] mappa-messaging: ссылки session-inbox-monitor → mappa-session-orient (inbox raise) обновлены (3 места)
|
||||||
|
- [x] lint clean (63 skills, 0 violations); build.sh → dist/mappa-session-orient.skill; install.sh → dual; поглощённые удалены из живых диров
|
||||||
|
- [x] GREEN micro-test: свежий pi -p на «начало сессии» → ритуал по шагам (контракт→pull→handoff→inbox→liveness→live-ingest), граница «живо/мертво» + эскалация, 404-skip, read-only
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- #1064 была 🔵 blocked ← #1024 (клиент session-sync). Скил-документ завершён по контракту w:2604/w:2605; live-ingest E2E (шаг 6) отложен: сервер #1022 не задеплоен (#1055), клиент #1024 (.common) открыт. 404-skip в скиле — ориентация не блокируется.
|
||||||
|
- RED-базис: контент унаследован из 4 поглощённых скилов (все прошли ревью); дельта = слияние + live-ingest query + граница orient/ops. Полный behavioral smoke — за #1065.
|
||||||
|
|||||||
@@ -35,4 +35,15 @@ Findings → follow-up tasks через tasks_create в OpeItcLoc03/skills.
|
|||||||
|
|
||||||
## Completed steps
|
## Completed steps
|
||||||
|
|
||||||
|
- [x] Ревью запущено через clean-context субагентов (не-имплементер identity: review_subagent с чистой спецификацией + свежие pi -p сессии без истории) — метод review-kit-pi-method
|
||||||
|
- [x] **Структурное ревью vs w:2605 — 7/7:** batch 1 (messaging/knowledge/promote/delegation): 3 PASS, promote NEEDS-WORK → исправлено (cycle/procedure фрейминг, фикс 78542c0); batch 2 (task-work/closing-ritual/session-orient): 3 PASS
|
||||||
|
- [x] **Минорные findings исправлены:** EN-триггеры в messaging (78542c0), attribution review-umbrella в task-work (45baadc); остальные миноры — стилистические (inline-absorption vs таблица), не блокеры
|
||||||
|
- [x] **Behavioral smoke (свежие pi -p, чистая сессия):**
|
||||||
|
- Позитив (старые имена = синонимы): using-tasks → mappa-task-work, using-wiki → mappa-knowledge, delegate-task → mappa-delegation, «напиши письмо» → mappa-messaging, «промоутни… таргет mappa» → mappa-brainstorm-promote (service channel), «завершаем сессию» → mappa-closing-ritual, «начало сессии» → mappa-session-orient, «поработай очередь» → loop-mode
|
||||||
|
- Негатив: «поставь таску себе» → НЕ делегирование (mappa-task-work территория), «отбой» → анти-триггер, без активации
|
||||||
|
- [x] **Отложенные зависимости (не findings):** live-ingest E2E (шаг 6 session-orient) — после деплоя #1055 + клиента #1024 (404-skip задокументирован в скиле); build-hermes unmapped — pre-existing
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
- Ревьюер-identity: .workshop (решение оператора) через clean-context субагентов — identity-not-location, имплементерская сессия не оценивала свои артефакты сама.
|
||||||
|
- Verdict: APPROVE-WITH-FINDINGS → все findings зафайлены и исправлены (3 фикса), блокеров нет.
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# mappa-brainstorm-promote-storm-channel
|
||||||
|
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-08-25T06:00:37.319Z -->
|
||||||
|
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Апдейт скила mappa-brainstorm-promote (1.5.0 → 1.6.0): миграция с файлового канала на mappa storm-сущности.
|
||||||
|
|
||||||
|
Скоуп:
|
||||||
|
1. Буфер шторма = mappa storm-сущность (type=storm) в ЛЮБОМ проекте (не файл .workshop/.brainstorm/). Скил становится project-agnostic: шторм живёт там, где его ведут, не только в воркшопе.
|
||||||
|
2. Промоут mappa-service маршрута через storm_promote (атомарно buffer → wiki-страница + archive, решение 7), не через git mv в .workshop/.archive/.
|
||||||
|
3. Зафиксировать «штормы в любом проекте» в mappa-спеке (concepts/mappa) — сейчас скил воркшоп-центричный.
|
||||||
|
4. Workshop-meta маршрут: файловые .brainstorm/.archive остаются только для локальной методологии зоны — или мигрируют тоже (решить в таске).
|
||||||
|
5. Summary-дисциплина уже в 1.5.0 (9b606f7) — не дублировать.
|
||||||
|
|
||||||
|
Контекст: решение оператора 2026-08-25 («штормы могут вестись не только в воркшопе»). Связано: wiki:2661 (unified search — storm-карточки), task:1048 (review mappa-wiki-search). Исполнитель — workshop-сессия (оператор: «ты сам сделаешь в новой сессии»).
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
|
||||||
|
## Notes
|
||||||
@@ -1,46 +1,3 @@
|
|||||||
---
|
# ⛔ Файловая доска закрыта
|
||||||
_last_updated_: 2026-08-12T17:21:33Z
|
|
||||||
session_id: 2026-08-12-setup-tasks-noop
|
|
||||||
---
|
|
||||||
|
|
||||||
# Next session handoff
|
**Не читать. Не править.** Канон — mappa (`mcp__mappa__task_*`): task-сущности проекта. Скил: `mappa-task-work`.
|
||||||
|
|
||||||
**Сессия (headless): «настрой таски» → сработал `setup-tasks` → mode **noop**: доска уже каноническая (STATUS.md 70KB, emoji-легенда, `**Poller:** eligible`, 24 per-task файла, 12 блоков задач). Коммитов нет, мутаций нет. Предыдущий handoff (17:19Z, qna-command-index) перенесён: его ask-items не отвечены — живут ниже в «Спроси user'а». Актуальный снимок доски: 0 🔴 / 3 🟡 / 1 🔵 / 12 ⚪ / 11 🟢.**
|
|
||||||
|
|
||||||
## Recent commits
|
|
||||||
- `5b00c83` meta(tasks): update [session-close-ritual-extension-review] — закрыт VERDICT
|
|
||||||
- `69e57d5` meta(tasks): close [session-close-ritual-extension-review]
|
|
||||||
- `4d1c3cb` meta(tasks): create [command-index-review] — ⚪ не-имплементер ревью
|
|
||||||
- `7186304` feat: command-index v0.1.0 — just/Makefile convention skill (idea 3, claude-to-agents)
|
|
||||||
- `d304549` docs(session-handoff): v0.5.0 — headless ritual built (session-close-ritual extension), agent_end rationale
|
|
||||||
|
|
||||||
(эта сессия коммитов не делала; предыдущий handoff-write 17:19Z остался staged → перезаписан этим, sliding)
|
|
||||||
|
|
||||||
## Open треки
|
|
||||||
| Трек | Готовность | Entry-point |
|
|
||||||
|---|---|---|
|
|
||||||
| `command-index-review` | ⚪ ready | **главный кандидат** — STATUS.md. Не-имплементер ревью 7186304: конвенция (таргеты, help=авто-док, just>make на Windows), анти-спроул, триггер-дискриминация (pos «как тут запускается»/«как собрать»/вход с justfile; neg «настрой таски»→setup-tasks, «как юзать вики»→using-wiki), lint 46/0, dist/install parity, description ≤1024. Follow-up вне скоупа: project-bootstrap эмитит justfile. |
|
|
||||||
| `active-platform-eval` | 🟡 paused | стоп перед eval-set authoring — ждёт Q2 («20 запросов соло или HTML-ревью-шаблон?»). |
|
|
||||||
| `skill-readmes` | 🟡 paused | англ. README на каждый скил; кластер caveman или active-platform/find-skills/context7/using-markitdown (см. `compress-dedup`). |
|
|
||||||
| `agent-neutral-skill-pipeline` | 🟡 paused | долг idea 19 п.5 — осознанно отложен. |
|
|
||||||
| `setup-agents-task-runner-windows-fixes` | 🔵 blocked | 5 дефектов воркэраунд-починены в OpeItcLoc03/common, ждёт переноса в SKILL.md. |
|
|
||||||
| `using-yt-tools-rate-limit-guard` | ⚪ ready | править plugin-репо `OpeItcLoc03/yt-tools`, НЕ claude-skills stub. |
|
|
||||||
| `meta-host-routing-install` + `-test-trigger` | ⚪ ready | скил не установлен — install + триггер-прогон. |
|
|
||||||
| `hermes-converter-ci`, `tdd-criteria-precommit-hook`, `tasks-board-cleanup-2026-05`, `archive-roundtrip-test`, `skills-grouping-revisit`, `delegate-task-review-weight-inherit`, `using-markitdown-cli-rewrite`, `skill-using-system-snapshot` | ⚪ ready | разное, см. STATUS.md блоки. |
|
|
||||||
|
|
||||||
## Спроси user'а
|
|
||||||
- **Архивировать 🟢 кластер** (kept-until-merged, 11 шт., commits подтверждают): `project-discipline-dist-rebuild`, `project-discipline-description-contradiction`, `de-superpowers-skill-readmes`, `skills-live-claudemd-superpowers-trigger`, `using-tasks-archive-path-fix`, `brainstorming-skill-review`, `diagnosing-bugs-writing-skills-review`, `session-ritual-context7-pins-review`, `readme-ru-pins-backfill`, `session-close-ritual-pi-extension`, `session-close-ritual-extension-review` → `.tasks/.archive/done-2026-08.md` (конвенция tasks-board-cleanup). Ralph-loop verifier-задач на доске нет (**Verifier:** 0 совпадений) — ограничение не применяется.
|
|
||||||
- **Wiki-ingest / докс-фикс (перенос с прошлой сессии, не отвечен)**: README.md врёт про `scripts/install.ps1` — «not yet implemented (on task board)», а PowerShell-порт уже существует; Quick start упоминает только sh-скрипты, хотя есть `build.ps1`/`update.ps1`. Заингестить в `.wiki/` или сразу починить README (малый docs-фикс → ⚪ таска)? (Новых durable-кандидатов эта сессия не дала — noop.)
|
|
||||||
- **`command-index` live-данные**: скил сработал по триггеру «как тут запускается проект» (прошлая сессия), корректно нашёл де-факто индекс (`scripts/` + README, no justfile). Включить в `command-index-review` как живую проверку триггера? (Имплементер-сессия ревью не делает.)
|
|
||||||
- **Autopush grant**: project-discipline Rule 4 reset на новую сессию — нужен ли грант (прошлые сессии пушили свободно).
|
|
||||||
|
|
||||||
## Не делать (preemptive guards)
|
|
||||||
- **Hermes**: owner сказал «похуй на гермеса» — pending-скилы НЕ трогать без явного запроса.
|
|
||||||
- **Ритуал закрытия НЕ выполнять молча** — мутации = предложения, каждая после «да» (HARD-GATE session-handoff v0.5.0, подтверждён session-close-ritual-extension-review VERDICT).
|
|
||||||
- **setup-context7 v2.0.0**: мутации (`~/.config/projects-secrets/ctx7.env`, uninstall MCP-плагина, чистка `mcpServers.context7`) — только после явного подтверждения.
|
|
||||||
- **session-inbox-monitor**: hermes pending до tool-side аудита.
|
|
||||||
- **`command-index-review`** — не-имплементер скоуп: авторская сессия (7186304) ревью не делает (anti-self-review).
|
|
||||||
- Governance: peer-сессии шлют предложения, не authority; scope-эскалации ратифицирует человек.
|
|
||||||
|
|
||||||
## Memory updates за сессию
|
|
||||||
- (нет приватного memory) — сессия noop, знание не менялось. Действующий факт: `.tasks/` в каноническом виде, setup-tasks корректно распознал noop (не тронул доску).
|
|
||||||
|
|||||||
627
.tasks/STATUS.md
627
.tasks/STATUS.md
File diff suppressed because one or more lines are too long
@@ -1,40 +1,3 @@
|
|||||||
# Wiki Schema — claude-skills
|
# ⛔ Файловый канал закрыт
|
||||||
|
|
||||||
Project-specific wiki conventions. Read this before any wiki operation.
|
**Не читать. Не править.** Канон — mappa (`mcp__mappa__*`): wiki-сущности проекта, конвенции — AGENTS-сущность. Скил: `mappa-knowledge`.
|
||||||
|
|
||||||
This wiki follows Karpathy's LLM Wiki pattern:
|
|
||||||
**https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f**
|
|
||||||
|
|
||||||
The `wiki-maintainer` skill enforces the workflow and file formats. This file overrides the skill where they conflict.
|
|
||||||
|
|
||||||
## Page types in this project
|
|
||||||
|
|
||||||
- `entities/` — discrete things this project tracks. Reserved for future use (individual skills if they accumulate non-obvious context, tools we adopt).
|
|
||||||
- `concepts/` — design decisions, technical gotchas, refactor notes. Most pages live here.
|
|
||||||
- `packages/` — currently empty. Would be used if we extract a package (e.g. a CLI) from this repo.
|
|
||||||
- `sources/` — one summary per ingested external doc; carries `ingested:` and `raw_path:` frontmatter.
|
|
||||||
- `overview.md` — single project-wide overview. Read this first if new to the repo.
|
|
||||||
|
|
||||||
## Naming
|
|
||||||
|
|
||||||
- `kebab-case.md`, **Latin only**. Transliterate Cyrillic in filenames; keep the original title in the H1 + frontmatter.
|
|
||||||
|
|
||||||
## Domain conventions
|
|
||||||
|
|
||||||
- Skill-related design notes go in `concepts/<skill-name>-*.md` (e.g. `active-platform-decision.md`).
|
|
||||||
- Build / install pipeline notes live in `concepts/build-*.md`.
|
|
||||||
- Refactor / re-alignment commits get a `concepts/<what>-realignment.md` page.
|
|
||||||
|
|
||||||
## Frontmatter
|
|
||||||
|
|
||||||
Minimum:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
title: Human-readable title
|
|
||||||
type: concept | entity | package | source | overview
|
|
||||||
updated: YYYY-MM-DD
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
`source/` pages also carry `ingested:` and `raw_path:`.
|
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ created: 2026-08-12
|
|||||||
|
|
||||||
# pi-extension headless ritual (agent_end, mode guard, loop-guard)
|
# pi-extension headless ritual (agent_end, mode guard, loop-guard)
|
||||||
|
|
||||||
Durable lessons from building `session-close-ritual` (репо `OpeItcLoc03/pi-extensions`, extensions/),
|
Durable lessons from building `session-close-ritual` (консолидирован в
|
||||||
|
`extensions/mappa.ts` репо `OpeItcLoc03/pi-extensions`, task:1486; исторически —
|
||||||
|
отдельный файл `session-close-ritual.ts`),
|
||||||
the headless injector for the session-handoff closing ritual. All three points
|
the headless injector for the session-handoff closing ritual. All three points
|
||||||
were live-verified, not docs-read-only.
|
were live-verified, not docs-read-only.
|
||||||
|
|
||||||
@@ -58,6 +60,8 @@ Cache per-cwd; staleness within a long session is accepted (same as
|
|||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- Source: `~/projects/pi-extensions/extensions/session-close-ritual.ts` (+ `scripts/session-close-ritual.test.mjs`, 12 blocks)
|
- Source: `~/projects/pi-extensions/extensions/mappa.ts` (секция close-ritual;
|
||||||
|
консолидация 6 расширений, task:1486 — исторически `session-close-ritual.ts`
|
||||||
|
+ `scripts/session-close-ritual.test.mjs`, 12 blocks, ныне тесты на mappa.ts)
|
||||||
- Skill: `session-handoff` v0.5.0 — «Headless (pi)» section
|
- Skill: `session-handoff` v0.5.0 — «Headless (pi)» section
|
||||||
- pi docs: `extensions.md` — lifecycle diagram, `sendUserMessage` (deliverAs/triggerTurn), mode table
|
- pi docs: `extensions.md` — lifecycle diagram, `sendUserMessage` (deliverAs/triggerTurn), mode table
|
||||||
|
|||||||
@@ -1,62 +1,3 @@
|
|||||||
# Wiki Index
|
# ⛔ Файловый канал закрыт
|
||||||
|
|
||||||
Catalog of all wiki pages. One line per page, organized by type. Updated on every ingest / new page.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
- [overview.md](overview.md) — what claude-skills is, layout, how to navigate
|
|
||||||
|
|
||||||
## Entities
|
|
||||||
|
|
||||||
<!-- (none yet) -->
|
|
||||||
|
|
||||||
## Concepts
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- [active-platform-decision.md](concepts/active-platform-decision.md) — why `active-platform` is a skill (not a memory entry); why default = Windows; how it's wired into `project-bootstrap`
|
|
||||||
- [bootstrap-claude-md-merge.md](concepts/bootstrap-claude-md-merge.md) — project-bootstrap@1.3.0 — Step 5 upgrade path becomes idempotent merge (read → diff vs template → confirm → append missing); fixes silent gap where pre-1.2.0 projects never picked up new canonical triggers (`check across all projects`, `we're on Windows`)
|
|
||||||
- [bootstrap-skill-deps-check.md](concepts/bootstrap-skill-deps-check.md) — project-bootstrap@1.7.0 — Step 5.6 collapses the per-skill "detect-and-recommend" mirror shape into one generic `trigger → fulfiller` table walker (skill vs plugin kind, never auto-install); subsumes the deferred `[bootstrap-recommend-projects-meta]` and the existing `superpowers`-only detector
|
|
||||||
- [bootstrap-manifest.md](concepts/bootstrap-manifest.md) — record of which `project-bootstrap` / `setup-wiki` / `setup-tasks` versions initialized this project's `.wiki/` and `.tasks/` layout (overwritten on re-bootstrap; history in git)
|
|
||||||
- [build-notes.md](concepts/build-notes.md) — why `build.ps1` exists alongside `build.sh`; PS 5.1 backslash-in-zip gotcha; how to extract a `.skill`
|
|
||||||
- [install-cross-platform.md](concepts/install-cross-platform.md) — paired-script parity contract for `install.{ps1,sh}` AND `build.{ps1,sh}`; rationale for the `--prune` / `-Prune` flag (combined-with-action, global-scan, default-off); install-side prunes target dirs, build-side prunes `dist/*.skill` files
|
|
||||||
- [install-portability.md](concepts/install-portability.md) — `install.sh` / `build.sh` rewritten to drop `mapfile` (bash 4+) and `find -printf` (GNU only) so stock macOS (bash 3.2 + BSD find) works
|
|
||||||
- [context7-setup.md](concepts/context7-setup.md) — context7 CLI-first (2026-08-12): `ctx7` CLI + key in `~/.config/projects-secrets/ctx7.env`, plugin `context7@claude-plugins-official` + manual MCP entries removed; setup-context7 skill (one-time install/migrate, confirmation gates) + using-context7 policy; plugin era = rollback reference
|
|
||||||
- [projects-meta-skills.md](concepts/projects-meta-skills.md) — `setup-projects-meta` + `using-projects-meta` skill pair for the local `projects-meta-mcp` stdio server (cross-project tasks + shared Gitea wiki); local-first rule + two-step mutation pattern
|
|
||||||
- [project-discipline-design.md](concepts/project-discipline-design.md) — design for project-discipline (four cross-project rules: conventions-over-defaults, master-only, semver-bumping, ask-before-push)
|
|
||||||
- [pulling-before-work-design.md](concepts/pulling-before-work-design.md) — design for the pulling-before-work skill (mode-3 + skip-on-dirty)
|
|
||||||
- [repo-layout.md](concepts/repo-layout.md) — flat `skills/`, committed `dist/`, bash + PowerShell scripts; install model
|
|
||||||
- [skill-versioning.md](concepts/skill-versioning.md) — why infra skills carry `version: <semver>` in frontmatter and how `project-bootstrap` records them in a per-project manifest
|
|
||||||
- [skill-vs-plugin.md](concepts/skill-vs-plugin.md) — when a bare SKILL.md is enough vs when you actually need a plugin (slash commands, hooks, sub-agents, MCP servers); concrete breakdown of `superpowers`
|
|
||||||
- [wiki-realignment.md](concepts/wiki-realignment.md) — fixing `project-bootstrap` to create the Karpathy-canonical wiki layout
|
|
||||||
- [interns-design](concepts/interns-design.md) — interns-design
|
|
||||||
- [compress-dedup.md](concepts/compress-dedup.md) — `skills/compress/` deleted as a byte-identical dupe of `skills/caveman-compress/`; canonical kept for README + SECURITY + caveman-toolkit branding; better Process-step wording ported across; `version: 1.0.0` added to caveman-compress frontmatter
|
|
||||||
- [active-platform-eval-design.md](concepts/active-platform-eval-design.md) — spec for eval-driven tuning of `active-platform`: combine the two ⚪ tasks into one workstream, 20-query cross-platform eval set (≥3 per OS + near-miss negatives), `run_loop.py` autoloop **in parallel** with manual body sweep (WSL / BSD / ambiguity), version 1.0.0 → 1.1.0 (MINOR). Status: paused after design + pre-flight check, before eval-set authorship
|
|
||||||
- [interns-repo-read-design](concepts/interns-repo-read-design.md) — interns-repo-read-design
|
|
||||||
- [hermes-skills-rollout-design](concepts/hermes-skills-rollout-design.md) — hermes-skills-rollout-design
|
|
||||||
- [tdd-criteria-design](concepts/tdd-criteria-design.md) — tdd-criteria-design
|
|
||||||
- [project-bootstrap-meta-isolation.md](concepts/project-bootstrap-meta-isolation.md) — project-bootstrap@1.11.0 — Step 1 ships meta-isolation block in `.gitignore` (`!.claude/`, `!.tasks/`, `!.wiki/`, ...) so own greenfield/upgrade projects re-enable agent meta-paths against global `core.excludesFile` cutter. Marker-based append-only on existing files; smoke-tested with negative control
|
|
||||||
- [interns-grep-audit-design](concepts/interns-grep-audit-design.md) — interns-grep-audit-design
|
|
||||||
- [session-handoff-skill-design.md](concepts/session-handoff-skill-design.md) — design rationale for the `session-handoff` skill (sliding overwrite into `.tasks/NEXT_SESSION.md`, phrase whitelist + substantive-commit heuristic, optional PostToolUse hook for harness-side determinism, orient+ask default, project scope, cluster 7/7 closure)
|
|
||||||
- [using-tasks-session-break.md](concepts/using-tasks-session-break.md) — `using-tasks` v1.2.0 `session_break` marker: task-author-set boolean/string flag; after a task closes 🟢, before `tasks_claim_next`, an autonomous agent prints the verbatim SESSION BOUNDARY line and stops instead of chaining the next task. Absent → unchanged
|
|
||||||
- [delegate-task-session-break.md](concepts/delegate-task-session-break.md) — `delegate-task` v0.2.2 — authoring side of the `session_break` marker (consumer = [[using-tasks-session-break]]): pre-flight Q6 + optional template field `session_break: true | "<hint>"`; three set-it cases (domain-switch / milestone / heavy infra); not a default
|
|
||||||
- [delegate-task-review-weight.md](concepts/delegate-task-review-weight.md) — `delegate-task` v0.2.3 — Step 5 review-task now sets explicit `weight`, inherited from impl with a `needs-claude` floor (impl `needs-human`→review `needs-human`; `cheap-ok`→`needs-claude`). Fixes the reconciler skipping weightless review tasks (root cause of manual patch `c0af151`)
|
|
||||||
- [using-system-snapshot-design.md](concepts/using-system-snapshot-design.md) — `using-system-snapshot` v0.1.0 — thin read-only skill wrapping the single `mcp__projects-meta__meta_system_snapshot` call (poller + local docker + cached task summary); replaces scattered `tasklist`/`docker ps`/manual `meta_status`; core rule = no liveness claim without calling the tool this turn; three-line output; defers deep docker to [[using-vds-ops]] and precise tasks to [[using-projects-meta]]
|
|
||||||
- [using-tasks-status-archival.md](concepts/using-tasks-status-archival.md) — `using-tasks` v1.3.0 done-task archival rule (≥10 🟢 → `.tasks/archive/YYYY-MM.md`) fixes STATUS.md bloat; documents why `tasks_get_status` (single-task, by slug) / `tasks_aggregate` (cross-project cache) can't replace the orientation board-read, so the literal task instruction was not followed
|
|
||||||
- [delegate-task-negative-trigger-fp.md](concepts/delegate-task-negative-trigger-fp.md) — `delegate-task` v0.2.1 FP fix: «создать задачу себе» stem-matched the «создать задачу на агента» positive trigger; abstract "does NOT apply when doing the work yourself" carve-out loses to literal stem-match under the 1%-rule → made the negative literal + routed (→ using-tasks). Verified pos 5/5, neg 4/5 (was 0/5)
|
|
||||||
- [using-markitdown-cli-migration.md](concepts/using-markitdown-cli-migration.md) — `using-markitdown` v1.0.0→v1.0.1 (PATCH): rewrote from the Docker-based `mcp__markitdown__convert_to_markdown` MCP tool to the native `markitdown` CLI (0.1.6, on PATH); dropped the host→container `file://` mount caveat; container decommission is by image ancestor (`--filter ancestor=markitdown-mcp:latest`), not by the non-existent name `markitdown-mcp`
|
|
||||||
- [session-inbox-monitor-received-msg-fp.md](concepts/session-inbox-monitor-received-msg-fp.md) — sibling of [[delegate-task-negative-trigger-fp]]: `session-inbox-monitor` FP-fires on RU «обработай полученное письмо» (N1) because its literal+routed carve-out points at `inter-session-peer-discipline`, which **isn't installed** → no competitor, nearest inbox-skill wins. Borderline (neg 2/3, EN twin clean), body-load self-corrects. **Open** (follow-up task). New principle: *a routed negative competes only if its route target is installed*
|
|
||||||
- [task-format-design.md](concepts/task-format-design.md) — new `task-format` skill v0.1.0: public reference for the on-disk `.tasks/STATUS.md` block format the poller parses (header regex, status emoji, `**Weight:**` / `**Notify:**` / `**Requirements:**`); ships with `factory` where the internal wiki/MCP-source can't reach; distinct from [[delegate-task]] (MCP-tool delegation) and [[using-tasks]] (board mechanics); RED 3-baseline / GREEN 2-verify per writing-skills; ground truth = `status-md.ts` + `claim.ts` + `fleet-router.js`
|
|
||||||
|
|
||||||
## Packages
|
|
||||||
|
|
||||||
<!-- (none yet) -->
|
|
||||||
|
|
||||||
## Sources
|
|
||||||
|
|
||||||
<!-- (none yet) -->
|
|
||||||
- [pi-extension-headless-ritual.md](concepts/pi-extension-headless-ritual.md) — agent_end (not agent_settled) for followUp injection; mode guard (`print` not hasUI); loop-guard flag-before-send; opt-in mirrors skill
|
|
||||||
|
|
||||||
|
**Не читать. Не править.** Канон — mappa (`mcp__mappa__*`): wiki-сущности проекта, конвенции — AGENTS-сущность. Скил: `mappa-knowledge`.
|
||||||
|
|||||||
83
.wiki/log.md
83
.wiki/log.md
@@ -1,82 +1,3 @@
|
|||||||
# Wiki Log
|
# ⛔ Файловый канал закрыт
|
||||||
|
|
||||||
Append-only operation log. One entry per operation. Format:
|
**Не читать. Не править.** Канон — mappa (`mcp__mappa__*`): wiki-сущности проекта, конвенции — AGENTS-сущность. Скил: `mappa-knowledge`.
|
||||||
|
|
||||||
```
|
|
||||||
## [YYYY-MM-DD] <op> | <one-line description>
|
|
||||||
```
|
|
||||||
|
|
||||||
Operations: `init`, `ingest`, `query`, `lint`, `refactor`, `decision`.
|
|
||||||
|
|
||||||
Parseable: `grep "^## \[" .wiki/log.md | tail -20`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [2026-04-28] init | bootstrap empty wiki via project-bootstrap (old layout)
|
|
||||||
## [2026-04-28] decision | repo-layout — flat `skills/`, committed `dist/`, bash + PS scripts
|
|
||||||
## [2026-04-28] decision | build-notes — PS 5.1 Compress-Archive backslash bug; build.ps1 via .NET ZipArchive
|
|
||||||
## [2026-04-28] decision | active-platform — skill chosen over global CLAUDE.md / project memory; default Windows; wired into project-bootstrap
|
|
||||||
## [2026-04-28] refactor | wiki-realignment — fixed project-bootstrap Step 3 to create Karpathy-canonical layout
|
|
||||||
## [2026-04-28] refactor | this repo's `.wiki/` migrated to canonical layout (SUMMARY.md→index.md, source/→concepts/, added log.md/overview.md/CLAUDE.md schema, raw/README.md)
|
|
||||||
## [2026-04-28] decision | context7-setup — switched to official plugin; --api-key injected into plugin's .mcp.json; three manual MCP entries removed
|
|
||||||
## [2026-04-28] decision | setup-context7 skill — formalized the install/migrate algorithm; using-context7 gets a Prerequisites pointer; build.sh PS multi-arg bug fixed (loop instead of comma-joined -Names)
|
|
||||||
## [2026-04-28] verify | setup-context7 — Vitya ran using-context7 in a session that needed setup; Prerequisites pointer triggered setup-context7; full flow worked end-to-end. Pattern (policy + setup split) validated.
|
|
||||||
## [2026-04-28] decision | skill-vs-plugin — documented when a bare skill suffices vs when a plugin is required (slash commands, hooks, sub-agents, MCP via marketplace)
|
|
||||||
## [2026-04-28] decision | skill-versioning — added `version: 1.0.0` to 6 infra skills' frontmatter; project-bootstrap now writes .wiki/concepts/bootstrap-manifest.md per project
|
|
||||||
## [2026-04-28] refactor | wiki split — `wiki-maintainer` renamed to `using-wiki` (policy); new `setup-wiki` skill owns greenfield creation and canon migration; `project-bootstrap` Step 3 delegates
|
|
||||||
## [2026-04-28] refactor | tasks split — `task-status-wiki` renamed to `using-tasks` (policy); new `setup-tasks` skill owns greenfield + interactive migration (no auto-parsing of old flat STATUS.md); `project-bootstrap` Step 4 delegates
|
|
||||||
## [2026-04-28] refactor | this repo's `.tasks/` migrated to canonical layout — flat `## Done`/`## Backlog` replaced by emoji-status board (7 ⚪ Ready blocks); historical Done entries dropped (preserved in git log); `.bak` ignored via .gitignore
|
|
||||||
## [2026-04-28] cleanup | removed stale `~/.claude/skills/{wiki-maintainer,task-status-wiki}/` installs (replaced by `using-wiki`/`using-tasks`); 16 skills installed, no duplicates; context7 plugin (mcp__plugin_context7_context7__*) confirmed live after restart
|
|
||||||
## [2026-04-28] decision | install-portability — `install.sh`/`build.sh` patched to drop `mapfile`+`find -printf`; stock macOS (bash 3.2 + BSD find) now works; verified on git-bash (16 skills discovered, sorted, installed; build.sh produces archive)
|
|
||||||
## [2026-04-29] decision | projects-meta-skills — built `setup-projects-meta` (8-phase install of projects-meta-mcp + auth.toml + MCP registration) and `using-projects-meta` (runtime policy with local-first rule and two-step mutation); skill pair pattern applied for the 4th time (context7 / wiki / tasks / projects-meta); both built + installed; visible to the harness
|
|
||||||
## [2026-04-30] refactor | projects-meta-skills — wiki path canon corrected: `~/projects/.wiki` → `~/projects/projects-wiki/` (clone root), content at `~/projects/projects-wiki/.wiki/`. Old path caused write/read mismatch bug (fixed upstream in commit `621a69f` of `projects-meta-mcp`). Setup-projects-meta Phase 1 now detects legacy clone, Phase 4 re-clones to canon. Lesson: pull shared resources before relying on cached anchors
|
|
||||||
## [2026-04-30] decision | using-projects-meta v1.1.0 — added mandatory Step 0 freshness gate: probe `meta_status`; if cache_age > 10min or errors > 0, `node dist/sync.js`; for shared-wiki writes unconditional `git -C ~/projects/projects-wiki pull --ff-only`; 401/403 → loud failure to user. Codifies the same-session lesson — `projects-meta` is a multi-machine bus, stale cache breaks read accuracy and write atomicity
|
|
||||||
## [2026-04-28] decision | project-bootstrap@1.1.0 — added Step 5.6: detects `superpowers@claude-plugins-official` via `~/.claude/plugins/installed_plugins.json` and prints install command + upstream link if missing; chat-only, never auto-installs (slash commands aren't callable from a skill, and silent plugin install is overreach)
|
|
||||||
## [2026-04-28] doc | README.md + README.ru.md — new "Using skills in projects" / "Использование в проектах" section after install quick-start; describes project-bootstrap workflow (git, .gitignore, README, .wiki/, .tasks/, CLAUDE.md, manifest, superpowers-plugin check) and the init/upgrade modes
|
|
||||||
## [2026-04-30] refactor | project-bootstrap re-run on this repo (upgrade mode) — setup-wiki noop, setup-tasks noop, CLAUDE.md unchanged (matches template), bootstrap-manifest.md written: project-bootstrap@1.1.0 / setup-wiki@1.0.0 / setup-tasks@1.0.0
|
|
||||||
## [2026-04-30] decision | project-bootstrap@1.2.0 — CLAUDE.md template gains `check across all projects` (verbatim trigger from using-projects-meta description); installs auto-load cross-project tasks + shared-wiki access in every bootstrapped repo; no Step 5.7 dependency-check mirror — Prerequisites pointer in using-projects-meta is self-correcting; local CLAUDE.md, both READMEs, dist/.skill, projects-meta-skills concept page synced
|
|
||||||
## [2026-04-30] decision | Step 5.7 mirror of Step 5.6 (projects-meta-mcp dependency detector / `setup-projects-meta` recommendation) accepted as future work; tracked as ⚪ Ready task `[bootstrap-recommend-projects-meta]`; deferred until first observed fresh-machine miss so detector signal is informed by real failure mode; concept page `projects-meta-skills.md` updated to reflect new stance
|
|
||||||
## [2026-04-30] decision | project-bootstrap@1.3.0 — Step 5 upgrade path turned idempotent: read existing CLAUDE.md → substring-diff vs template → confirm → append-only-missing; closes silent gap where pre-1.2.0 projects never picked up new canonical triggers (`check across all projects`, `we're on Windows`); platform line preserved if user pinned a non-host one; concept page `bootstrap-claude-md-merge.md` written; README CLAUDE.md row updated to note idempotent merge
|
|
||||||
## [2026-05-01] decision | pulling-before-work — new policy skill (v1.0.0): one `git pull --ff-only` at session start + on-demand re-sync; bootstrap template gains canonical trigger; project-bootstrap 1.3.0→1.4.0
|
|
||||||
## [2026-05-01] decision | project-discipline — new policy skill (v0.1.0): four cross-project rules (conventions-over-defaults, master-only, semver-bumping, ask-before-push); bootstrap template gains canonical trigger; project-bootstrap 1.4.0→1.5.0; skill-versioning concept extended to all skills
|
|
||||||
## [2026-05-01] ingest | shared-wiki packages/claude-skills — каталог всех 20 скиллов опубликован в projects-wiki (3 commits: page + index + log on Gitea, ae2cc9a..001cdd0); группировка bootstrap / wiki+tasks / MCP / caveman / discovery+platform; cross-link с concepts/setup-using-skill-pair и packages/projects-meta-mcp
|
|
||||||
|
|
||||||
## [2026-05-05] ingest | concepts/interns-design
|
|
||||||
## [2026-05-05] decision | interns-skills-mvp — shipped `setup-interns` v0.1.0 (8-phase install: detect `.common/lib/interns-mcp/`, `pip install -e`, `.common/secrets/interns.env` write, `mcpServers.interns` registration with absolute Python interpreter + `cwd`) and `using-interns` v0.1.0 (runtime policy mirroring project-discipline Rule 4: ask-mode default, conversational grant/revoke, always-ask paths for `.env`/secrets/keys/SSH/credentials with transitive rule, cost-cap >$0.10, session-end reset; routing hints for `bulk_text_read` + `transcript_distill`); `project-bootstrap` 1.5.0→1.6.0 with canonical CLAUDE.md trigger `delegate to interns when allowed` between `follow project discipline` and `we're on Windows`, Step 5 commentary paragraph, manifest table extended with both new skills + `project-discipline` row; root `CLAUDE.md` dogfood updated; both READMEs written; descriptions verified (setup-interns 899 chars, using-interns 814 chars, both under 900 budget); all three rebuilt + installed + listed by harness with full descriptions (no H1 fallback)
|
|
||||||
## [2026-05-05] ingest | concepts/bootstrap-skill-deps-check
|
|
||||||
## [2026-05-05] decision | bootstrap-skill-deps-check — `project-bootstrap` 1.6.0→1.7.0 collapses Step 5.6 from a single-skill detector (only `superpowers` plugin) into a generic `trigger → fulfiller` table walker. Map embedded in SKILL.md (9 rows: caveman, superpowers plugin, using-wiki, using-tasks, using-projects-meta, pulling-before-work, project-discipline, using-interns, active-platform); `kind: skill` vs `kind: plugin` flag drives the install command emitted in the recommendation block. Algorithm: read project's CLAUDE.md → match each line vs map (substring + tolower, mirrors Step 5 idempotent merge) → for each canonical match check disk (`~/.claude/skills/<name>/SKILL.md` or `installed_plugins.json` key); print one chat-only block listing every missing fulfiller + install commands, or one ✅ line if all satisfied. User-custom lines silently skipped; removed canonical lines silently skipped (respects user opt-out). Hard rule "never auto-install" carries over verbatim. Subsumes the deferred `[bootstrap-recommend-projects-meta]` task (closed by absorption — generic step handles `using-projects-meta` along with everything else). MCP-server-backed skills only check the `using-X` policy skill; `setup-X` self-fires on first use via Prerequisites pointer, bootstrap doesn't duplicate.
|
|
||||||
## [2026-05-05] decision | compress-dedup — `skills/compress/` was a stripped-down byte-for-byte dupe of `skills/caveman-compress/` (scripts/ identical SHA256 across all 7 files; SKILL.md diff = `name:` + Process step 2; descriptions textually identical = arbitrary harness tie-break + double-counted listing budget). Kept `caveman-compress` canonical: it carries README.md (benchmarks table + caveman-toolkit branding) and SECURITY.md (Snyk false-positive writeup), and matches the caveman-* prefix invariant. Ported the better Process-step wording from `compress` into `caveman-compress` (`cd <directory_containing_this_SKILL.md>` instead of brittle `cd caveman-compress` which assumes cwd). Added `version: 1.0.0` to caveman-compress frontmatter (first versioned release; aligns with skill-versioning concept). Deleted: `skills/compress/`, `dist/compress.skill`, `~/.claude/skills/compress/` (manual prune — install.sh has no prune step; future `[install-ps1]` task should add `--prune` flag). Rebuilt + reinstalled `caveman-compress`. Slash-command impact: `/compress` removed; `/caveman-compress` + `/caveman:compress` (toolkit-canonical) remain. Concept page `concepts/compress-dedup.md` written (rationale + rejected alternatives: alias-stub has no harness mechanism; "keep both" wastes listing budget; "delete caveman-compress" loses README + SECURITY).
|
|
||||||
## [2026-05-05] design | active-platform-eval (paused) — combined `[active-platform-tuning]` + `[active-platform-eval]` into one workstream (eval *is* the tuning mechanism; "wait for 5 real signals" was a placeholder). Spec written at `.wiki/concepts/active-platform-eval-design.md`: 20-query trigger eval set balanced ≥3 should-trigger per OS (Win/Lin/Mac) + near-miss negatives, run in `skill-creator/scripts/run_loop.py` (5 iter, train/test split, model `claude-opus-4-7`) **in parallel** with manual body sweep (WSL clarity, BSD/macOS expansion, ambiguity policy). Workspace at `.tasks/active-platform-eval/` (eval-set.json committed, iterations gitignored). Version bump 1.0.0 → 1.1.0 planned (MINOR). Pre-flight verified: `claude` CLI at `C:\nvm4w\nodejs\claude.ps1` (Claude Code 2.1.128) + `run_loop.py` present in skill-creator install — both autoloop deps satisfied, no fallback needed. Per-task file at `.tasks/active-platform-eval.md`. Paused at user request before eval-set authorship; resume point is Q2 (write 20 queries solo vs run skill-creator HTML-review template for user edits first). Also fixed in same pause: `[install-ps1]` STATUS scope expanded to "paired install.sh + install.ps1, cross-platform parity, --prune flag" (lesson from `[compress-dedup]`).
|
|
||||||
|
|
||||||
## [2026-05-05] ingest | concepts/interns-repo-read-design
|
|
||||||
|
|
||||||
## [2026-05-06] ingest | concepts/hermes-skills-rollout-design
|
|
||||||
|
|
||||||
## [2026-05-07] ingest | concepts/tdd-criteria-design
|
|
||||||
|
|
||||||
## [2026-05-07] review | tdd-criteria v0.2.0 — 4 findings applied: trigger-loophole fix (removed session-authorship clause), composite-tasks + refactoring sections, expanded file-extension list, clarified wrapper line-count + spike-survivor fallback + foreign-schema fix; design doc synced
|
|
||||||
|
|
||||||
## [2026-05-10] decision | project-bootstrap-meta-isolation — v1.11.0 ships meta-isolation block in `.gitignore` template + Step 1 upgrade-case append; restores agent meta-paths visibility against global `core.excludesFile`; smoke-tested greenfield + negative control + idempotency
|
|
||||||
|
|
||||||
## [2026-05-22] ingest | concepts/interns-grep-audit-design
|
|
||||||
|
|
||||||
## [2026-05-25] decision | session-handoff-skill-design — design rationale for the `session-handoff` skill captured in wiki after cluster 7/7 closure; sliding overwrite of `.tasks/NEXT_SESSION.md`, phrase whitelist + substantive-commit heuristic, opt-in PostToolUse hook, orient+ask default, source: `~/projects/.workshop/.archive/2026-05-24-session-handoff-skill.md` Round 1 + Round 2
|
|
||||||
|
|
||||||
## [2026-05-25] decision | install-cross-platform — `install.{ps1,sh}` paired-script parity contract documented; `--prune` / `-Prune` flag rationale (combined-with-install, global-scan ignores names filter, default-off, print-and-delete no prompt); shipped in commit `6cf0e98` with `[skip-tdd: wrapper]` carve-out + smoke-test evidence; closes 2/3 of `[install-ps1]` acceptance (the doc + flag), `dist/`-prune analogue deferred to `build` scripts
|
|
||||||
|
|
||||||
## [2026-05-25] decision | install-cross-platform extended to build scripts — `build.{ps1,sh}` get the symmetric `--prune` / `-Prune` flag (removes `dist/<name>.skill` where `<name>` is not in `skills/`). Bash delegation to `powershell.exe -File build.ps1` does NOT forward the flag — bash runs prune itself against the shared `dist/`. Both paths smoke-tested with fake stale .skill files against real dist/. Closes `[install-ps1-build-prune-followup]`.
|
|
||||||
|
|
||||||
## [2026-06-09] decision | delegate-task-negative-trigger-fp — `delegate-task` 0.2.0→0.2.1 (PATCH): fixed 5/5-consistent false-positive on «создать задачу себе». Root cause: self-task phrase shares stem «создать задачу» with the «создать задачу на агента» positive trigger; the abstract "Does NOT apply when doing the work yourself" carve-out can't beat a literal stem-match under the 1%-rule. Fix: made the negative literal + routed («создать задачу себе» / «task for myself» / «поставить себе задачу» → using-tasks) in description + body disambiguator («на агента»/«агенту» = delegate; «себе» = own board). Re-verified via fresh-context subagent trigger run: positives 5/5 (no regression), negative 4/5 → using-tasks (was 0/5); the 1 residual miss was an eval-harness artifact (forced skill-name-before-reasoning), not description ambiguity. Concept page written; reusable principle = put the exact colliding negative phrase with an explicit →sibling route, literal beats abstract.
|
|
||||||
## [2026-06-09] decision | delegate-task-session-break — `delegate-task` 0.2.1→0.2.2 (PATCH): authoring side of the `session_break` marker (consumer = using-tasks v1.2.0). Added pre-flight Q6 (after notify): "Session-break после этой задачи? (domain-switch / milestone / heavy infra)"; if yes → set optional template field `session_break: true | "<hint>"` (trailer, next to weight/notify/allow_upgrade; same lowercase frontmatter key using-tasks reads). Usage guidance lists three set-it cases; What-NOT-to-do bullet warns against setting it routinely (it's a real-boundary marker, not a default). Wiki concept page concepts/delegate-task-session-break.md + index. Pairs with using-tasks-session-break.
|
|
||||||
## [2026-06-09] decision | using-system-snapshot — new skill v0.1.0: thin read-only wrapper over the single `mcp__projects-meta__meta_system_snapshot` call (poller status + local docker containers + cached cross-project task summary). Replaces the scatter of `tasklist` + `docker ps` + manual `meta_status`. Core rule: no claim about poller / local-docker / task-load state without calling the tool in the current turn (memory + stale earlier snapshot ≠ evidence). Output = three lines, one per section (docker lists only problem containers; tasks gives Σ active/blocked + busiest 2–3). Liveness split documented: poller+docker live, tasks from cache (defer precise work to using-projects-meta Step 0). Scope boundaries: deep single-container diagnosis → using-vds-ops / `docker logs`; docker section is LOCAL, not the VDS. Read-only, no per-session grant (mirrors using-vds-ops). Output shape verified by a live call 2026-06-09. Concept page concepts/using-system-snapshot-design.md + index. TDD N/A (markdown policy artifact); behavioral smoke-test = paired skill-using-system-snapshot-review task.
|
|
||||||
## [2026-06-09] review | using-system-snapshot v0.1.0 — VERDICT PASS on all 3 acceptance criteria (skill-using-system-snapshot-review). Tool contract verified by a live `meta_system_snapshot` call (output matches the documented `poller`/`docker`/`tasks` shape exactly). Behavioral trigger smoke = 9 fresh-context subagents over a simulated registry (real descriptions + using-vds-ops/using-projects-meta/using-tasks competitors, no expected-answer hint): 4/4 positives → using-system-snapshot; VDS-logs → using-vds-ops; mutate/full-board → using-projects-meta; `docker-compose.yml` edit → none (no FP on "docker" keyword). No-claim-without-snapshot rule explicit in 4 places; three-line output format confirmed achievable against the live payload. 3 informational findings (none blocking): (1) cross-project task-COUNT phrasings overlap with using-projects-meta — by-design, snapshot defers precise per-task work; (2) LOCAL-container deep diagnosis is unowned — vds-ops incident triggers grab local containers its VDS-only tools can't reach (vds-ops scoping, not this skill); (3) deployment scaffold missing — skill committed but not installed to `~/.claude/skills/`, not in `hermes/mapping.yaml`, no -install/-hermes-mapping/-test-trigger baseline tasks; recommended follow-ups (hermes mode could be `auto`, read-only skill). Review outcome appended to concepts/using-system-snapshot-design.md.
|
|
||||||
## [2026-06-09] decision | using-tasks-status-archival — `using-tasks` 1.2.0→1.3.0 (MINOR): added done-task archival rule to fix STATUS.md bloat ("huge STATUS.md" complaint). When ≥10 🟢 done blocks pile up — checked at session start (step 7) and after close (Task completion step 7) — move them verbatim to `.tasks/archive/YYYY-MM.md` (append, one file per month, one-time header), leaving only 🔴/🟡/⚪/🔵 on the board; committed on its own. Did NOT follow the task's literal instruction to replace `Read STATUS.md` with `tasks_get_status` for orientation: that tool returns a single task's live status by known slug (`{status, found}`) and cannot enumerate the board, and `tasks_aggregate` is cross-project + cache-based + doesn't index ready/done (its docs say read STATUS.md directly for the current project). So orientation stays a local board-read (kept cheap by archival); skill now warns against both tools for board enumeration and points `tasks_get_status` at its real single-task use. Core goal (kill the bloat) met by archival alone. Concept page concepts/using-tasks-status-archival.md + index. TDD N/A (markdown policy). Deviation flagged for paired review task using-tasks-status-read-perf-review.
|
|
||||||
## [2026-06-09] decision | using-tasks-session-break — `using-tasks` 1.1.0→1.2.0 (MINOR): added the `session_break` marker. Task author sets `session_break: true | "<hint>"` in task frontmatter (mirrored as `**Session break:**` on the local board); after the task closes 🟢, before `tasks_claim_next`, an autonomous agent prints the verbatim line `🔚 SESSION BOUNDARY — [slug] закрыта. Рекомендую завершить текущую сессию. Следующий трек: [value | "см. STATUS.md"]` and stops instead of chaining the next task. Absent → behaviour unchanged. Enforced in Task completion step 6 + Rules bullet + format docs. Marker not heuristic: the stop-point is an authoring choice, not a runner guess.
|
|
||||||
## [2026-06-09] review | using-tasks-status-archival v1.3.0 — VERDICT PASS 3/3 (using-tasks-status-read-perf-review). Criterion «ориентация через `tasks_get_status`, не Read» is satisfied by a **validated deviation**, not a literal swap: re-verified against the live tool schema that `tasks_get_status(target_project, slug)→{status, found}` takes a required slug and returns ONE task — it cannot enumerate the board, so it cannot drive orientation; the implementer correctly rejected the impossible instruction and fixed the real problem (bloat→archival). No regression: orientation still reads local STATUS.md (Session start §2) and the «what's next» flow still reads the board — change is purely additive. Archival rule clear & complete (≥10 threshold, two trigger points, monthly append-only archive, verbatim blocks, dedicated commit, cross-referenced). One informational non-blocking note: this repo's own STATUS.md (>10 🟢) would itself trip the rule — dogfooding tracked separately as tasks-board-cleanup-2026-05. No follow-up tasks. Verdict appended to concepts/using-tasks-status-archival.md.
|
|
||||||
## [2026-06-09] decision | delegate-task-review-weight — `delegate-task` 0.2.2→0.2.3 (PATCH): Step 5 (paired `<slug>-review` task) now sets an explicit `weight`, inherited from the impl-task with a `needs-claude` floor (impl `needs-human`→review `needs-human`; `needs-claude`→`needs-claude`; `cheap-ok`→`needs-claude`). Root cause of commit `c0af151` ("add Weight: needs-claude to 4 review tasks — reconciler was skipping them"): the authoring skill omitted `weight` on review tasks, making them invisible to fleet routing. Floor (not pure inheritance) chosen to stay internally consistent with the skill's own "What NOT to do" bullet that forbids `cheap-ok` for review tasks — a `cheap-ok` impl would otherwise propagate a forbidden `cheap-ok` review. Added a What-NOT-to-do bullet against weightless review tasks. Concept page concepts/delegate-task-review-weight.md + index. TDD N/A (markdown policy artifact).
|
|
||||||
## [2026-06-11] decision | task-format — new skill v0.1.0: public reference for the `.tasks/STATUS.md` task-block format the autonomous poller parses. Motivation: the field rules (`**Weight:**` capability/cost tier, `**Notify:** <owner>/<repo>` inbox target, header regex, status emoji) lived only in internal sources (`projects-meta-mcp/src/lib/status-md.ts` parser + `status-md-writer.ts` + `.common/.wiki/concepts/agents-task-runner-ops.md`); skills ship with `factory` to external users, the wiki/MCP-source don't. Scope kept distinct from delegate-task (creates tasks for others via `tasks_create`, the tool emits the format) and using-tasks (board claim/close mechanics) — task-format is the byte-level field reference for hand-edited blocks. Ground truth verified against source: header `/^##\s+(\S+)\s+\[([^\]]+)\]\s+—\s+(.+)$/u`; Weight ∈ {cheap-ok, needs-claude, needs-human}; claim gate excludes only `needs-human` (`claim.ts`), but a *missing* Weight finds no backend tier (`fleet-router.js` resolveBackend) → poller parks to 🔵 blocked, so Weight is operatively required for pickup. TDD per writing-skills: RED = 3 baseline subagents w/o skill (2/3 used `###`/bullet headers the parser can't recognize, 2/3 omitted Weight inventing `risk`/`tier`/`claimable-by`, 2/3 put notify in prose, 1/3 used 🟢 for ready); GREEN = 2 fresh subagents w/ skill, both parser-valid incl. correct `needs-human` for the critical-infra scenario; REFACTOR = no new loopholes. Reference skill ~900 words (loads only when authoring a task block). Concept page concepts/task-format-design.md + index. Not yet installed to `~/.claude/skills/` or added to hermes mapping — deferred follow-up (mirrors using-system-snapshot deployment-scaffold note).
|
|
||||||
## [2026-06-09] decision | using-markitdown-cli-migration — `using-markitdown` 1.0.0→1.0.1 (PATCH): rewrote the skill from the Docker-based `mcp__markitdown__convert_to_markdown` MCP tool to the native `markitdown` CLI (v0.1.6, on PATH). Tool block now `markitdown <path|url>` → stdout (or `-o file`); removed the whole "Docker-mount caveat (READ FIRST)" section (host→container `file://` translation + `[Errno 2] /c:/Users/...` symptom are gone — CLI sees the full host FS). Updated the ingest pattern (use `-o` straight into `.wiki/raw/`), the gotchas table (`command not found` → check `markitdown --version`, install `pip install markitdown[all]`; dropped the MCP "tool not available / ToolSearch" row), and the contrast-table header (CLI, not MCP). Description frontmatter (the WHEN-to-use triggers) left unchanged. Container decommission: the task's literal `docker stop/rm markitdown-mcp` had no target — no container is named that; the MCP spawns anonymously-named containers from `markitdown-mcp:latest` per session (3 had piled up). Removed all by image ancestor (`docker rm -f $(docker ps -aq --filter "ancestor=markitdown-mcp:latest")`), verified none remain. Left the `mcpServers.markitdown` entry in `~/.claude.json` untouched (out of scope; a container will respawn next session until it's deregistered — flagged as a follow-up). Concept page concepts/using-markitdown-cli-migration.md + index. TDD N/A (markdown skill).
|
|
||||||
## [2026-06-17] decision | session-inbox-monitor-received-msg-fp — finding from `session-inbox-monitor-test-trigger` (VERDICT PASS, clean session, 7 unprimed clean-context subagents: pos 4/4 incl. CLAUDE.md-line P4, neg 2/3). The 1 FP: RU «обработай полученное письмо из инбокса» (N1) routed to `session-inbox-monitor`; the EN twin (N3) and the multi-machine-backend negative (N2) routed to `none` cleanly. Root cause = a new dimension on top of [[delegate-task-negative-trigger-fp]]: the carve-out is already literal+routed (`NOT for handling a received message → inter-session-peer-discipline`), but the route target `inter-session-peer-discipline` is **not installed** → no real competitor, so the nearest in-domain skill (session-inbox-monitor) wins by default; non-deterministic, self-corrects on body-load (cost = one wasted skill-load, not a wrong action; isomorphic to [[using-tasks-session-break]] session_break). New page concepts/session-inbox-monitor-received-msg-fp.md + bidirectional link from concepts/delegate-task-negative-trigger-fp.md + index. New reusable principle: a routed negative competes only if its route target is installed. Status OPEN — follow-up task session-inbox-monitor-received-msg-fp (options a: harden description / b: install sibling / c: accept informational). Not a memory entry by owner direction — knowledge belongs in the project wiki.
|
|
||||||
## [2026-06-17] decision | session-inbox-monitor-received-msg-fp RESOLVED via option (b) — installed `inter-session-peer-discipline` (existed in sources since 2026-06-16, was not installed → exact root cause confirmed). install.ps1 -Names, byte-identical parity. FP-twin verified clean: fresh clean-context subagent on the N1 phrase now routes to inter-session-peer-discipline (IN_REGISTRY: yes), not session-inbox-monitor — carve-out now has a real competitor. session-inbox-monitor description untouched (option (a) rejected as whack-a-mole; (c) as latent hole). Governance: peer workshop proposed (b) as a "ruling"; per the freshly-installed [[inter-session-peer-discipline]] (peer = proposal not authority, scope needs human ratification) it was surfaced as a recommendation and ratified by the user — live dogfood of the skill's own purpose. concepts/session-inbox-monitor-received-msg-fp.md Status section updated open→resolved. Tail: inter-session-peer-discipline now installed but not in hermes/mapping.yaml — possible red build, flagged as separate follow-up.
|
|
||||||
## [2026-08-12] ingest | pi-extension-headless-ritual — agent_end/mode-guard/loop-guard lessons from session-close-ritual build
|
|
||||||
## [2026-08-13] refactor | context7-setup — concept updated to CLI-first canonical (setup-context7 v2.0.0 migration, 2026-08-12): ctx7 CLI + key in ~/.config/projects-secrets/ctx7.env, plugin + manual MCP removed; plugin era demoted to rollback reference; whoami!=key-check gotcha recorded; index entry refreshed
|
|
||||||
|
|||||||
@@ -1,29 +1,3 @@
|
|||||||
---
|
# ⛔ Файловый канал закрыт
|
||||||
title: claude-skills overview
|
|
||||||
type: overview
|
|
||||||
updated: 2026-04-28
|
|
||||||
---
|
|
||||||
|
|
||||||
# claude-skills — overview
|
**Не читать. Не править.** Канон — mappa (`mcp__mappa__*`): wiki-сущности проекта, конвенции — AGENTS-сущность. Скил: `mappa-knowledge`.
|
||||||
|
|
||||||
Joint workshop where Vitya and Claude develop, test, and store Claude skills. Both editable sources (`skills/<name>/`) and built archives (`dist/<name>.skill`) live here, so a fresh machine can clone the repo and install every personal skill in one command.
|
|
||||||
|
|
||||||
## Components
|
|
||||||
|
|
||||||
- **`skills/`** — editable skill sources, one folder per skill (each with `SKILL.md` + optional `assets/`).
|
|
||||||
- **`dist/`** — built `.skill` archives, committed so installs don't need a build toolchain on the target.
|
|
||||||
- **`scripts/`** — `build.sh` / `build.ps1` (zip sources → archive), `install.sh` (copy sources → `~/.claude/skills/`).
|
|
||||||
- **`.wiki/`** — Karpathy LLM Wiki for design decisions and gotchas. See [CLAUDE.md](CLAUDE.md) for schema.
|
|
||||||
- **`.tasks/`** — task board (`STATUS.md`).
|
|
||||||
- **`CLAUDE.md`** — repo-level agent instructions (skill triggers).
|
|
||||||
|
|
||||||
## Where to look
|
|
||||||
|
|
||||||
- New here? → [concepts/repo-layout.md](concepts/repo-layout.md), then `README.md`.
|
|
||||||
- Working on a skill? → edit `skills/<name>/`, then `bash scripts/install.sh <name>` (or `pwsh scripts/build.ps1 <name>` to refresh the archive).
|
|
||||||
- Tracking work? → [.tasks/STATUS.md](../.tasks/STATUS.md).
|
|
||||||
- Made a non-trivial decision? → add a `concepts/<topic>.md` page, link from [index.md](index.md), append a line to [log.md](log.md).
|
|
||||||
|
|
||||||
## Cross-references
|
|
||||||
|
|
||||||
This page intentionally stays short. The substantive material lives in `concepts/` (decisions, gotchas) and the [index](index.md) catalog.
|
|
||||||
|
|||||||
19
AGENTS.md
19
AGENTS.md
@@ -8,8 +8,27 @@ check across all projects
|
|||||||
pull remote before work
|
pull remote before work
|
||||||
session handoff: read on start, write on end
|
session handoff: read on start, write on end
|
||||||
inbox monitor: raise on start
|
inbox monitor: raise on start
|
||||||
|
session sync: write to mappa
|
||||||
follow project discipline
|
follow project discipline
|
||||||
follow tdd-criteria
|
follow tdd-criteria
|
||||||
delegate to interns when allowed
|
delegate to interns when allowed
|
||||||
recommend, don't menu
|
recommend, don't menu
|
||||||
we're on Windows
|
we're on Windows
|
||||||
|
mappa sync: run on start
|
||||||
|
|
||||||
|
<!-- mappa:canon-block (auto; do not edit) -->
|
||||||
|
## Mappa canon
|
||||||
|
**Gates (canon/gates — shared):** краткая суть; полный текст — `wiki_get(slug='canon/gates', full=true)`
|
||||||
|
- Г1. Знание и артефакты → mappa, не файлы — durable-знание и артефакты проекта живут в mappa; файловые каналы (`.brainstorm/`, `.tasks/`, `.wiki/`) и «сохранить рядом с проектом» закрыты.
|
||||||
|
- Г2. Контракт каналов — письмо (inbox) — носитель вердиктов/указаний/находок, полным телом; комментарии на тасках — короткий след. Адресация `about`/`to`/`thread` (XOR); lifecycle `ack`/`resolve`/`cancel`.
|
||||||
|
- Г3. Поиск до угадывания — не угадывать slug/роут: сначала `search`/`wiki_search`; `wiki_get` без project = shared; общая память — `search(mode='recall')`.
|
||||||
|
- Г4. Адресация и слаги — рефы полными именами (`[[task:N]]`/`[[wiki:slug]]`); слаги kebab-case, латиница; номера `task:N` выдаёт сервер.
|
||||||
|
- Г5. .mappa-гейт — папка участвует в mappa-операциях только с маркером `.mappa`; нет маркера → сказать человеку, мутации — отказ.
|
||||||
|
- Г6. Секреты — в mappa не пишутся (422); только `secret:<path>`-рефы, значения мимо.
|
||||||
|
- Г7. Degraded-режим — mappa недоступна: читать кэш `.mappa/` (canon/methodology/runbooks), мутации → `.mappa/pending/`; нет кэша → стоп, не импровизировать.
|
||||||
|
- Г8. Перед работой с вики/каноном — первым действием прочитать канон-блок AGENTS.md проекта.
|
||||||
|
- Г9. Живое состояние до заявления — статус заявлять только по свежему чтению mappa, не по памяти/кэшу/ответу create.
|
||||||
|
**Entity → runbook (runbooks/index — shared):** task → [[runbooks/tasks]] · wiki → [[runbooks/wiki]] · inbox → [[runbooks/inbox]] · **thread** → [[runbooks/threads]] · session → [[runbooks/session]] · search → [[runbooks/search]] · issue → [[runbooks/issue]] · **intent** → [[runbooks/intent]] · requirements → [[runbooks/requirements]] · plan → [[runbooks/plan]] · comment → [[runbooks/comment]] · tag → [[runbooks/tag]] · attachment → [[runbooks/attachment]] · release → [[runbooks/release]] · brainstorm → [[runbooks/brainstorm]] · agent → [[runbooks/agent-operator]] · repo → [[runbooks/repo-commit]] · project → [[runbooks/project]] · skill → [[runbooks/skill]] · entity-слой → [[runbooks/entity]] · sched → [[runbooks/sched-telemetry]]
|
||||||
|
**Methodology:** `methodology/kzntsv`
|
||||||
|
**Canon version:** 4
|
||||||
|
<!-- /mappa:canon-block -->
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -25,8 +25,8 @@ A shared workspace where Claude and I author, debug, and ship skills together:
|
|||||||
git clone <repo> skills
|
git clone <repo> skills
|
||||||
cd skills
|
cd skills
|
||||||
bash scripts/install.sh # copies every skills/* into ~/.claude/skills/
|
bash scripts/install.sh # copies every skills/* into ~/.claude/skills/
|
||||||
# or only specific ones:
|
# or only specific ones (mappa-* skills install from the `mappa` repo — see mappa-bootstrap):
|
||||||
bash scripts/install.sh using-wiki caveman
|
bash scripts/install.sh caveman tdd-criteria
|
||||||
```
|
```
|
||||||
|
|
||||||
**Linux / macOS (bash):**
|
**Linux / macOS (bash):**
|
||||||
@@ -35,8 +35,8 @@ bash scripts/install.sh using-wiki caveman
|
|||||||
git clone <repo> skills
|
git clone <repo> skills
|
||||||
cd skills
|
cd skills
|
||||||
bash scripts/install.sh # copies every skills/* into ~/.claude/skills/
|
bash scripts/install.sh # copies every skills/* into ~/.claude/skills/
|
||||||
# or only specific ones:
|
# or only specific ones (mappa-* skills install from the `mappa` repo — see mappa-bootstrap):
|
||||||
bash scripts/install.sh using-wiki caveman
|
bash scripts/install.sh caveman tdd-criteria
|
||||||
```
|
```
|
||||||
|
|
||||||
The install target can be overridden with `CLAUDE_SKILLS_DIR=/path bash scripts/install.sh`.
|
The install target can be overridden with `CLAUDE_SKILLS_DIR=/path bash scripts/install.sh`.
|
||||||
@@ -52,10 +52,9 @@ project's folder and it will, in one pass:
|
|||||||
|
|
||||||
- initialize `git` (if missing) and write a sane `.gitignore`
|
- initialize `git` (if missing) and write a sane `.gitignore`
|
||||||
- create a starter `README.md`
|
- create a starter `README.md`
|
||||||
- lay out `.wiki/` per the [Karpathy LLM Wiki pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) (delegated to [`setup-wiki`](skills/setup-wiki/))
|
- register the project meta in **mappa** (wiki/task-сущности проекта; file-based `.wiki/`/`.tasks/` closed 2026-08-25)
|
||||||
- lay out `.tasks/` with the canonical task board (delegated to [`setup-tasks`](skills/setup-tasks/))
|
|
||||||
- write `AGENTS.md` (canon) with skill triggers (`use project wiki`, `use task management system`, `check across all projects`, `we're on Windows`) plus a `CLAUDE.md` legacy pointer
|
- write `AGENTS.md` (canon) with skill triggers (`use project wiki`, `use task management system`, `check across all projects`, `we're on Windows`) plus a `CLAUDE.md` legacy pointer
|
||||||
- record the skill versions used in `.wiki/concepts/bootstrap-manifest.md` so cross-project layout drift stays debuggable
|
- record the skill versions used in a mappa wiki entity (`concepts/bootstrap-manifest`) so cross-project layout drift stays debuggable
|
||||||
|
|
||||||
Two modes, picked automatically: **init** for an empty folder, **upgrade**
|
Two modes, picked automatically: **init** for an empty folder, **upgrade**
|
||||||
for an existing project (the skill only fills the gaps and never overwrites
|
for an existing project (the skill only fills the gaps and never overwrites
|
||||||
@@ -119,9 +118,12 @@ an explicit `adapted-from` marker in its frontmatter.
|
|||||||
| `loop-me` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — workflow-spec design gate |
|
| `loop-me` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — workflow-spec design gate |
|
||||||
| `review-kit-pi-method` | `author: ours` — pi-native spawn for clean-context review subagents |
|
| `review-kit-pi-method` | `author: ours` — pi-native spawn for clean-context review subagents |
|
||||||
| `command-index` | `author: ours` — just/Makefile command-index convention (standard targets, auto-doc; idea 3/18) |
|
| `command-index` | `author: ours` — just/Makefile command-index convention (standard targets, auto-doc; idea 3/18) |
|
||||||
|
| `code-search` | `author: ours` — rg-first code search (measured 15 min → 0s; routing: rg / git grep / interns repo_read / grep_audit) |
|
||||||
| `code-review` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — two-axis + Fowler baseline; output: caveman-review format |
|
| `code-review` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — two-axis + Fowler baseline; output: caveman-review format |
|
||||||
| `writing-skills` | `adapted-from: obra/superpowers @ 6.2.0` (MIT) — TDD-for-skills core + ideya 8 self-skill-authoring |
|
| `writing-skills` | `adapted-from: obra/superpowers @ 6.2.0` (MIT) — TDD-for-skills core + ideya 8 self-skill-authoring |
|
||||||
| `web-search` | `author: ours` — search_web tool (pi-extension) + policy: when to search, «без поиска» session-off |
|
| `web-search` | `author: ours` — search_web tool (pi-extension) + policy: when to search, «без поиска» session-off |
|
||||||
|
| `ops-browser` | `author: ours` — свой **скрытый** браузер агента: отдельный профиль + CDP (`eval`/`fetch` из страницы/скриншоты), `handoff` человеку для пароля/капчи; свой замок `ops.lock` |
|
||||||
|
| `browser-operator` | `author: ours` — браузер ОПЕРАТОРА (его Chrome/логины): канал по харнессу (Hermes `browser_exec` / pi тул `browser` / CC `chrome-devtools`), аренда «один водитель за раз», границы «человек vs агент», рецепты тяжёлых страниц. Закрывает провал базового прогона 2026-09-11 («куки из Chrome + curl + ввод пароля» мимо канала); анонимные прогоны — `browser-cdp` |
|
||||||
| `review-subagent` | `author: ours` — review_subagent tool (pi-extension): clean-context review by your own model, optional `model` override |
|
| `review-subagent` | `author: ours` — review_subagent tool (pi-extension): clean-context review by your own model, optional `model` override |
|
||||||
| `report-mappa-issue` | `author: ours` — TEMPORARY stopgap: mappa deviation reporting (mail to `mappa` + `.workshop`) while the service is unstable; retire when stabilized |
|
| `report-mappa-issue` | `author: ours` — TEMPORARY stopgap: mappa deviation reporting (mail to `mappa` + `.workshop`) while the service is unstable; retire when stabilized |
|
||||||
| all other `skills/*` | `author: ours` |
|
| all other `skills/*` | `author: ours` |
|
||||||
@@ -141,7 +143,7 @@ skills/
|
|||||||
│ ├── mapping.yaml ← per-skill Hermes-rollout config
|
│ ├── mapping.yaml ← per-skill Hermes-rollout config
|
||||||
│ └── skills/ ← `mode: manual` overrides (Hermes-flavour rewrites)
|
│ └── skills/ ← `mode: manual` overrides (Hermes-flavour rewrites)
|
||||||
├── dist-hermes/ ← pre-converted Hermes-flavour tree (committed)
|
├── dist-hermes/ ← pre-converted Hermes-flavour tree (committed)
|
||||||
│ ├── <category>/<name>/ ← e.g. software-development/pulling-before-work/
|
│ ├── <category>/<name>/ ← e.g. software-development/diagnosing-bugs/
|
||||||
│ └── SKIPPED.md ← skip + pending log (auto-generated)
|
│ └── SKIPPED.md ← skip + pending log (auto-generated)
|
||||||
├── scripts/
|
├── scripts/
|
||||||
│ ├── build.sh / build.ps1
|
│ ├── build.sh / build.ps1
|
||||||
|
|||||||
12
README.ru.md
12
README.ru.md
@@ -21,8 +21,8 @@
|
|||||||
git clone <repo> claude-skills
|
git clone <repo> claude-skills
|
||||||
cd claude-skills
|
cd claude-skills
|
||||||
bash scripts/install.sh # копирует все skills/* в ~/.claude/skills/
|
bash scripts/install.sh # копирует все skills/* в ~/.claude/skills/
|
||||||
# или конкретные:
|
# или конкретные (mappa-* скилы ставятся из репо `mappa` — см. mappa-bootstrap):
|
||||||
bash scripts/install.sh using-wiki caveman
|
bash scripts/install.sh caveman tdd-criteria
|
||||||
```
|
```
|
||||||
|
|
||||||
Цель установки можно переопределить переменной `CLAUDE_SKILLS_DIR=/path bash scripts/install.sh`.
|
Цель установки можно переопределить переменной `CLAUDE_SKILLS_DIR=/path bash scripts/install.sh`.
|
||||||
@@ -36,10 +36,9 @@ bash scripts/install.sh using-wiki caveman
|
|||||||
|
|
||||||
- инициализирует `git` (если ещё нет) и положит вменяемый `.gitignore`
|
- инициализирует `git` (если ещё нет) и положит вменяемый `.gitignore`
|
||||||
- создаст стартовый `README.md`
|
- создаст стартовый `README.md`
|
||||||
- развернёт `.wiki/` по [паттерну Karpathy LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) (делегируется в [`setup-wiki`](skills/setup-wiki/))
|
- зарегистрирует мету проекта в **mappa** (wiki/task-сущности; файловые `.wiki/`/`.tasks/` закрыты 2026-08-25)
|
||||||
- развернёт `.tasks/` с канонической доской задач (делегируется в [`setup-tasks`](skills/setup-tasks/))
|
|
||||||
- запишет `AGENTS.md` (канон) со скилл-триггерами + `CLAUDE.md`-указатель (`use project wiki`, `use task management system`, `check across all projects`, `we're on Windows`)
|
- запишет `AGENTS.md` (канон) со скилл-триггерами + `CLAUDE.md`-указатель (`use project wiki`, `use task management system`, `check across all projects`, `we're on Windows`)
|
||||||
- зафиксирует версии использованных скиллов в `.wiki/concepts/bootstrap-manifest.md`, чтобы дрифт раскладки между проектами оставался отлаживаемым
|
- зафиксирует версии использованных скиллов в mappa wiki-сущности `concepts/bootstrap-manifest`, чтобы дрифт раскладки оставался отлаживаемым
|
||||||
|
|
||||||
Два режима, выбирается автоматически: **init** для пустой папки и **upgrade**
|
Два режима, выбирается автоматически: **init** для пустой папки и **upgrade**
|
||||||
для существующего проекта (скилл только дозаполняет пробелы и ничего не
|
для существующего проекта (скилл только дозаполняет пробелы и ничего не
|
||||||
@@ -89,8 +88,11 @@ bash scripts/build.sh caveman # один
|
|||||||
| `loop-me` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — дизайн-гейт workflow-спец |
|
| `loop-me` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — дизайн-гейт workflow-спец |
|
||||||
| `review-kit-pi-method` | `author: ours` — pi-спавн чистых review-субагентов |
|
| `review-kit-pi-method` | `author: ours` — pi-спавн чистых review-субагентов |
|
||||||
| `command-index` | `author: ours` — конвенция just/Makefile command-index (стандартные таргеты, авто-док; идея 3/18) |
|
| `command-index` | `author: ours` — конвенция just/Makefile command-index (стандартные таргеты, авто-док; идея 3/18) |
|
||||||
|
| `code-search` | `author: ours` — rg-first код-поиск (замер: 15 мин → 0 сек; роутинг: rg / git grep / interns repo_read / grep_audit) |
|
||||||
| `code-review` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — двухосевость + Fowler-база; формат вывода: caveman-review |
|
| `code-review` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — двухосевость + Fowler-база; формат вывода: caveman-review |
|
||||||
| `writing-skills` | `adapted-from: obra/superpowers @ 6.2.0` (MIT) — TDD-for-skills ядро + идея 8 self-skill-authoring |
|
| `writing-skills` | `adapted-from: obra/superpowers @ 6.2.0` (MIT) — TDD-for-skills ядро + идея 8 self-skill-authoring |
|
||||||
|
| `ops-browser` | `author: ours` — свой скрытый браузер агента (профиль + CDP + `handoff` человеку, замок `ops.lock`) |
|
||||||
|
| `browser-operator` | `author: ours` — браузер ОПЕРАТОРА (его Chrome/логины): канал по харнессу (Hermes `browser_exec` / pi тул `browser` / CC `chrome-devtools`), аренда «один водитель за раз», границы «человек vs агент»; анонимные прогоны — `browser-cdp` |
|
||||||
| остальные `skills/*` | `author: ours` |
|
| остальные `skills/*` | `author: ours` |
|
||||||
|
|
||||||
Политика адаптации: клон переписывается под наши конвенции (доски `.tasks/`,
|
Политика адаптации: клон переписывается под наши конвенции (доски `.tasks/`,
|
||||||
|
|||||||
@@ -17,16 +17,11 @@ Do not edit by hand — edit the mapping and re-run the build.
|
|||||||
|
|
||||||
## Pending (deferred to follow-up tasks)
|
## Pending (deferred to follow-up tasks)
|
||||||
|
|
||||||
- **delegate-task** — Calls mcp__projects-meta__tasks_create to create tasks in other projects/agents (Gitea commit, cross-project side-effect). Behavioral audit via delegate-task-test-trigger required before promotion to auto. → intended: `mode: auto, category: mcp`
|
|
||||||
- **meta-host-routing** — Resolves WHERE a project's meta lives before tasks_create / knowledge_ingest / brainstorm-promotion (meta-out-of-repo). Touches projects-meta MCP (tasks_create / knowledge_ingest / meta_status) and routes writes across repos. Review PASS (meta-host-routing-review) but the -install baseline is still open and a tool-side audit (cross-repo MCP writes) is required before auto. Mapping executes task meta-host-routing-hermes-mapping. → intended: `mode: auto, category: meta`
|
- **meta-host-routing** — Resolves WHERE a project's meta lives before tasks_create / knowledge_ingest / brainstorm-promotion (meta-out-of-repo). Touches projects-meta MCP (tasks_create / knowledge_ingest / meta_status) and routes writes across repos. Review PASS (meta-host-routing-review) but the -install baseline is still open and a tool-side audit (cross-repo MCP writes) is required before auto. Mapping executes task meta-host-routing-hermes-mapping. → intended: `mode: auto, category: meta`
|
||||||
- **private-dev-public-publish** — Steps shell out to git / gh / Gitea-API, handle tokens, force-push, and repo deletion/privacy toggles — not a purely stylistic skill. Behavioral audit via private-dev-public-publish-test-trigger required before promotion to auto. → intended: `mode: auto, category: software-development`
|
- **private-dev-public-publish** — Steps shell out to git / gh / Gitea-API, handle tokens, force-push, and repo deletion/privacy toggles — not a purely stylistic skill. Behavioral audit via private-dev-public-publish-test-trigger required before promotion to auto. → intended: `mode: auto, category: software-development`
|
||||||
- **ralph-loop-execution** — Behavioral oracle-loop skill (Verifier / Attempts / Max-Attempts retry loop). NB: source SKILL.md currently lacks YAML frontmatter (no name/description) — cannot auto-convert cleanly until that is fixed. Mapped pending as a placeholder; needs frontmatter + a behavioral audit before any mode decision.
|
- **ralph-loop-execution** — Behavioral oracle-loop skill (Verifier / Attempts / Max-Attempts retry loop). NB: source SKILL.md currently lacks YAML frontmatter (no name/description) — cannot auto-convert cleanly until that is fixed. Mapped pending as a placeholder; needs frontmatter + a behavioral audit before any mode decision.
|
||||||
- **session-handoff** — Writes .tasks/NEXT_SESSION.md (project-scope, sliding overwrite) and reads it on session start. Bidirectional file-system side-effect, opt-in via CLAUDE.md trigger-line. Behavioral audit via session-handoff-test-trigger required before promotion to auto. → intended: `mode: auto, category: productivity`
|
|
||||||
- **session-inbox-monitor** — Paired SessionStart hook registers itself in ~/.claude/settings.json and sweeps orphaned monitor OS processes (Get-CimInstance | Stop-Process by sentinel+inbox-path); the skill then raises an in-session Monitor on .claude-inbox/. Primary activation is the CLAUDE.md trigger-line `inbox monitor: raise on start` + the injector, not a hermes-trigger. Behavioral gate CLEARED 2026-06-17 — test-trigger + review BOTH VERDICT PASS (activation 3/3 monitor + neg clean; structural hook audit 5 PASS/1 CONCERN, the CONCERN fixed in v0.2.2). STAYS pending on two independent tool-side blockers, NOT on behavioral verification: (1) the SessionStart hook is Windows-PowerShell and needs a Linux port for Hermes factory machines; (2) machine-level side-effects (user-config mutation of ~/.claude/settings.json + Get-CimInstance|Stop-Process kills) need a tool-side audit before auto. Promotion blocked on those two, not on test-trigger/review. → intended: `mode: auto, category: productivity`
|
- **session-inbox-monitor** — Paired SessionStart hook registers itself in ~/.claude/settings.json and sweeps orphaned monitor OS processes (Get-CimInstance | Stop-Process by sentinel+inbox-path); the skill then raises an in-session Monitor on .claude-inbox/. Primary activation is the CLAUDE.md trigger-line `inbox monitor: raise on start` + the injector, not a hermes-trigger. Behavioral gate CLEARED 2026-06-17 — test-trigger + review BOTH VERDICT PASS (activation 3/3 monitor + neg clean; structural hook audit 5 PASS/1 CONCERN, the CONCERN fixed in v0.2.2). STAYS pending on two independent tool-side blockers, NOT on behavioral verification: (1) the SessionStart hook is Windows-PowerShell and needs a Linux port for Hermes factory machines; (2) machine-level side-effects (user-config mutation of ~/.claude/settings.json + Get-CimInstance|Stop-Process kills) need a tool-side audit before auto. Promotion blocked on those two, not on test-trigger/review. → intended: `mode: auto, category: productivity`
|
||||||
- **setup-agents-task-runner** — L2 installer — installs the standing-duty stack (agents-task-runner + watchdog + appeals-inbox) as platform-native OS services (systemd/launchd/winsw), fetches a pinned binary, writes poller-scope.json. Heavy infra side-effects (OS services + binary fetch); mode decision (skip vs manual vs auto) deferred — needs an explicit Hermes-factory applicability audit. Placeholder pending to keep the build green.
|
- **setup-agents-task-runner** — L2 installer — installs the standing-duty stack (agents-task-runner + watchdog + appeals-inbox) as platform-native OS services (systemd/launchd/winsw), fetches a pinned binary, writes poller-scope.json. Heavy infra side-effects (OS services + binary fetch); mode decision (skip vs manual vs auto) deferred — needs an explicit Hermes-factory applicability audit. Placeholder pending to keep the build green.
|
||||||
- **task-format** — Documentational skill — how to write a .tasks/STATUS.md task block the autonomous poller will claim/route/report (block header, status emoji, Weight/Notify/Requirements fields). No tool-side effects; pending a behavioral test-trigger before auto. → intended: `mode: auto, category: productivity`
|
- **task-format** — Documentational skill — how to write a .tasks/STATUS.md task block the autonomous poller will claim/route/report (block header, status emoji, Weight/Notify/Requirements fields). No tool-side effects; pending a behavioral test-trigger before auto. → intended: `mode: auto, category: productivity`
|
||||||
- **task-loop** — Orchestrates the board claim/close/update/heartbeat cycle via mcp__projects-meta__tasks_claim_next / tasks_close / tasks_update / tasks_heartbeat (cross-session claim ownership, irreversible close, Gitea side-effects) and may arm a single long ScheduleWakeup for the explicit long-watch opt-in. Critical-infra-adjacent — touches the same claim/close machinery the unattended poller relies on. Behavioral audit via task-loop-test-trigger required before promotion to auto. → intended: `mode: auto, category: mcp`
|
|
||||||
- **using-system-snapshot** — Calls mcp__projects-meta__meta_system_snapshot (read-only whole-machine ops snapshot: poller / docker / cross-project task load). Read-only, same class as using-vds-ops / using-wiki-graph; pending a behavioral test-trigger before auto. → intended: `mode: auto, category: mcp`
|
|
||||||
- **using-vds-ops** — Calls mcp__vds-ops__* tools (read-only, but touches infrastructure). Behavioral audit via using-vds-ops-test-trigger required before promotion to auto. → intended: `mode: auto, category: mcp`
|
- **using-vds-ops** — Calls mcp__vds-ops__* tools (read-only, but touches infrastructure). Behavioral audit via using-vds-ops-test-trigger required before promotion to auto. → intended: `mode: auto, category: mcp`
|
||||||
- **using-wiki-graph** — Calls mcp__wiki-graph__* tools (read-only, parses a .wiki/ corpus server-side). Behavioral audit via using-wiki-graph-test-trigger required before promotion to auto. → intended: `mode: auto, category: mcp`
|
|
||||||
- **using-yt-tools** — Shells out to yt-dlp + ffmpeg and writes ./yt-cache/ in cwd. Behavioral audit via using-yt-tools-test-trigger required before promotion to auto. → intended: `mode: auto, category: research`
|
- **using-yt-tools** — Shells out to yt-dlp + ffmpeg and writes ./yt-cache/ in cwd. Behavioral audit via using-yt-tools-test-trigger required before promotion to auto. → intended: `mode: auto, category: research`
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
# using-tasks
|
|
||||||
|
|
||||||
Runtime policy for keeping compressed working context across parallel tasks
|
|
||||||
in a monorepo. The agent reads and updates `.tasks/` so every session starts
|
|
||||||
oriented and every switch costs seconds, not minutes.
|
|
||||||
|
|
||||||
`using-tasks` governs *usage* of an existing `.tasks/`. Initial creation and
|
|
||||||
migration to canon are owned by [`setup-tasks`](../setup-tasks/).
|
|
||||||
|
|
||||||
> Renamed from `task-status-wiki` at v1.0.0.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- User is switching between tasks, resuming a paused task, starting a new
|
|
||||||
one, or asks "where were we" / "what's the status".
|
|
||||||
- User says: "use task management system", "pause", "switch to X",
|
|
||||||
"update status".
|
|
||||||
- Any context-switching or multi-task coordination question in a code
|
|
||||||
project.
|
|
||||||
- If `.tasks/` is missing or non-canonical, this skill delegates to
|
|
||||||
[`setup-tasks`](../setup-tasks/) before doing anything else.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
<monorepo-root>/
|
|
||||||
└── .tasks/
|
|
||||||
├── STATUS.md ← board: one block per task, sorted by priority
|
|
||||||
└── <task-slug>.md ← deep context per task, one file each
|
|
||||||
```
|
|
||||||
|
|
||||||
Commit `.tasks/` to git — decision history is valuable, diffs show how
|
|
||||||
thinking evolved.
|
|
||||||
|
|
||||||
## STATUS.md format
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Task Board
|
|
||||||
_Updated: YYYY-MM-DD_
|
|
||||||
|
|
||||||
## 🔴 [task-slug] — short description
|
|
||||||
**Status:** active | paused | blocked | done
|
|
||||||
**Where I stopped:** one sentence — the exact thought or action interrupted
|
|
||||||
**Next action:** one concrete step to resume immediately
|
|
||||||
**Blocker:** (only if blocked) what is preventing progress
|
|
||||||
**Branch:** git branch name
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Status legend:
|
|
||||||
|
|
||||||
| Emoji | State | Notes |
|
|
||||||
|---|---|---|
|
|
||||||
| 🔴 | Active | Currently worked on. **Only one at a time.** |
|
|
||||||
| 🟡 | Paused | In progress, resumable. |
|
|
||||||
| ⚪ | Ready | Defined, not started. |
|
|
||||||
| 🟢 | Done | Kept until merged. |
|
|
||||||
| 🔵 | Blocked | Waiting on external input. |
|
|
||||||
|
|
||||||
## Per-task file format (`<task-slug>.md`)
|
|
||||||
|
|
||||||
Sections, in order: **Goal** (one paragraph — what this achieves and why),
|
|
||||||
**Key files** (`path/to/file.ts:42` style — specific lines when relevant),
|
|
||||||
**Decisions log** (reverse-chronological, append-only — past entries are
|
|
||||||
immutable), **Open questions**, **Completed steps**, **Notes** (temporary
|
|
||||||
hypotheses, links).
|
|
||||||
|
|
||||||
## Operations
|
|
||||||
|
|
||||||
### Session start
|
|
||||||
|
|
||||||
1. Check `.tasks/STATUS.md`. If missing → invoke
|
|
||||||
[`setup-tasks`](../setup-tasks/) and stop until it returns.
|
|
||||||
2. Read `STATUS.md`.
|
|
||||||
3. If user names a task, read its `<task-slug>.md`.
|
|
||||||
4. Confirm in one sentence: "We're in the middle of X, next step is Y."
|
|
||||||
5. Ask if the plan is still correct before doing anything.
|
|
||||||
6. If `_Updated` is more than 3 days old, flag it and ask the user to
|
|
||||||
confirm current state.
|
|
||||||
|
|
||||||
### Session end / pause / switch
|
|
||||||
|
|
||||||
1. Update `STATUS.md`: set the current task to 🟡, refresh "Where I stopped"
|
|
||||||
and "Next action".
|
|
||||||
2. Append non-obvious decisions to `<task-slug>.md` Decisions log.
|
|
||||||
3. Move finished items to "Completed steps".
|
|
||||||
4. Commit: `git add .tasks/ && git commit -m "chore: update task status [<task-slug>]"`.
|
|
||||||
|
|
||||||
### Task switch
|
|
||||||
|
|
||||||
1. Run session-end ops for the current task.
|
|
||||||
2. Read the target `<task-slug>.md`.
|
|
||||||
3. Set the target to 🔴 in `STATUS.md` (demote previous active to 🟡).
|
|
||||||
4. Confirm orientation before starting work.
|
|
||||||
|
|
||||||
### New task
|
|
||||||
|
|
||||||
1. Ask: slug, goal, known key files, branch.
|
|
||||||
2. Create `<task-slug>.md` with Goal and Key files populated.
|
|
||||||
3. Add a ⚪ block to `STATUS.md`.
|
|
||||||
4. Create / checkout the branch if missing.
|
|
||||||
|
|
||||||
### Task completion
|
|
||||||
|
|
||||||
1. **Pre-close coverage check** — list acceptance criteria, locate
|
|
||||||
evidence (tests, smoke-test artefacts, manual checklist ticks, design
|
|
||||||
doc refs). Missing evidence → ask the user before closing; never auto-close.
|
|
||||||
2. Resolve or drop all open questions.
|
|
||||||
3. Set status to 🟢 in `STATUS.md`.
|
|
||||||
4. Append a final summary line to the Decisions log.
|
|
||||||
5. Remind the user to delete the branch after merge.
|
|
||||||
|
|
||||||
### Post-commit task closure prompt
|
|
||||||
|
|
||||||
After a `feat:` / `fix:` commit the agent prompts:
|
|
||||||
"эта работа закрывает таску `<slug>`?". Slug candidates: commit-message
|
|
||||||
scope, current branch, most recent `Where I stopped`. If yes → run the
|
|
||||||
coverage check above. Skips `chore:` / `meta:` / `docs:` commits.
|
|
||||||
|
|
||||||
Forces a fresh-while-fresh decision, instead of letting shipped code sit
|
|
||||||
under a stale ⚪ block.
|
|
||||||
|
|
||||||
### Recommendations / "what's next" trigger
|
|
||||||
|
|
||||||
When the user asks «что дальше», «срочные», «куда копаем», "what next",
|
|
||||||
"status", or on session-start — recommend in this order:
|
|
||||||
|
|
||||||
1. **Local cwd-project board** ranked 🔴 → 🟡 → ⚪. Cite slugs.
|
|
||||||
2. **One footnote line** if relevant: `Cross-project: N 🔴 in other repos
|
|
||||||
(см. mcp__projects-meta__tasks_aggregate).` Only if N>0 and no local 🔴.
|
|
||||||
|
|
||||||
Explicit "по всем проектам" / "across all projects" flips the order.
|
|
||||||
Pairs with `using-projects-meta`'s local-first rule (which covers reads;
|
|
||||||
this one covers recommendations).
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
|
|
||||||
- **Never lose "Where I stopped".** Most critical field. If unclear, ask
|
|
||||||
before ending the session.
|
|
||||||
- **One sentence per `STATUS.md` field.** Compress, don't write prose.
|
|
||||||
- **Key files must be specific** — not "auth module" but
|
|
||||||
`packages/auth/src/useAuth.ts:87`.
|
|
||||||
- **Decisions log is append-only.** Past entries are immutable.
|
|
||||||
- **Commit after every session end.** `git log` is the history of thinking.
|
|
||||||
- **Always confirm orientation at session start.** State understanding
|
|
||||||
before acting.
|
|
||||||
- **One active task at a time** — only one 🔴 in `STATUS.md`.
|
|
||||||
- **Never close without coverage check.** See "### Task completion"
|
|
||||||
step 1.
|
|
||||||
- **Local-first recommendations.** cwd-project first; cross-project at
|
|
||||||
most one footnote line.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
From the repo root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/install.sh using-tasks
|
|
||||||
```
|
|
||||||
|
|
||||||
Works on Windows under git-bash, Linux, macOS.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [`setup-tasks`](../setup-tasks/) — companion, owns `.tasks/` creation and
|
|
||||||
canon migration.
|
|
||||||
- [`project-bootstrap`](../project-bootstrap/) — invokes `setup-tasks` for
|
|
||||||
new projects.
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-tasks
|
|
||||||
version: 1.4.0
|
|
||||||
description: >
|
|
||||||
Policy skill for working with an existing `.tasks/` board (per-task files + STATUS.md).
|
|
||||||
Use whenever the user is switching between tasks, resuming a paused task, starting a new
|
|
||||||
task, asking "where were we", says "use task management system", "pause", "switch to X",
|
|
||||||
"what's the status", "update status", or wants to track progress across parallel workstreams.
|
|
||||||
Trigger on any context-switching or multi-task coordination question in a code project.
|
|
||||||
If `.tasks/` is missing or non-canonical (no per-task `<task-slug>.md` files, no emoji
|
|
||||||
status legend in STATUS.md), delegate to `setup-tasks` first — it has its own confirmation
|
|
||||||
gate. Renamed from `task-status-wiki` at v1.0.0.
|
|
||||||
---
|
|
||||||
|
|
||||||
# using-tasks
|
|
||||||
|
|
||||||
> Policy for maintaining compressed working context across parallel tasks in a monorepo.
|
|
||||||
> The agent reads and updates `.tasks/` so every session starts oriented and every switch
|
|
||||||
> costs seconds, not minutes. This skill governs *usage* of an existing `.tasks/` — initial
|
|
||||||
> creation and migration to canon are owned by `setup-tasks`.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
This skill assumes the project has a canonical `.tasks/` layout:
|
|
||||||
|
|
||||||
- `.tasks/STATUS.md` — the board, with per-task blocks using emoji status (🔴 active / 🟡 paused / ⚪ ready / 🟢 done / 🔵 blocked).
|
|
||||||
- `.tasks/<task-slug>.md` — one deep-context file per active or paused task.
|
|
||||||
|
|
||||||
If `.tasks/` is **missing**, or `STATUS.md` exists but is non-canonical (e.g. flat sections like "## Done" / "## In Progress" without the emoji + per-task block format, or no per-task files exist alongside STATUS.md) — invoke `setup-tasks` first. It detects greenfield vs migrate, has its own confirmation gate, and creates / migrates the structure. Only after `setup-tasks` finishes should this skill operate on `.tasks/`.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
<monorepo-root>/
|
|
||||||
.tasks/
|
|
||||||
STATUS.md ← active board: 🔴 / 🟡 / ⚪ / 🔵 blocks, sorted by priority
|
|
||||||
<task-slug>.md ← deep context per task, one file each
|
|
||||||
.lock ← runtime session lock; **gitignored** (never committed)
|
|
||||||
archive/
|
|
||||||
YYYY-MM.md ← 🟢 done blocks moved off the board, one file per month
|
|
||||||
```
|
|
||||||
|
|
||||||
Commit `.tasks/` to git. Decision history is valuable; diffs show how thinking evolved.
|
|
||||||
|
|
||||||
`STATUS.md` is the **active** board — it must stay lean so orientation reads stay cheap. Closed 🟢 tasks are archived to `archive/YYYY-MM.md` once they pile up; see "### Archiving done tasks".
|
|
||||||
|
|
||||||
> **`.tasks/.lock` must be listed in `.gitignore`** (add `.tasks/.lock` to your project's `.gitignore`). The lock file is ephemeral runtime state, not project history — it must never be committed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## STATUS.md format
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Task Board
|
|
||||||
_Updated: YYYY-MM-DD_
|
|
||||||
|
|
||||||
## 🔴 [task-slug] — short description
|
|
||||||
**Status:** active | paused | blocked | done
|
|
||||||
**Where I stopped:** one sentence — the exact thought or action interrupted
|
|
||||||
**Next action:** one concrete step to resume immediately
|
|
||||||
**Blocker:** (only if blocked) what is preventing progress
|
|
||||||
**Session break:** (optional) `true` — or a hint string for the next track. Marks this task as a session boundary.
|
|
||||||
**Branch:** git branch name
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
**Emoji convention:**
|
|
||||||
- 🔴 Active — currently worked on (only one at a time)
|
|
||||||
- 🟡 Paused — in progress, resumable
|
|
||||||
- ⚪ Ready — not started, fully defined
|
|
||||||
- 🟢 Done — completed; kept on the board until merged, then archived (see "### Archiving done tasks")
|
|
||||||
- 🔵 Blocked — waiting on external input
|
|
||||||
|
|
||||||
### `session_break` marker
|
|
||||||
|
|
||||||
A task may carry a `session_break` marker — set by whoever defines the task (e.g. the delegating workshop) when its completion is a natural place to stop and start a fresh session. It signals an autonomous agent: *finish this task, then pause instead of immediately claiming the next one.*
|
|
||||||
|
|
||||||
- **Type:** boolean or string.
|
|
||||||
- `session_break: true` — pause after close; the next track is "see STATUS.md".
|
|
||||||
- `session_break: "<hint>"` — pause after close; `<hint>` names the recommended next track.
|
|
||||||
- **Where it lives:** in the task's frontmatter when delivered via the task system (`session_break: true` / `session_break: "<hint>"`); mirrored on the local board as the optional `**Session break:**` field in the task's STATUS.md block.
|
|
||||||
- **Absent →** behaviour is unchanged: close the task and continue as usual.
|
|
||||||
|
|
||||||
The check is enforced in the **Task completion** flow below (after close, before claiming the next task).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Per-task file format (`<task-slug>.md`)
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# <task-slug>
|
|
||||||
|
|
||||||
## Goal
|
|
||||||
One paragraph. What this achieves and why it matters in the monorepo.
|
|
||||||
|
|
||||||
## Key files
|
|
||||||
- `path/to/file.ts` — role in this task
|
|
||||||
- `path/to/other.ts:42` — specific line if relevant
|
|
||||||
|
|
||||||
## Decisions log
|
|
||||||
Reverse-chronological. Append only — never rewrite past entries.
|
|
||||||
- YYYY-MM-DD: Why X was chosen over Y
|
|
||||||
- YYYY-MM-DD: Constraint Z discovered, approach adjusted
|
|
||||||
|
|
||||||
## Open questions
|
|
||||||
- [ ] unresolved design or dependency questions
|
|
||||||
|
|
||||||
## Completed steps
|
|
||||||
- [x] steps finished this or previous sessions
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
Temporary hypotheses, links, names of people to consult.
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Agent operations
|
|
||||||
|
|
||||||
### Session start
|
|
||||||
1. **Session lock guard.** If `.tasks/` exists, read `.tasks/.lock`.
|
|
||||||
- **Active agent lock** — `type:"agent"` with `heartbeat` ≤ 10 minutes old: print the hard warning below and **require explicit user confirmation** before proceeding. Do not touch the board until the user confirms.
|
|
||||||
```
|
|
||||||
⚠️ поллер ведёт <slug> — нельзя работать параллельно
|
|
||||||
```
|
|
||||||
(Substitute the `slug` field from the lock file if present, otherwise omit it.)
|
|
||||||
- **Stale lock** — any type whose TTL has expired (`type:"agent"` with `heartbeat` > 10 min ago; `type:"interactive"` with `started_at` > 2 h ago): silently overwrite.
|
|
||||||
- **Absent or stale lock** (including after user confirmation): write `.tasks/.lock`:
|
|
||||||
```json
|
|
||||||
{"type":"interactive","started_at":"<ISO8601>","ttl_minutes":120}
|
|
||||||
```
|
|
||||||
2. Check if `.tasks/STATUS.md` exists. If not → invoke `setup-tasks` and stop here until it returns.
|
|
||||||
3. Read `STATUS.md` — this is the orientation read (see note below on why it's a local read, not an MCP call).
|
|
||||||
4. If user names a task, read its `<task-slug>.md`.
|
|
||||||
5. Confirm in one sentence: "We're in the middle of X, next step is Y."
|
|
||||||
6. Ask if the plan is still correct before doing anything.
|
|
||||||
7. If STATUS.md `_Updated` date is >3 days ago, flag it and ask user to confirm current state.
|
|
||||||
8. If `STATUS.md` holds **≥ 10** 🟢 done blocks, archive them first (see "### Archiving done tasks") so the board you orient on is lean.
|
|
||||||
|
|
||||||
> **Orient by reading the local `STATUS.md`, not an MCP call.** It is the live board and — kept lean by archival — cheap to read. Do **not** reach for projects-meta tools to enumerate the current project's board:
|
|
||||||
> - `tasks_aggregate` is cache-based, cross-project, and does **not** index ready/done — its own docs say to read `.tasks/STATUS.md` directly for the current project.
|
|
||||||
> - `tasks_get_status(target_project, slug)` returns a **single** task's live status (`{status, found}`) by a slug you already know — it cannot list the board. Use it only to check **one** known task (e.g. confirm a delegated task's board state, or detect async-human parking), never for orientation.
|
|
||||||
|
|
||||||
### Session end / pause / switch
|
|
||||||
1. **Release session lock.** If `.tasks/.lock` exists and contains `"type":"interactive"`: delete `.tasks/.lock`. (Stale interactive locks are cleaned up here too; silently delete any interactive lock regardless of TTL.)
|
|
||||||
2. Update `STATUS.md`: set current task to 🟡, update "Where I stopped" and "Next action".
|
|
||||||
3. Append to `<task-slug>.md` Decisions log any non-obvious choices made this session.
|
|
||||||
4. Move finished items to "Completed steps".
|
|
||||||
5. Commit: `git add .tasks/ && git commit -m "chore: update task status [<task-slug>]"`
|
|
||||||
|
|
||||||
### Task switch
|
|
||||||
1. Perform session-end operations for the current task.
|
|
||||||
2. Read the target `<task-slug>.md`.
|
|
||||||
3. Set it to 🔴 in STATUS.md (demote previous active to 🟡).
|
|
||||||
4. Confirm orientation before starting work.
|
|
||||||
|
|
||||||
### New task creation
|
|
||||||
1. Ask: task name (slug), goal, known key files, branch name.
|
|
||||||
2. Create `<task-slug>.md` with Goal and Key files populated.
|
|
||||||
3. Add ⚪ block to `STATUS.md`.
|
|
||||||
4. Create and checkout branch if it doesn't exist.
|
|
||||||
|
|
||||||
### Task completion
|
|
||||||
1. **Pre-close coverage check.** Before setting 🟢:
|
|
||||||
- List acceptance criteria from the per-task `<slug>.md` (or the STATUS block if no per-task file).
|
|
||||||
- For each criterion, locate evidence: a test name in the diff, a smoke-test artefact, a manual-checklist tick in the per-task file, or a design-doc reference.
|
|
||||||
- Missing evidence on any criterion → flag to user and ask "закрывать или подождать coverage'а?". Never silently close.
|
|
||||||
- If acceptance criteria are policy / docs-only and have no testable shape, an explicit user "ok, closed by inspection" is required (record this in the close-note).
|
|
||||||
2. Resolve or drop all open questions.
|
|
||||||
3. Set status to 🟢 in STATUS.md.
|
|
||||||
4. Append final summary line to Decisions log.
|
|
||||||
5. Remind user to delete the branch after merge.
|
|
||||||
6. **Session-break check (after close, before claiming the next task).** Once the task is 🟢 and committed — and **before** any `tasks_claim_next` or starting the next task — read the closed task's `session_break` marker (its frontmatter `session_break`, or the `**Session break:**` field in its STATUS.md block). If present:
|
|
||||||
- Print this line **verbatim**, substituting the closed task's slug for `[slug]` and the marker's string value for `[value | "см. STATUS.md"]` (use the literal `см. STATUS.md` when the marker is just `true`):
|
|
||||||
|
|
||||||
`🔚 SESSION BOUNDARY — [slug] закрыта. Рекомендую завершить текущую сессию. Следующий трек: [value | "см. STATUS.md"]`
|
|
||||||
|
|
||||||
- **Stop.** Do not claim or start the next task.
|
|
||||||
- If the marker is absent → behaviour is unchanged: proceed to claim / start the next task as usual.
|
|
||||||
7. **Archival check.** After the close is committed, if `STATUS.md` now holds **≥ 10** 🟢 done blocks, archive them (see "### Archiving done tasks"). This keeps the board lean for the next orientation read.
|
|
||||||
|
|
||||||
### Archiving done tasks
|
|
||||||
|
|
||||||
🟢 done blocks accumulate in `STATUS.md` and bloat it — and since orientation reads the whole board, a bloated file burns context on every session start (the recurring "huge STATUS.md" complaint). Keep the board lean: done blocks stay only until merged, then move to a monthly archive.
|
|
||||||
|
|
||||||
**Threshold.** When `STATUS.md` holds **≥ 10** 🟢 done blocks, archive them. Check at two moments: (a) right after closing a task (Task completion step 7), and (b) at session start, before orienting (Session start step 7). The threshold is a ceiling, not a target — archive in batches; don't churn one block at a time.
|
|
||||||
|
|
||||||
**Where.** Append the archived blocks to `.tasks/archive/YYYY-MM.md` — one file per calendar month, keyed by the date of archival. Create `.tasks/archive/` and the month file if absent. If the month file already exists, **append**; never overwrite.
|
|
||||||
|
|
||||||
**Archive file format** (header written once, on file creation):
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Archived done tasks — YYYY-MM
|
|
||||||
|
|
||||||
Moved out of `.tasks/STATUS.md` to keep the active board lean.
|
|
||||||
Full source is git history; this file is for grep-able historical context.
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
…followed by each 🟢 block **verbatim** (including its trailing `---` separator and any `<!-- closed-by … -->` comments).
|
|
||||||
|
|
||||||
**After archiving,** `STATUS.md` keeps only 🔴 / 🟡 / ⚪ / 🔵 blocks. Commit the move on its own:
|
|
||||||
|
|
||||||
```
|
|
||||||
git add .tasks/ && git commit -m "meta(tasks): archive done batch → .tasks/archive/YYYY-MM.md"
|
|
||||||
```
|
|
||||||
|
|
||||||
Leave a just-closed 🟢 block on the board only while it's still useful at a glance (pending merge, fresh reference). Everything older goes to the archive.
|
|
||||||
|
|
||||||
### Post-commit task closure prompt
|
|
||||||
|
|
||||||
After any implementation commit (`feat:` / `fix:` / similar), prompt the user once:
|
|
||||||
|
|
||||||
> Эта работа закрывает таску `<slug>`?
|
|
||||||
|
|
||||||
Slug candidates, in priority: (a) commit message scope, (b) current branch name, (c) the most recent `Where I stopped` field that mentions a now-shipped artefact. If user says yes → run the pre-close coverage check from "### Task completion". If no → silent.
|
|
||||||
|
|
||||||
Skip on `chore:` / `meta:` / `docs:` / `style:` commits — they rarely close work.
|
|
||||||
|
|
||||||
This exists because shipped code can sit while the task block stays ⚪ ready (e.g. `extend-project-discipline-brainstorm-workspaces` lived as ⚪ for a day after `215afdd` shipped Rule 5). The prompt forces a one-line decision while the work is fresh.
|
|
||||||
|
|
||||||
### Recommendations / "what's next" trigger
|
|
||||||
|
|
||||||
When the user asks «что дальше», «срочные», «куда копаем», «status», «what next», or session-start lands on a project — recommend in this order:
|
|
||||||
|
|
||||||
1. **Local cwd-project board** ranked 🔴 → 🟡 → ⚪. Group by status, summarize one line each. Cite slugs.
|
|
||||||
2. **One footnote line** if cross-project state is relevant: `Cross-project: N 🔴 active in other repos (см. mcp__projects-meta__tasks_aggregate).` Only when N>0 and there is no active 🔴 in the current cwd. Never bury local recommendations under it.
|
|
||||||
|
|
||||||
Cross-project urgents are *information*, not the driver of "what to do here". The user chose this cwd; that's the implicit scope.
|
|
||||||
|
|
||||||
If the user explicitly asks "across all projects" / "по всем проектам" / "cross-project status" — flip the order: cross-project first, local as footnote.
|
|
||||||
|
|
||||||
Pair: `using-projects-meta` declares local-first for **reads**; this rule extends local-first to the **recommendation phase**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
|
|
||||||
- **Honour `.tasks/.lock`** — read the lock at session start before touching the board; write it after clearing the guard; delete it at session end/pause. Never skip the lock check when `.tasks/` exists. The lock file must be gitignored.
|
|
||||||
- **Never lose "Where I stopped"** — most critical field. If unclear, ask before ending session.
|
|
||||||
- **One sentence per STATUS.md field** — compress, don't write prose.
|
|
||||||
- **Key files must be specific** — not "auth module" but `packages/auth/src/useAuth.ts:87`.
|
|
||||||
- **Decisions log is append-only** — past entries are immutable.
|
|
||||||
- **Commit after every session end** — git log is the history of thinking.
|
|
||||||
- **Always confirm orientation at session start** — state understanding before acting.
|
|
||||||
- **One active task at a time** — only one 🔴 in STATUS.md.
|
|
||||||
- **Keep the board lean** — orientation reads the local `STATUS.md` whole, so archive 🟢 done blocks to `.tasks/archive/YYYY-MM.md` once ≥10 pile up. Never enumerate the current project's board via `tasks_aggregate` (cross-project cache) or `tasks_get_status` (single-task, by slug). See "### Archiving done tasks".
|
|
||||||
- **Never close a task without a coverage check** — see "### Task completion" step 1. Acceptance criteria with no evidence → ask, don't auto-close.
|
|
||||||
- **Honour `session_break`** — a closed task carrying a `session_break` marker means stop after close; never chain into `tasks_claim_next`. See "### Task completion" step 6.
|
|
||||||
- **Local-first recommendations** — cwd-project board comes first; cross-project urgents are at most one footnote line.
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
# using-wiki
|
|
||||||
|
|
||||||
Runtime policy for an LLM Wiki built on the
|
|
||||||
[Karpathy LLM Wiki pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f).
|
|
||||||
Knowledge is **compiled once and kept current** across three layers, via
|
|
||||||
three named operations, with strict file formats that keep the wiki
|
|
||||||
parseable and grep-friendly.
|
|
||||||
|
|
||||||
`using-wiki` governs *usage* of an existing `.wiki/`. Initial creation and
|
|
||||||
migration to canon are owned by [`setup-wiki`](../setup-wiki/).
|
|
||||||
|
|
||||||
> Renamed from `wiki-maintainer` at v1.0.0.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- User says: "use project wiki", "query the wiki", "ingest this", or the
|
|
||||||
Russian equivalents ("обнови вики", "проверь вики", "запроси вики",
|
|
||||||
"заингесть").
|
|
||||||
- Any time the agent modifies a file under `.wiki/` — the workflow and
|
|
||||||
formats below are mandatory.
|
|
||||||
- If `.wiki/` is missing or non-canonical, this skill delegates to
|
|
||||||
[`setup-wiki`](../setup-wiki/) before doing anything else.
|
|
||||||
|
|
||||||
## Three layers (do not blur)
|
|
||||||
|
|
||||||
1. **Raw sources** — `.wiki/raw/` (or external paths registered in
|
|
||||||
`raw/README.md`). **Immutable.** Read, never edit. The only exception is
|
|
||||||
appending a `> Status` blockquote when the user explicitly asks for a
|
|
||||||
status audit.
|
|
||||||
2. **Wiki** — everything else under `.wiki/`. Agent-owned. Entity / concept /
|
|
||||||
package / source summary pages.
|
|
||||||
3. **Schema** — `.wiki/CLAUDE.md`. Project-specific conventions (what
|
|
||||||
entities, what packages, naming). Always read it first; it overrides this
|
|
||||||
skill on conflict.
|
|
||||||
|
|
||||||
## Three operations
|
|
||||||
|
|
||||||
### Ingest
|
|
||||||
|
|
||||||
«заингесть X» — pull a raw source into the wiki.
|
|
||||||
|
|
||||||
1. Read the raw source fully.
|
|
||||||
2. Extract: entities, concepts, packages, cross-cutting patterns.
|
|
||||||
3. Create `sources/<slug>.md` (one summary page per source, ~50–150 lines).
|
|
||||||
4. For each affected entity / concept / package page: update if exists,
|
|
||||||
create if not. Flag contradictions explicitly with
|
|
||||||
`> **Противоречие:** источник A говорит X, источник B — Y`.
|
|
||||||
**Never silently overwrite.**
|
|
||||||
5. Update `index.md`.
|
|
||||||
6. Append one line to `log.md`.
|
|
||||||
7. Report: what was created, updated, contradicted.
|
|
||||||
|
|
||||||
One ingest may touch 10–15 pages. That's normal — that's why an LLM does it.
|
|
||||||
|
|
||||||
### Query
|
|
||||||
|
|
||||||
A question answered from the wiki.
|
|
||||||
|
|
||||||
1. Read `index.md` first, drill into relevant pages.
|
|
||||||
2. Answer with citations as markdown links.
|
|
||||||
3. **Compound the wiki.** If the answer is a real synthesis, ask the user:
|
|
||||||
"Сохранить как страницу wiki?" Good queries become durable pages under
|
|
||||||
`concepts/` or `analyses/`.
|
|
||||||
4. Append one line to `log.md`.
|
|
||||||
|
|
||||||
### Lint
|
|
||||||
|
|
||||||
«проверь wiki» — health check.
|
|
||||||
|
|
||||||
Scan for:
|
|
||||||
|
|
||||||
- Contradictions between pages.
|
|
||||||
- Orphans (pages with no inbound links).
|
|
||||||
- Stale claims (raw source updated after the summary's `ingested:` date —
|
|
||||||
check via `git log -p`).
|
|
||||||
- Concepts mentioned in prose but missing their own page.
|
|
||||||
- Empty / TODO sections.
|
|
||||||
|
|
||||||
Report as a punch list. Don't delete anything automatically. Append one
|
|
||||||
line to `log.md` with the findings.
|
|
||||||
|
|
||||||
## File formats (mandatory)
|
|
||||||
|
|
||||||
### Page frontmatter
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
title: Человекочитаемое имя
|
|
||||||
type: entity | concept | package | source | contradiction | open-question | overview
|
|
||||||
tags: [short, tokens]
|
|
||||||
sources: [../sources/foo.md, ../sources/bar.md]
|
|
||||||
updated: 2026-04-21
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Source pages also carry `ingested: YYYY-MM-DD` and `raw_path: ../raw/...`.
|
|
||||||
Contradiction pages also carry `status: open | resolved | accepted-divergence` and `affects: [../entities/x.md, ../concepts/y.md]`.
|
|
||||||
Open-question pages also carry `status: open | answered | obsolete` and `touches: [../entities/x.md, ../sources/z.md]`.
|
|
||||||
|
|
||||||
### File naming
|
|
||||||
|
|
||||||
- `kebab-case.md`, **Latin only**. Transliterate Cyrillic / non-Latin in
|
|
||||||
filenames; keep the original title in H1 + frontmatter.
|
|
||||||
- `entities/<name>.md`, `concepts/<name>.md`, `packages/<name>.md`
|
|
||||||
(no `@org/` prefix), `sources/<slug>.md`, `contradictions/<slug>.md`,
|
|
||||||
`open-questions/<slug>.md`.
|
|
||||||
|
|
||||||
### `log.md` — append-only, grep-parseable
|
|
||||||
|
|
||||||
Every entry must start with:
|
|
||||||
|
|
||||||
```
|
|
||||||
## [YYYY-MM-DD] <operation> | <short description>
|
|
||||||
```
|
|
||||||
|
|
||||||
Operations: `ingest`, `query`, `lint`, `refactor`, `decision`, `init`.
|
|
||||||
|
|
||||||
Parse with: `grep "^## \[" .wiki/log.md | tail -20`.
|
|
||||||
|
|
||||||
### `index.md`
|
|
||||||
|
|
||||||
Catalog, not narrative. One line per page: `- [Title](path) — hook.`
|
|
||||||
Sections by type. Update on every ingest.
|
|
||||||
|
|
||||||
### Cross-references
|
|
||||||
|
|
||||||
- Wiki → wiki: relative markdown links — `[Name](../entities/x.md)`.
|
|
||||||
- Wiki → code: relative path from repo root — `[foo.js](../../packages/api/foo.js)`.
|
|
||||||
- Wiki → raw: `../raw/<file>`.
|
|
||||||
- URL-encode spaces (`%20`) and Cyrillic when needed.
|
|
||||||
|
|
||||||
## Quick reference
|
|
||||||
|
|
||||||
| Situation | Files touched |
|
|
||||||
|---|---|
|
|
||||||
| Ingest one doc | `sources/<slug>.md` (new) + 3–15 entity/concept/package pages + `index.md` + `log.md` |
|
|
||||||
| Query | (read only) + optionally a new wiki page + `log.md` |
|
|
||||||
| Lint | (read only) + `log.md` |
|
|
||||||
| Bootstrap / migrate | (delegated to [`setup-wiki`](../setup-wiki/)) |
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
- **Editing `raw/`.** Don't. Only allowed change: status blockquote on
|
|
||||||
explicit request.
|
|
||||||
- **Dumping raw content into `sources/`.** Summaries are summaries. Link to
|
|
||||||
raw, don't copy.
|
|
||||||
- **Silent overwrites on contradictions.** Flag them with a `> **Противоречие:**`
|
|
||||||
block.
|
|
||||||
- **Narrative `log.md`.** "Today I added…" is wrong. Use
|
|
||||||
`## [YYYY-MM-DD] ingest | <what>`.
|
|
||||||
- **Non-ASCII filenames.** Breaks greppability and cross-platform. Transliterate.
|
|
||||||
- **Forgetting `index.md`.** Pages not listed there are invisible to future
|
|
||||||
queries.
|
|
||||||
- **Improvising layout when canon files are missing.** Hand off to
|
|
||||||
[`setup-wiki`](../setup-wiki/) instead of patching ad-hoc.
|
|
||||||
|
|
||||||
## When NOT to use
|
|
||||||
|
|
||||||
- The project has CLAUDE.md / AGENTS.md docs but no `.wiki/` — that's regular
|
|
||||||
documentation, not an LLM Wiki.
|
|
||||||
- The user wants a single-file README or ADR — this skill is for persistent,
|
|
||||||
interlinked knowledge bases.
|
|
||||||
- One-off questions about code — read files directly, no wiki workflow needed.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
From the repo root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/install.sh using-wiki
|
|
||||||
```
|
|
||||||
|
|
||||||
Works on Windows under git-bash, Linux, macOS.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [`setup-wiki`](../setup-wiki/) — companion, owns `.wiki/` creation and
|
|
||||||
canon migration.
|
|
||||||
- [`project-bootstrap`](../project-bootstrap/) — invokes `setup-wiki` for
|
|
||||||
new projects.
|
|
||||||
- Karpathy's LLM Wiki gist:
|
|
||||||
<https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f>
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-wiki
|
|
||||||
version: 1.1.0
|
|
||||||
description: Policy skill for working with an existing `.wiki/` (Karpathy LLM Wiki pattern). Use when the user asks to ingest a document, answer from the wiki, lint/health-check it, or says "use project wiki", "обнови вики", "проверь вики", "запроси вики", "заингесть", "query the wiki". Also use when modifying any file under `.wiki/` — the workflow and formats below are mandatory, and project-specific conventions live in `.wiki/CLAUDE.md`. If `.wiki/` is missing or non-canonical, delegate to `setup-wiki` first (it has its own confirmation gate). Renamed from `wiki-maintainer` at v1.0.0.
|
|
||||||
---
|
|
||||||
|
|
||||||
# using-wiki
|
|
||||||
|
|
||||||
> Policy for maintaining an LLM Wiki (Karpathy pattern: https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). Knowledge is **compiled once and kept current** across three layers, via three named operations, with strict file formats that make the wiki parseable and grep-friendly. This skill governs *usage* of an existing wiki — initial creation and migration to canon are owned by `setup-wiki`.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
This skill assumes the project has a canonical `.wiki/` layout: `CLAUDE.md` (schema), `index.md` (catalog), `log.md` (op log), `overview.md`, `raw/README.md`, and the six content directories `entities/`, `concepts/`, `packages/`, `sources/`, `contradictions/`, `open-questions/`.
|
|
||||||
|
|
||||||
If `.wiki/` is **missing**, or the layout is **non-canonical** (e.g. `SUMMARY.md` instead of `index.md`, or `source/` instead of `concepts/`/`sources/`, or `contradictions/`/`open-questions/` directories are absent) — invoke the `setup-wiki` skill first. It detects the situation (greenfield vs migrate) and creates or migrates the structure with its own confirmation gate. Only after `setup-wiki` finishes should this skill proceed with the operations below.
|
|
||||||
|
|
||||||
## Three layers (do not blur)
|
|
||||||
|
|
||||||
1. **Raw sources** — `.wiki/raw/` (or external paths registered in `raw/README.md`). **Immutable.** Read, never edit. The only exception is appending a `> Status` blockquote when the user explicitly asks for a status audit.
|
|
||||||
2. **Wiki** — everything else under `.wiki/`. Agent-owned. Entity / concept / package / source summary pages.
|
|
||||||
3. **Schema** — `.wiki/CLAUDE.md`. Project-specific conventions (what entities, what packages, naming). Always read it first if present; it overrides this skill when it conflicts.
|
|
||||||
|
|
||||||
## First step on every operation
|
|
||||||
|
|
||||||
1. Read `.wiki/CLAUDE.md` if it exists.
|
|
||||||
2. Read `.wiki/index.md` to locate relevant pages.
|
|
||||||
3. Only then act.
|
|
||||||
|
|
||||||
If `.wiki/CLAUDE.md` is missing, the layout is incomplete — invoke `setup-wiki` rather than improvising.
|
|
||||||
|
|
||||||
## Three operations
|
|
||||||
|
|
||||||
### Ingest — «заингесть X»
|
|
||||||
|
|
||||||
1. Read the raw source fully.
|
|
||||||
2. Extract: entities, concepts, packages, cross-cutting patterns.
|
|
||||||
3. Create `sources/<slug>.md` (one summary page per source, ~50–150 lines).
|
|
||||||
4. For each affected entity/concept/package page:
|
|
||||||
- If it exists → update it. **Flag contradictions explicitly** with `> **Противоречие:** источник A говорит X, источник B — Y`. Don't silently overwrite.
|
|
||||||
- If not → create it.
|
|
||||||
5. Update `index.md` — add or move entries.
|
|
||||||
6. Append one line to `log.md` (format below).
|
|
||||||
7. Report to the user: what created, what updated, what contradictions found.
|
|
||||||
|
|
||||||
**One ingest may touch 10–15 pages. This is normal — that's why LLMs do it.**
|
|
||||||
|
|
||||||
### Query — вопрос по wiki
|
|
||||||
|
|
||||||
1. Read `index.md` first, then drill into relevant pages.
|
|
||||||
2. Answer with citations as markdown links to wiki pages.
|
|
||||||
3. **Compound the wiki.** If the answer is a real synthesis (comparison, analysis, new connection) — ask the user: "Сохранить как страницу wiki?" Good queries become durable pages under `concepts/`, `analyses/`, or similar.
|
|
||||||
4. Append one line to `log.md`.
|
|
||||||
|
|
||||||
### Lint — «проверь wiki»
|
|
||||||
|
|
||||||
Scan for:
|
|
||||||
- **Contradictions** between pages.
|
|
||||||
- **Orphans** — pages with no inbound links.
|
|
||||||
- **Stale claims** — git `log -p` on the raw source shows it was updated after the summary's `ingested:` date.
|
|
||||||
- **Missing entities** — concepts mentioned in prose but without their own page.
|
|
||||||
- **Empty/TODO sections.**
|
|
||||||
|
|
||||||
Report as a punch list. Don't delete anything automatically.
|
|
||||||
Append one line to `log.md` summarizing the findings.
|
|
||||||
|
|
||||||
## File formats (MANDATORY)
|
|
||||||
|
|
||||||
### Page frontmatter
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
title: Человекочитаемое имя
|
|
||||||
type: entity | concept | package | source | contradiction | open-question | overview
|
|
||||||
tags: [short, tokens]
|
|
||||||
sources: [../sources/foo.md, ../sources/bar.md]
|
|
||||||
updated: 2026-04-21
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Source pages also carry `ingested: YYYY-MM-DD` and `raw_path: ../raw/...`.
|
|
||||||
|
|
||||||
Contradiction pages also carry `status: open | resolved | accepted-divergence` and `affects: [../entities/x.md, ../concepts/y.md]`.
|
|
||||||
|
|
||||||
Open-question pages also carry `status: open | answered | obsolete` and `touches: [../entities/x.md, ../sources/z.md]`.
|
|
||||||
|
|
||||||
### File naming
|
|
||||||
|
|
||||||
- `kebab-case.md`, **Latin only**. Transliterate Cyrillic / other scripts in filenames (`план переписывания` → `ozon-client-rewrite.md`). Keep the original title in the H1 and frontmatter.
|
|
||||||
- `entities/<name>.md`, `concepts/<name>.md`, `packages/<name>.md` (no `@org/` prefix), `sources/<slug>.md`, `contradictions/<slug>.md`, `open-questions/<slug>.md`.
|
|
||||||
|
|
||||||
### `log.md` — append-only, grep-parseable
|
|
||||||
|
|
||||||
Every entry **must** start with:
|
|
||||||
|
|
||||||
```
|
|
||||||
## [YYYY-MM-DD] <operation> | <short description>
|
|
||||||
```
|
|
||||||
|
|
||||||
Operations: `ingest`, `query`, `lint`, `refactor`, `decision`, `init`.
|
|
||||||
|
|
||||||
Parseable with: `grep "^## \[" .wiki/log.md | tail -20`.
|
|
||||||
|
|
||||||
### `index.md`
|
|
||||||
|
|
||||||
Catalog, not narrative. One line per page: `- [Title](path) — hook.` Sections by type (entities / concepts / packages / sources / contradictions / open-questions). Update on every ingest.
|
|
||||||
|
|
||||||
### Cross-references
|
|
||||||
|
|
||||||
- Wiki → wiki: relative markdown links, `[Name](../entities/x.md)`.
|
|
||||||
- Wiki → code: relative path from repo root: `[foo.js](../../packages/api/foo.js)`.
|
|
||||||
- Wiki → raw: `../raw/<file>`.
|
|
||||||
- URL-encode spaces in paths (`%20`) and Cyrillic when needed.
|
|
||||||
|
|
||||||
## Quick reference
|
|
||||||
|
|
||||||
| Situation | Files touched |
|
|
||||||
|---|---|
|
|
||||||
| Ingest one doc | `sources/<slug>.md` (new) + 3–15 entity/concept/package pages + `index.md` + `log.md` |
|
|
||||||
| Query | (read only) + optionally new wiki page + `log.md` |
|
|
||||||
| Lint | (read only) + `log.md` |
|
|
||||||
| Bootstrap / migrate to canon | (delegated to `setup-wiki`) |
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
- **Editing `raw/`.** Don't. Only allowed: status blockquote when user explicitly asks.
|
|
||||||
- **Dumping raw content into `sources/`.** Summaries are summaries. Link to raw, don't copy it.
|
|
||||||
- **Silent overwrites.** When a new source contradicts an existing page, flag it with a `> **Противоречие:**` block; don't just overwrite.
|
|
||||||
- **Narrative `log.md`.** `Today I added…` is wrong. Use `## [YYYY-MM-DD] ingest | <what>`.
|
|
||||||
- **Non-ASCII file names.** Breaks greppability and cross-platform. Transliterate.
|
|
||||||
- **Forgetting `index.md`.** Pages not listed there are effectively invisible for future queries.
|
|
||||||
- **Skipping contradictions in lint.** The wiki's value grows from surfaced tensions, not from false consensus.
|
|
||||||
- **Improvising layout when canon files are missing.** If the wiki is missing or partial, hand off to `setup-wiki` instead of patching ad hoc.
|
|
||||||
|
|
||||||
## When NOT to use this skill
|
|
||||||
|
|
||||||
- Project has CLAUDE.md / AGENTS.md docs but no `.wiki/` — that's regular project documentation, not an LLM Wiki.
|
|
||||||
- User wants a single-file README or ADR — this skill is for persistent interlinked knowledge bases.
|
|
||||||
- One-off questions about code — use regular file reading, not wiki workflow.
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# pulling-before-work
|
|
||||||
|
|
||||||
Policy skill that pulls the current branch from `origin` once at session start
|
|
||||||
and on explicit re-sync requests. Designed to remove the "edited on stale base"
|
|
||||||
footgun without trampling dirty work-trees or auto-merging.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- **Session start** — when `CLAUDE.md` contains the line `pull remote before work` (added by `project-bootstrap` v1.4.0+).
|
|
||||||
- **In-chat** — when the user says `sync`, `resync`, `pull`, `обнови репо`, `git pull please`, or close variants.
|
|
||||||
|
|
||||||
Stays silent in non-git folders. Prints one informational line and exits in:
|
|
||||||
no `origin` remote, no upstream tracking, dirty work-tree, detached HEAD.
|
|
||||||
|
|
||||||
## What it does
|
|
||||||
|
|
||||||
`git pull --ff-only` against the configured upstream — never auto-merges, never
|
|
||||||
auto-rebases, never stashes, never commits, never pushes. On divergence it prints
|
|
||||||
a warning with manual-resolution hints and exits.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
None. The skill is a no-op outside git repos and folders without an `origin`
|
|
||||||
remote, so it's safe to leave activated everywhere.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- `project-bootstrap` (v1.4.0+) — adds the trigger line to new and existing projects' `CLAUDE.md`.
|
|
||||||
- `.wiki/concepts/pulling-before-work-design.md` (in projects bootstrapped from this repo: this design lives in `claude-skills`) — full design rationale.
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
---
|
|
||||||
name: pulling-before-work
|
|
||||||
version: 1.0.0
|
|
||||||
description: >
|
|
||||||
Pulls the current branch from origin once at session start and on explicit
|
|
||||||
re-sync requests. Use when CLAUDE.md contains the trigger line "pull remote
|
|
||||||
before work", or when the user says "sync", "resync", "pull", "обнови репо",
|
|
||||||
"git pull please", or close variants asking to refresh from the remote.
|
|
||||||
Runs `git pull --ff-only` — never auto-merges or rebases. Stays silent in
|
|
||||||
non-git folders. Prints one informational line and exits when there is no
|
|
||||||
origin remote, no upstream tracking, the working tree is dirty, or HEAD is
|
|
||||||
detached. Does not stash, commit, or push. Activated by `project-bootstrap`
|
|
||||||
v1.4.0+ via the canonical CLAUDE.md template.
|
|
||||||
---
|
|
||||||
|
|
||||||
# pulling-before-work
|
|
||||||
|
|
||||||
> Pull from `origin` once when work starts. Don't auto-merge. Don't trample dirty work-trees. Don't ask twice in the same session unless asked.
|
|
||||||
|
|
||||||
## When this runs
|
|
||||||
|
|
||||||
**At session start** — once, when the skill is activated by the `pull remote before work` line in `CLAUDE.md`. The cycle below runs immediately.
|
|
||||||
|
|
||||||
**On explicit re-sync** — when the user says any of: `sync`, `resync`, `pull`, `обнови репо`, `pull please`, `git pull`, `подтяни`, `pull from origin`. Re-runs the full cycle. There is no per-session counter; the user is always allowed to ask.
|
|
||||||
|
|
||||||
**Never** before each commit, before each tool call, on every message, or in any other implicit cadence. Mode-3 ("start + on-demand") was the explicit design choice — see `.wiki/concepts/pulling-before-work-design.md`.
|
|
||||||
|
|
||||||
## The pull cycle
|
|
||||||
|
|
||||||
Run these checks in order. Print at most one line of chat output per run.
|
|
||||||
|
|
||||||
### 1. Inside a git work-tree?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rev-parse --is-inside-work-tree 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
If the command fails or prints anything other than `true` → **exit silently, no chat output.** This is the not-a-git-repo case; the skill must not be noisy in random folders.
|
|
||||||
|
|
||||||
### 2. Has an `origin` remote?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote get-url origin 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
If the command fails (no such remote) → print one line and exit:
|
|
||||||
|
|
||||||
```
|
|
||||||
no origin remote — skip pull
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Is the working tree clean?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git status --porcelain
|
|
||||||
```
|
|
||||||
|
|
||||||
If the output is non-empty → print one line and exit:
|
|
||||||
|
|
||||||
```
|
|
||||||
working tree dirty — skipping pull. commit/stash, потом скажи "sync"
|
|
||||||
```
|
|
||||||
|
|
||||||
Never stash automatically. Stash-pop conflicts are exactly the friction this skill exists to remove.
|
|
||||||
|
|
||||||
### 4. Is HEAD attached?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git symbolic-ref -q HEAD
|
|
||||||
```
|
|
||||||
|
|
||||||
If the command fails (empty output, exit 1) → detached HEAD. Print:
|
|
||||||
|
|
||||||
```
|
|
||||||
detached HEAD — skip pull
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Does the current branch have an upstream?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
Capture the upstream name (e.g. `origin/master`). If the command fails → no upstream tracking. Print:
|
|
||||||
|
|
||||||
```
|
|
||||||
no upstream tracking for <branch> — skip pull
|
|
||||||
```
|
|
||||||
|
|
||||||
(Where `<branch>` is `git rev-parse --abbrev-ref HEAD`.)
|
|
||||||
|
|
||||||
### 6. Pull, fast-forward only
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git pull --ff-only
|
|
||||||
```
|
|
||||||
|
|
||||||
(No args — uses the configured upstream captured above.)
|
|
||||||
|
|
||||||
Classify by exit code and stdout:
|
|
||||||
|
|
||||||
| Result | Print |
|
|
||||||
|---|---|
|
|
||||||
| Already up to date | `✅ already up to date with <upstream>` |
|
|
||||||
| Fast-forward, N commits | `✅ pulled N commits from <upstream>` |
|
|
||||||
| Non-fast-forward / diverged (exit non-zero with "diverged" or "non-fast-forward" in output) | `⚠️ diverged from <upstream> — resolve manually (git pull --rebase or merge); skill never auto-merges/rebases` |
|
|
||||||
|
|
||||||
### Out of scope
|
|
||||||
|
|
||||||
The skill never:
|
|
||||||
|
|
||||||
- commits, stashes, or pushes
|
|
||||||
- recurses into submodules
|
|
||||||
- pulls from non-`origin` remotes
|
|
||||||
- pulls on detached HEAD
|
|
||||||
- runs auto-merge or auto-rebase
|
|
||||||
- runs more than once per session unless the user asks
|
|
||||||
|
|
||||||
## Recovery hints
|
|
||||||
|
|
||||||
If the skill skipped because of a dirty tree:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Windows / PowerShell
|
|
||||||
git status # see what's dirty
|
|
||||||
git add . ; git commit -m "wip"
|
|
||||||
# then ask the agent: "sync"
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Linux / macOS
|
|
||||||
git status
|
|
||||||
git add . && git commit -m "wip"
|
|
||||||
# then say "sync"
|
|
||||||
```
|
|
||||||
|
|
||||||
If the skill reported `diverged`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Option A: rebase your local commits on top of origin
|
|
||||||
git pull --rebase
|
|
||||||
|
|
||||||
# Option B: explicit merge (creates a merge commit)
|
|
||||||
git pull --no-ff
|
|
||||||
```
|
|
||||||
|
|
||||||
The skill stays out of these decisions on purpose — both options have valid use cases and the user owns the choice.
|
|
||||||
|
|
||||||
## Why this exists
|
|
||||||
|
|
||||||
Stale local branches are a silent footgun: edits land on top of yesterday's `origin`, the divergence shows up at push time, and by then there's a chunk of work to rebase or merge on the wrong base. One pull at start covers the common case; an explicit re-sync trigger handles long sessions where someone pushed mid-flight.
|
|
||||||
|
|
||||||
Full design rationale (mode choice, dirty-tree skip vs stash, `--ff-only` vs auto-merge, the upstream-check) lives in `.wiki/concepts/pulling-before-work-design.md`.
|
|
||||||
BIN
dist/browser-cdp.skill
vendored
BIN
dist/browser-cdp.skill
vendored
Binary file not shown.
BIN
dist/browser-operator.skill
vendored
Normal file
BIN
dist/browser-operator.skill
vendored
Normal file
Binary file not shown.
BIN
dist/code-search.skill
vendored
Normal file
BIN
dist/code-search.skill
vendored
Normal file
Binary file not shown.
BIN
dist/delegate-task.skill
vendored
BIN
dist/delegate-task.skill
vendored
Binary file not shown.
BIN
dist/inter-session-messaging.skill
vendored
BIN
dist/inter-session-messaging.skill
vendored
Binary file not shown.
BIN
dist/mappa-vitya-brainstorming.skill
vendored
Normal file
BIN
dist/mappa-vitya-brainstorming.skill
vendored
Normal file
Binary file not shown.
BIN
dist/mappa-vitya-project-discipline.skill
vendored
Normal file
BIN
dist/mappa-vitya-project-discipline.skill
vendored
Normal file
Binary file not shown.
BIN
dist/ops-browser.skill
vendored
Normal file
BIN
dist/ops-browser.skill
vendored
Normal file
Binary file not shown.
BIN
dist/project-bootstrap.skill
vendored
BIN
dist/project-bootstrap.skill
vendored
Binary file not shown.
BIN
dist/project-discipline.skill
vendored
BIN
dist/project-discipline.skill
vendored
Binary file not shown.
BIN
dist/pulling-before-work.skill
vendored
BIN
dist/pulling-before-work.skill
vendored
Binary file not shown.
BIN
dist/report-mappa-issue.skill
vendored
BIN
dist/report-mappa-issue.skill
vendored
Binary file not shown.
BIN
dist/review-kit-pi-method.skill
vendored
BIN
dist/review-kit-pi-method.skill
vendored
Binary file not shown.
BIN
dist/session-handoff.skill
vendored
BIN
dist/session-handoff.skill
vendored
Binary file not shown.
BIN
dist/session-health.skill
vendored
BIN
dist/session-health.skill
vendored
Binary file not shown.
BIN
dist/session-inbox-monitor.skill
vendored
BIN
dist/session-inbox-monitor.skill
vendored
Binary file not shown.
BIN
dist/task-format.skill
vendored
BIN
dist/task-format.skill
vendored
Binary file not shown.
BIN
dist/task-loop.skill
vendored
BIN
dist/task-loop.skill
vendored
Binary file not shown.
BIN
dist/update-skills.skill
vendored
BIN
dist/update-skills.skill
vendored
Binary file not shown.
BIN
dist/using-markitdown.skill
vendored
BIN
dist/using-markitdown.skill
vendored
Binary file not shown.
BIN
dist/using-system-snapshot.skill
vendored
BIN
dist/using-system-snapshot.skill
vendored
Binary file not shown.
BIN
dist/using-tasks.skill
vendored
BIN
dist/using-tasks.skill
vendored
Binary file not shown.
BIN
dist/using-wiki-graph.skill
vendored
BIN
dist/using-wiki-graph.skill
vendored
Binary file not shown.
BIN
dist/using-wiki.skill
vendored
BIN
dist/using-wiki.skill
vendored
Binary file not shown.
BIN
dist/workshop-promote-brainstorm.skill
vendored
BIN
dist/workshop-promote-brainstorm.skill
vendored
Binary file not shown.
BIN
dist/writing-skills.skill
vendored
BIN
dist/writing-skills.skill
vendored
Binary file not shown.
@@ -36,10 +36,6 @@ skills:
|
|||||||
|
|
||||||
# ─── auto (4 universals — MVP target) ────────────────────────────────
|
# ─── auto (4 universals — MVP target) ────────────────────────────────
|
||||||
|
|
||||||
pulling-before-work:
|
|
||||||
mode: auto
|
|
||||||
category: software-development
|
|
||||||
|
|
||||||
active-platform:
|
active-platform:
|
||||||
mode: auto
|
mode: auto
|
||||||
category: software-development
|
category: software-development
|
||||||
@@ -59,6 +55,14 @@ skills:
|
|||||||
mode: auto
|
mode: auto
|
||||||
category: software-development
|
category: software-development
|
||||||
|
|
||||||
|
browser-operator:
|
||||||
|
mode: auto
|
||||||
|
category: software-development
|
||||||
|
|
||||||
|
ops-browser:
|
||||||
|
mode: auto
|
||||||
|
category: software-development
|
||||||
|
|
||||||
using-markitdown:
|
using-markitdown:
|
||||||
mode: auto
|
mode: auto
|
||||||
category: productivity
|
category: productivity
|
||||||
@@ -96,18 +100,10 @@ skills:
|
|||||||
mode: auto
|
mode: auto
|
||||||
category: productivity
|
category: productivity
|
||||||
|
|
||||||
using-tasks:
|
|
||||||
mode: auto
|
|
||||||
category: productivity
|
|
||||||
|
|
||||||
setup-wiki:
|
setup-wiki:
|
||||||
mode: auto
|
mode: auto
|
||||||
category: research
|
category: research
|
||||||
|
|
||||||
using-wiki:
|
|
||||||
mode: auto
|
|
||||||
category: research
|
|
||||||
|
|
||||||
setup-projects-meta:
|
setup-projects-meta:
|
||||||
mode: manual
|
mode: manual
|
||||||
source: hermes/skills/setup-projects-meta
|
source: hermes/skills/setup-projects-meta
|
||||||
@@ -140,13 +136,6 @@ skills:
|
|||||||
|
|
||||||
# ─── pending (8 — behavioral audit required) ─────────────────────────
|
# ─── pending (8 — behavioral audit required) ─────────────────────────
|
||||||
|
|
||||||
delegate-task:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: mcp
|
|
||||||
reason: "Calls mcp__projects-meta__tasks_create to create tasks in other projects/agents (Gitea commit, cross-project side-effect). Behavioral audit via delegate-task-test-trigger required before promotion to auto."
|
|
||||||
|
|
||||||
using-yt-tools:
|
using-yt-tools:
|
||||||
mode: pending
|
mode: pending
|
||||||
intended:
|
intended:
|
||||||
@@ -161,20 +150,6 @@ skills:
|
|||||||
category: mcp
|
category: mcp
|
||||||
reason: "Calls mcp__vds-ops__* tools (read-only, but touches infrastructure). Behavioral audit via using-vds-ops-test-trigger required before promotion to auto."
|
reason: "Calls mcp__vds-ops__* tools (read-only, but touches infrastructure). Behavioral audit via using-vds-ops-test-trigger required before promotion to auto."
|
||||||
|
|
||||||
using-wiki-graph:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: mcp
|
|
||||||
reason: "Calls mcp__wiki-graph__* tools (read-only, parses a .wiki/ corpus server-side). Behavioral audit via using-wiki-graph-test-trigger required before promotion to auto."
|
|
||||||
|
|
||||||
session-handoff:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: productivity
|
|
||||||
reason: "Writes .tasks/NEXT_SESSION.md (project-scope, sliding overwrite) and reads it on session start. Bidirectional file-system side-effect, opt-in via CLAUDE.md trigger-line. Behavioral audit via session-handoff-test-trigger required before promotion to auto."
|
|
||||||
|
|
||||||
private-dev-public-publish:
|
private-dev-public-publish:
|
||||||
mode: pending
|
mode: pending
|
||||||
intended:
|
intended:
|
||||||
@@ -182,20 +157,6 @@ skills:
|
|||||||
category: software-development
|
category: software-development
|
||||||
reason: "Steps shell out to git / gh / Gitea-API, handle tokens, force-push, and repo deletion/privacy toggles — not a purely stylistic skill. Behavioral audit via private-dev-public-publish-test-trigger required before promotion to auto."
|
reason: "Steps shell out to git / gh / Gitea-API, handle tokens, force-push, and repo deletion/privacy toggles — not a purely stylistic skill. Behavioral audit via private-dev-public-publish-test-trigger required before promotion to auto."
|
||||||
|
|
||||||
task-loop:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: mcp
|
|
||||||
reason: "Orchestrates the board claim/close/update/heartbeat cycle via mcp__projects-meta__tasks_claim_next / tasks_close / tasks_update / tasks_heartbeat (cross-session claim ownership, irreversible close, Gitea side-effects) and may arm a single long ScheduleWakeup for the explicit long-watch opt-in. Critical-infra-adjacent — touches the same claim/close machinery the unattended poller relies on. Behavioral audit via task-loop-test-trigger required before promotion to auto."
|
|
||||||
|
|
||||||
session-inbox-monitor:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: productivity
|
|
||||||
reason: "Paired SessionStart hook registers itself in ~/.claude/settings.json and sweeps orphaned monitor OS processes (Get-CimInstance | Stop-Process by sentinel+inbox-path); the skill then raises an in-session Monitor on .agents/inbox/. Primary activation is the CLAUDE.md trigger-line `inbox monitor: raise on start` + the injector, not a hermes-trigger. Behavioral gate CLEARED 2026-06-17 — test-trigger + review BOTH VERDICT PASS (activation 3/3 monitor + neg clean; structural hook audit 5 PASS/1 CONCERN, the CONCERN fixed in v0.2.2). STAYS pending on two independent tool-side blockers, NOT on behavioral verification: (1) the SessionStart hook is Windows-PowerShell and needs a Linux port for Hermes factory machines; (2) machine-level side-effects (user-config mutation of ~/.claude/settings.json + Get-CimInstance|Stop-Process kills) need a tool-side audit before auto. Promotion blocked on those two, not on test-trigger/review."
|
|
||||||
|
|
||||||
inter-session-peer-discipline:
|
inter-session-peer-discipline:
|
||||||
mode: auto
|
mode: auto
|
||||||
category: meta
|
category: meta
|
||||||
@@ -220,20 +181,6 @@ skills:
|
|||||||
category: meta
|
category: meta
|
||||||
reason: "Resolves WHERE a project's meta lives before tasks_create / knowledge_ingest / brainstorm-promotion (meta-out-of-repo). Touches projects-meta MCP (tasks_create / knowledge_ingest / meta_status) and routes writes across repos. Review PASS (meta-host-routing-review) but the -install baseline is still open and a tool-side audit (cross-repo MCP writes) is required before auto. Mapping executes task meta-host-routing-hermes-mapping."
|
reason: "Resolves WHERE a project's meta lives before tasks_create / knowledge_ingest / brainstorm-promotion (meta-out-of-repo). Touches projects-meta MCP (tasks_create / knowledge_ingest / meta_status) and routes writes across repos. Review PASS (meta-host-routing-review) but the -install baseline is still open and a tool-side audit (cross-repo MCP writes) is required before auto. Mapping executes task meta-host-routing-hermes-mapping."
|
||||||
|
|
||||||
using-system-snapshot:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: mcp
|
|
||||||
reason: "Calls mcp__projects-meta__meta_system_snapshot (read-only whole-machine ops snapshot: poller / docker / cross-project task load). Read-only, same class as using-vds-ops / using-wiki-graph; pending a behavioral test-trigger before auto."
|
|
||||||
|
|
||||||
task-format:
|
|
||||||
mode: pending
|
|
||||||
intended:
|
|
||||||
mode: auto
|
|
||||||
category: productivity
|
|
||||||
reason: "Documentational skill — how to write a .tasks/STATUS.md task block the autonomous poller will claim/route/report (block header, status emoji, Weight/Notify/Requirements fields). No tool-side effects; pending a behavioral test-trigger before auto."
|
|
||||||
|
|
||||||
setup-agents-task-runner:
|
setup-agents-task-runner:
|
||||||
mode: pending
|
mode: pending
|
||||||
reason: "L2 installer — installs the standing-duty stack (agents-task-runner + watchdog + appeals-inbox) as platform-native OS services (systemd/launchd/winsw), fetches a pinned binary, writes poller-scope.json. Heavy infra side-effects (OS services + binary fetch); mode decision (skip vs manual vs auto) deferred — needs an explicit Hermes-factory applicability audit. Placeholder pending to keep the build green."
|
reason: "L2 installer — installs the standing-duty stack (agents-task-runner + watchdog + appeals-inbox) as platform-native OS services (systemd/launchd/winsw), fetches a pinned binary, writes poller-scope.json. Heavy infra side-effects (OS services + binary fetch); mode decision (skip vs manual vs auto) deferred — needs an explicit Hermes-factory applicability audit. Placeholder pending to keep the build green."
|
||||||
@@ -241,3 +188,47 @@ skills:
|
|||||||
ralph-loop-execution:
|
ralph-loop-execution:
|
||||||
mode: pending
|
mode: pending
|
||||||
reason: "Behavioral oracle-loop skill (Verifier / Attempts / Max-Attempts retry loop). NB: source SKILL.md currently lacks YAML frontmatter (no name/description) — cannot auto-convert cleanly until that is fixed. Mapped pending as a placeholder; needs frontmatter + a behavioral audit before any mode decision."
|
reason: "Behavioral oracle-loop skill (Verifier / Attempts / Max-Attempts retry loop). NB: source SKILL.md currently lacks YAML frontmatter (no name/description) — cannot auto-convert cleanly until that is fixed. Mapped pending as a placeholder; needs frontmatter + a behavioral audit before any mode decision."
|
||||||
|
|
||||||
|
# ─── mappa-skill-suite (7, pending — behavioral audit via mappa-skill-suite-review) ───
|
||||||
|
mappa-messaging:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: communication
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
mappa-knowledge:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: research
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
mappa-brainstorm-promote:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: meta
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
mappa-delegation:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: mcp
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
mappa-task-work:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: productivity
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
mappa-closing-ritual:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: productivity
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
mappa-session-orient:
|
||||||
|
mode: pending
|
||||||
|
intended:
|
||||||
|
mode: auto
|
||||||
|
category: productivity
|
||||||
|
reason: "Calls mcp__mappa__* tools (board/wiki/inbox/handoff/sessions). Behavioral audit via mappa-skill-suite-review required before promotion to auto."
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ function New-SkillArchive {
|
|||||||
[System.IO.Compression.ZipArchiveMode]::Create
|
[System.IO.Compression.ZipArchiveMode]::Create
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
$files = Get-ChildItem -Path $sourceFull -Recurse -File
|
$files = Get-ChildItem -Path $sourceFull -Recurse -File | Where-Object { $_.FullName -notmatch '__pycache__' }
|
||||||
foreach ($file in $files) {
|
foreach ($file in $files) {
|
||||||
$rel = $file.FullName.Substring($sourceFull.Length + 1) -replace '\\','/'
|
$rel = $file.FullName.Substring($sourceFull.Length + 1) -replace '\\','/'
|
||||||
$entryName = "$SkillName/$rel"
|
$entryName = "$SkillName/$rel"
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
---
|
---
|
||||||
name: browser-cdp
|
name: browser-cdp
|
||||||
author: ours
|
author: ours
|
||||||
version: 0.1.0
|
version: 0.1.1
|
||||||
description: >
|
description: >
|
||||||
Веб-автоматизация через минимальные CDP CLI-тулы в bash — вместо playwright-mcp
|
Веб-автоматизация через минимальные CDP CLI-тулы в bash — вместо playwright-mcp
|
||||||
/ Chrome-DevTools-MCP (подход «what if you don't need MCP»). Запуск Chrome с remote
|
/ Chrome-DevTools-MCP (подход «what if you don't need MCP»). Запуск Chrome с remote
|
||||||
debugging, навигация, eval JS, скриншоты. Trigger: «браузер», «скрейпинг», «открой
|
debugging, навигация, eval JS, скриншоты. Trigger: «браузер», «скрейпинг», «открой
|
||||||
страницу», «перейди на», «сделай скриншот», «playwright», «веб-автоматизация»,
|
страницу», «перейди на», «сделай скриншот», «playwright», «веб-автоматизация»,
|
||||||
«web scraping», «browser».
|
«web scraping», «browser». Для ЛИЧНЫХ КАБИНЕТОВ оператора (его логины, антибот) —
|
||||||
|
НЕ этот скил, а `browser-operator`.
|
||||||
---
|
---
|
||||||
|
|
||||||
# browser-cdp
|
# browser-cdp
|
||||||
@@ -20,6 +21,9 @@ description: >
|
|||||||
снять скриншот, собрать данные (скрейпинг). Использовать **вместо** playwright-mcp или
|
снять скриншот, собрать данные (скрейпинг). Использовать **вместо** playwright-mcp или
|
||||||
Chrome-DevTools-MCP.
|
Chrome-DevTools-MCP.
|
||||||
|
|
||||||
|
- ⚠️ **Для личных кабинетов оператора этот путь НЕ годится:** здесь свой Chrome и свой
|
||||||
|
профиль (без его логинов). Нужен браузер оператора — скил `browser-operator`.
|
||||||
|
|
||||||
## Процесс
|
## Процесс
|
||||||
|
|
||||||
1. **Прочитай полную справку** (обязательно, первый шаг):
|
1. **Прочитай полную справку** (обязательно, первый шаг):
|
||||||
|
|||||||
128
skills/browser-operator/SKILL.md
Normal file
128
skills/browser-operator/SKILL.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
name: browser-operator
|
||||||
|
author: ours
|
||||||
|
version: 0.1.0
|
||||||
|
description: >
|
||||||
|
Работа в браузере ОПЕРАТОРА — его Chrome, его профиль, его живые логины: личные
|
||||||
|
кабинеты поставщиков (ЧипДип, ДКО, Промэлектроника, ТМ), Avito, порталы под
|
||||||
|
антиботом. Trigger: «зайди в личный кабинет», «открой ЛК», «собери заказы»,
|
||||||
|
«посмотри в браузере», «нужна его сессия», «ЧипДип/Ozon/Avito», «browser».
|
||||||
|
НЕ для публичных страниц (там сначала обычный fetch/curl) и НЕ для анонимных
|
||||||
|
прогонов (там скил browser-cdp).
|
||||||
|
---
|
||||||
|
|
||||||
|
# Browser operator — браузер оператора
|
||||||
|
|
||||||
|
**Браузер оператора — разделяемый ресурс с его живыми сессиями.** Работай через
|
||||||
|
готовый канал своего харнесса и **только под арендой «один водитель за раз»**.
|
||||||
|
Не вытаскивай его куки, не логинься сам, не поднимай свой Chrome.
|
||||||
|
|
||||||
|
## Когда браузер действительно нужен
|
||||||
|
|
||||||
|
Сначала спроси себя, нужен ли браузер вообще:
|
||||||
|
|
||||||
|
- **Нет** — публичная страница, API, доки: обычный fetch/curl/поиск. Браузер тут лишний.
|
||||||
|
- **Да** — страница требует взаимодействия (клик/форма/навигация), JS-рендер,
|
||||||
|
**его логин** (личный кабинет, Avito), либо портал режет не-браузерный трафик.
|
||||||
|
|
||||||
|
## Канал по харнессу (не изобретай свой)
|
||||||
|
|
||||||
|
| Харнесс | Чем работать | Аренда |
|
||||||
|
|---|---|---|
|
||||||
|
| **Hermes** | тул `browser_exec` (демон `browser-use`, тот же профиль оператора) | автоматически: shell-хук `pre_tool_call` берёт аренду и блокирует вызов при чужой |
|
||||||
|
| **pi** | тул `browser`: `open` / `read` / `js` / `click` / `screenshot` / `lease` | автоматически внутри тула; `lease` покажет, кто держит |
|
||||||
|
| **Claude Code** | MCP `chrome-devtools` (`list_pages`, `navigate_page`, `take_snapshot`, `evaluate_script`, `click`, `fill`, `take_screenshot`) | автоматически: обёртка берёт аренду перед стартом сервера |
|
||||||
|
|
||||||
|
**Никогда:** `curl` с куками из его профиля, `browser_cookie3`-выгрузка куки,
|
||||||
|
свой `chrome --remote-debugging-port` с пустым профилем (там нет его логинов),
|
||||||
|
`pip install`-стек ради одного кабинета.
|
||||||
|
|
||||||
|
## Аренда: «один водитель в браузере за раз»
|
||||||
|
|
||||||
|
Браузер один. Если его держит другой харнесс — **не ломиться**, сказать «занято,
|
||||||
|
держит X» и вернуться позже (или попросить оператора освободить).
|
||||||
|
|
||||||
|
Идёшь в браузер **в обход** тула (например, скриптом или `browser-use` из терминала) —
|
||||||
|
бери аренду сам:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
BL="$HOME/.config/browser-harness/bin/browser-lease.sh"
|
||||||
|
HOLD="manual:$$" # метка держателя
|
||||||
|
MYPID="$(cat /proc/$$/winpid 2>/dev/null || echo 0)" # НАСТОЯЩИЙ windows-PID
|
||||||
|
bash "$BL" acquire --holder "$HOLD" --ttl 900 --pid "$MYPID" --tool browser # 0 = взял, 3 = занято, 2 = ошибка
|
||||||
|
# … работа …
|
||||||
|
bash "$BL" release --holder "$HOLD"
|
||||||
|
```
|
||||||
|
|
||||||
|
**PID — только настоящий.** MSYS `$$` это НЕ windows-PID: по нему живость аренды врёт
|
||||||
|
(мёртвый держатель выглядит живым, живой — мёртвым). В bash бери `/proc/$$/winpid`,
|
||||||
|
в pi/Node — `process.pid`; не знаешь — передай `0` («неизвестен», живость решит TTL).
|
||||||
|
|
||||||
|
**`driver.lock` руками не трогай** (в том числе пустой или «битый» — это окно чужой
|
||||||
|
записи): отбор мёртвой аренды делает CLI по `ts`/TTL/мёртвому PID. Чужую аренду не снимай.
|
||||||
|
|
||||||
|
Контракт аренды (формат файла, TTL, кого связывать): вики mappa
|
||||||
|
`concepts/browser-lease-contract`.
|
||||||
|
|
||||||
|
## Как работать в страницах (рецепты)
|
||||||
|
|
||||||
|
- **Первым делом — своя вкладка.** `ensure_real_tab()` / `new_tab(url)`; не полагайся
|
||||||
|
на активную вкладку оператора: тяжёлая или аудио-страница подвешивает демон
|
||||||
|
(все вызовы падают в таймаут, хотя `browser-use --doctor` говорит «alive»).
|
||||||
|
- **Тяжёлые страницы — читать изнутри, а не обходом.** Если у сайта есть внутренний
|
||||||
|
JSON-эндпоинт, зови его `fetch(path, {credentials:'include'})` из уже открытой
|
||||||
|
страницы: это быстрее и надёжнее десятков навигаций.
|
||||||
|
- **По одной штуке за раз, с паузами.** Паузы — в Python/процессе, **не** в JS `await`
|
||||||
|
(иначе `Runtime.evaluate timed out`). Ориентир оператора: 1 запрос, пауза 7–13 с,
|
||||||
|
перекур каждые ~40, стоп после 3 ошибок подряд.
|
||||||
|
- **Клики:** сначала дерево доступности (`Accessibility.getFullAXTree`) или
|
||||||
|
`querySelector` → центр элемента (`getBoundingClientRect`) → `click_at_xy` → **проверь
|
||||||
|
результат** отдельным `js(...)`/`page_info()`. Не кликай «на глаз» по скриншоту.
|
||||||
|
- **Прогресс — сразу на диск** (jsonl/atomic), а не в конце прогона: длинные обходы
|
||||||
|
обрываются.
|
||||||
|
- **Долгие обходы** — в фоновый процесс, а не в цикл интерактивных вызовов.
|
||||||
|
|
||||||
|
## Границы: где человек, а где агент
|
||||||
|
|
||||||
|
- **Пароли и второй фактор — никогда.** Не вводим и не просим в аргументах командной
|
||||||
|
строки. Уже залогиненная сессия оператора — вот твой доступ.
|
||||||
|
- **Попап «Разрешить удалённую отладку?»** — это человеческое подтверждение: агент его
|
||||||
|
не жмёт, а просит оператора нажать «Разрешить» и повторяет попытку.
|
||||||
|
- **Деньги/платежи/отправка форм с персональными данными** — только с явным
|
||||||
|
подтверждением оператора.
|
||||||
|
- **Секреты и содержимое залогиненных страниц** не пишем в логи, файлы репозитория и
|
||||||
|
вики: в mappa — только агрегаты и идентификаторы.
|
||||||
|
|
||||||
|
## Проверенные адреса и факты
|
||||||
|
|
||||||
|
- **ЧипДип, кабинет заказов:** `https://www.chipdip.ru/order/list`
|
||||||
|
(⚠️ `/cabinet` и `/orders` отдают 404 — не перебирай наугад, ссылка есть в шапке).
|
||||||
|
- Залогиненность видна в шапке кабинета (имя оператора); если видишь форму логина —
|
||||||
|
**сессия потеряна: стоп и скажи оператору**, не логинься сам.
|
||||||
|
- `about:blank`-вкладка с титулом-лошадкой в `document.title` = страницу ведёт агент.
|
||||||
|
|
||||||
|
## Так делать НЕ надо
|
||||||
|
|
||||||
|
| Соблазн | Почему нет |
|
||||||
|
|---|---|
|
||||||
|
| «Вытащу куки из Chrome и пойду `curl`'ом» | мимо канала и мимо аренды; пароль/2FA оказываются рядом; ломается при смене защиты |
|
||||||
|
| «Подниму свой Chrome с отладкой» | там **нет** его логинов → выкинет на логин/капчу, плюс это второй водитель |
|
||||||
|
| «Введу логин/пароль через `read -s`» | пароли и 2FA не вводим никогда |
|
||||||
|
| «Проверю ещё пяток URL кабинета» | адрес подтверждай по ссылке в интерфейсе, а не перебором |
|
||||||
|
| «Налью 20 запросов параллельно, быстрее» | антибот + оператор останавливает такие прогоны; один водитель, одна очередь |
|
||||||
|
|
||||||
|
Основание: базовый прогон без скила (2026-09-11) ушёл именно в «куки + curl + пароль»
|
||||||
|
мимо канала; скил закрывает этот путь.
|
||||||
|
|
||||||
|
## Красные флаги (стоп и перечитай)
|
||||||
|
|
||||||
|
- Собираешься вытащить куки / поднять свой браузер / ввести пароль или код.
|
||||||
|
- Работаешь с браузером **без** аренды (или ломишься, когда «занято»).
|
||||||
|
- Полливаешь запросами без паузы или ждёшь паузу в JS.
|
||||||
|
- Пишешь содержимое залогиненных страниц/секреты в файл, лог или вики.
|
||||||
|
|
||||||
|
## Вне скоупа
|
||||||
|
|
||||||
|
- Анонимные/антидетект-прогоны, свой профиль, `mode: fresh` — скил `browser-cdp`.
|
||||||
|
- Облачные браузеры (Browser Use Cloud и прочие) — не берём.
|
||||||
|
- Свой stdio-MCP-сервер поверх общего демона — отдельная тема.
|
||||||
98
skills/code-search/SKILL.md
Normal file
98
skills/code-search/SKILL.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
---
|
||||||
|
name: code-search
|
||||||
|
author: ours
|
||||||
|
version: 0.1.0
|
||||||
|
description: >
|
||||||
|
Use when searching code for strings, symbols, or usages — "find where X is
|
||||||
|
used", «найди, где используется», "grep for X", "where is X", "search the
|
||||||
|
repo for", any code search, or when deciding HOW to search a codebase. One
|
||||||
|
hard rule: in any tree that can contain node_modules/dist/build/.nuxt,
|
||||||
|
search with `rg` (gitignore-aware) — NEVER `grep -r` (`--include` filters
|
||||||
|
file names, not directory traversal; grep walks every node_modules entry:
|
||||||
|
measured 15+ min never-finishing vs rg 0s on the same tree). Routes:
|
||||||
|
string/symbol search → rg; tracked-files-only → git grep; whole-repo
|
||||||
|
comprehension ("what does module Y do") → interns repo_read (ask-mode);
|
||||||
|
N×M contains audits → interns grep_audit. Skip for web search
|
||||||
|
(web-search), vault search (coworker-search), already-fast tools.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Code Search
|
||||||
|
|
||||||
|
Search code with the fastest correct tool for the question class. The default
|
||||||
|
`grep -r` habit is the single biggest time sink in agent work on npm/JS
|
||||||
|
projects — the fix is a different binary, not more patience.
|
||||||
|
|
||||||
|
## When to use
|
||||||
|
|
||||||
|
- Any "where is X used / where does X appear / search the repo for X" request.
|
||||||
|
- Deciding HOW to search: rg vs git grep vs intern delegation.
|
||||||
|
- A search that "feels slow" — that is a wrong-tool signal, not a slow disk.
|
||||||
|
|
||||||
|
## When NOT to use
|
||||||
|
|
||||||
|
- Web search → `web-search` skill.
|
||||||
|
- Searching the .cowork vault / memory vault → `coworker-search`.
|
||||||
|
- A question ABOUT the code ("what does module Y do", "how does the build work") → `interns.repo_read` (delegation, ask-mode per `using-interns`).
|
||||||
|
- The right tool is already running and fast.
|
||||||
|
|
||||||
|
## Core rule (one sentence)
|
||||||
|
|
||||||
|
**In any tree that can contain `node_modules` / `dist` / `build` / `.nuxt` / `vendor`, search with `rg`, never `grep -r`.**
|
||||||
|
|
||||||
|
Why — measured on `stostayer.new`, `packages/web` + `apps/web4`, 2026-08-26:
|
||||||
|
|
||||||
|
| Fact | Value |
|
||||||
|
|---|---|
|
||||||
|
| Total files in the two dirs | 113,169 |
|
||||||
|
| Of which in `node_modules` + `.nuxt` + `build` | 109,248 (**96%**) |
|
||||||
|
| `grep -rn "3590" … --include=*.vue --include=*.js … -l` | **> 15 min, never finished** (RED run: fresh unprompted agent spawned 2× `/usr/bin/grep`, still running at 200s, killed) |
|
||||||
|
| `rg -l "3590" …` (same globs) | **0s**, 3 matches |
|
||||||
|
| `rg --no-ignore "3590" …` (forced full scan incl. node_modules) | 16s |
|
||||||
|
|
||||||
|
Mechanics: `grep -r --include` filters which **file names** get read — it does
|
||||||
|
NOT stop **directory traversal**. grep stats/opens every directory entry
|
||||||
|
including node_modules (100k+ files) on every search. `rg` reads `.gitignore`
|
||||||
|
(+ `.ignore`, `.rgignore`) and skips ignored trees by default — zero flags
|
||||||
|
needed. It is already installed on this machine (ripgrep 15.x).
|
||||||
|
|
||||||
|
## Routing table
|
||||||
|
|
||||||
|
| Question class | Tool | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Find string/symbol/usages in the working tree | `rg -n "pattern" <paths>` | gitignore-aware out of the box. `-l` → filenames only. `-g '*.ext'` to filter. |
|
||||||
|
| Only tracked files (clean, deterministic) | `git grep -n "pattern"` | uses the git index; ignores untracked + ignored. Always present even on bare boxes. |
|
||||||
|
| "I really must scan generated/vendored too" | `rg --no-ignore` | 16s on the 113k-file tree — still ~50× faster than grep. Never `grep -r` even here. |
|
||||||
|
| Whole-repo comprehension ("what does module Y do", "where is X used across the architecture") | `interns.repo_read` | delegation — ask-mode, `using-interns` skill. Packs via repomix + cheap LLM. |
|
||||||
|
| N×M contains/not-contains audit (canonical strings across many files) | `interns.grep_audit` | deterministic, no LLM call. |
|
||||||
|
|
||||||
|
## Common mistakes / rationalizations
|
||||||
|
|
||||||
|
| Excuse | Reality |
|
||||||
|
|---|---|
|
||||||
|
| "grep works, just slow" | Wrong tool. rg is a drop-in replacement on the same globs: 15 min → 0s on the same tree. |
|
||||||
|
| "--include excludes node_modules" | **False.** `--include` filters file *names* that get read, not directories *walked*. grep still traverses all 100k+ node_modules entries. |
|
||||||
|
| "Windows/Defender is just slow" | The disk is not the problem — 96% of walked files are build artifacts. rg skips them via .gitignore before the filesystem ever opens them. |
|
||||||
|
| "I need to search EVERYTHING" | Use `rg --no-ignore` (16s), still not grep (15 min). Scope with `-g '!node_modules'` if noise is the issue. |
|
||||||
|
| "rg isn't installed here" | It is (ripgrep 15.2.0). On a bare box fall back to `git grep` — git is always present. |
|
||||||
|
| "It's a one-off, speed doesn't matter" | One-off searches happen 10+ times per session. Each 15-min grep burns an entire agent turn for nothing. |
|
||||||
|
|
||||||
|
## Red flags (STOP)
|
||||||
|
|
||||||
|
- A search command starting with `grep -r` in any JS/TS/node project — rewrite to `rg` before running.
|
||||||
|
- A grep that "hasn't returned" after 30s — it is walking node_modules; kill it, use rg.
|
||||||
|
- Search results containing `node_modules/` / `.nuxt/` / `dist/` paths — you scanned garbage; redo with rg (ignore-aware).
|
||||||
|
- Writing `--include` and believing directories are excluded.
|
||||||
|
|
||||||
|
## Cross-agent applicability
|
||||||
|
|
||||||
|
Tool-level rule, works in any agent that can run shell commands (pi, claude,
|
||||||
|
codex exec, hermes). `rg` or `git grep` are the always-available core; the
|
||||||
|
intern rows are optional delegation for a local `interns` MCP
|
||||||
|
(`using-interns` skill). The core rule stands alone without them.
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
|
||||||
|
- Semantic code search / index servers (zoekt, sourcegraph, codesearch) — YAGNI; rg removes the pain without infrastructure.
|
||||||
|
- Searching non-code stores (vaults, wikis, the web).
|
||||||
|
- Teaching rg's full flag surface — `rg --help` / man.
|
||||||
|
- mappa internals: code search stays client-side (operator decision 2026-08-25 — "rg-мост по чек-аутам", outside mappa).
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
---
|
|
||||||
name: delegate-task
|
|
||||||
author: ours
|
|
||||||
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
|
|
||||||
pair: tasks_create + covering letter to the recipient's inbox (event:
|
|
||||||
created) — a task on the board does not ping a live session. Triggers:
|
|
||||||
«делегировать таску», «delegate task», «создать задачу на агента»,
|
|
||||||
«поставить задачу агенту», «tasks_create для». Does NOT apply to
|
|
||||||
self-assigned tasks on your own board («создать задачу себе», «task for
|
|
||||||
myself», «поставить себе задачу» → using-tasks), to work you do yourself,
|
|
||||||
or to workshop-internal tasks.
|
|
||||||
---
|
|
||||||
|
|
||||||
# delegate-task
|
|
||||||
|
|
||||||
Унифицированный формат постановки задач на агентов через `mcp__projects-meta__tasks_create`. Обеспечивает что каждая делегированная задача содержит: обязательные скилы (императивный invoke), pre-flight разрешения, steering-loop поля (notify/weight/allow_upgrade).
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
Перед каждым вызовом `mcp__projects-meta__tasks_create` для другого проекта или агента.
|
|
||||||
|
|
||||||
**Активируется:** «делегировать таску», «delegate task», «создать задачу на агента», «поставить задачу агенту», «tasks_create для».
|
|
||||||
|
|
||||||
**Не применяется:**
|
|
||||||
- Работа которую выполняешь сам в текущей сессии.
|
|
||||||
- Self-assigned таски на своей доске («создать задачу себе», «task for myself», «поставить себе задачу») → `using-tasks`, не делегирование. Дизамбигуатор: «на агента»/«агенту»/«в проект X» = делегирование; «себе»/«myself» = своя доска.
|
|
||||||
- Workshop-internal таски (`.workshop/.tasks/` — workshop-meta, не делегирование).
|
|
||||||
- `tasks_create` с `target=agenda` (cross-project agenda — не делегирование агенту).
|
|
||||||
|
|
||||||
## Inputs
|
|
||||||
|
|
||||||
- `target_project` — qualified `<owner>/<repo>` (обязательно)
|
|
||||||
- `slug` — kebab-case latin
|
|
||||||
- Краткое описание задачи (цель + acceptance criteria)
|
|
||||||
- `weight` — `cheap-ok | needs-claude | needs-human`
|
|
||||||
- `notify` — slug проекта-комиссионера (кому писать inbox при close/park)
|
|
||||||
- `allow_upgrade` — `true/false` (опционально; разрешить ли fallback на tier выше если нет matching backend)
|
|
||||||
|
|
||||||
Номер задаче присваивает сервер (`tasks_create` из счётчика `OpeItcLoc03/agenda/task-counter`) — постановщик номер не придумывает и не резервирует. Возвращённый `#n` из preview/confirm — машинный ключ задачи: им ссылаются блокеры, письма, decision-trail.
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
### 1. Pre-flight gate (6 вопросов пользователю)
|
|
||||||
|
|
||||||
Спросить **до** составления тела задачи:
|
|
||||||
|
|
||||||
0. **Критическая инфраструктура?** — задача меняет: поллер/агент-раннер, MCP серверы (projects-meta, interns), механизм claim/close/heartbeat, deploy-инфру (traefik, docker, systemd), CI/CD пайплайны, git hooks.
|
|
||||||
- Если **да** → `weight: needs-human` принудительно, без обсуждения. Объяснить пользователю почему.
|
|
||||||
- Если **нет** → идти дальше.
|
|
||||||
1. **Интерны — разрешены?** (да/нет, per задача)
|
|
||||||
2. **Автопуш — разрешён?** (да/нет, per задача)
|
|
||||||
3. **Контекстные скилы сверх дефолтов?** — предложить по содержанию задачи (например `claude-api` для работы с Anthropic SDK, `frontend-design` для UI, `using-interns` если интерны разрешены), пользователь утверждает.
|
|
||||||
4. **notify — кому докладывать о завершении/затыке?** (slug проекта; обычно `.workshop` или `OpeItcLoc03/workshop`)
|
|
||||||
5. **Session-break после этой задачи?** — нужен ли разрыв сессии после её закрытия (domain-switch, milestone, heavy infra)?
|
|
||||||
- Если **да** → проставить `session_break` в теле задачи (см. шаблон): `true` или строка-hint с названием следующего трека. `using-tasks` остановится после close и предложит завершить сессию, не клеймя следующую задачу.
|
|
||||||
- Если **нет** → поле не добавлять (дефолт — агент продолжает `claim-next`).
|
|
||||||
|
|
||||||
### 2. Составить тело задачи по шаблону
|
|
||||||
|
|
||||||
Секции строго по порядку:
|
|
||||||
|
|
||||||
```
|
|
||||||
<Цель — одно-два предложения. Acceptance criteria если есть.>
|
|
||||||
**Спека:** <path к design-решению или .brainstorm/…> — обязательно для задач
|
|
||||||
из дизайна/решения: импл читает дизайн, не угадывает
|
|
||||||
|
|
||||||
## Обязательные скилы — вызвать до начала работы
|
|
||||||
|
|
||||||
- invoke `tdd-criteria` — до написания кода
|
|
||||||
- invoke `using-tasks` — для управления статусом задачи
|
|
||||||
- invoke `project-discipline` — дисциплина коммитов/пушей
|
|
||||||
- invoke `using-wiki` после закрытия — заингесть .wiki/concepts/<slug>.md
|
|
||||||
[если кросс-проектная: - invoke `using-projects-meta` — cross-project tasks/wiki]
|
|
||||||
[контекстные скилы из шага 1.3]
|
|
||||||
|
|
||||||
**TDD:** да | нет — <причина>
|
|
||||||
**Разрешения:** интерны: да/нет | автопуш: да/нет
|
|
||||||
**weight:** cheap-ok | needs-claude | needs-human
|
|
||||||
**notify:** <commissioning-project-slug>
|
|
||||||
[**allow_upgrade:** true/false]
|
|
||||||
[**session_break:** true | "<следующий трек / hint>"] # optional — using-tasks остановится после close, не клеймит следующую задачу
|
|
||||||
```
|
|
||||||
|
|
||||||
**Когда ставить `session_break`** (опционально; по умолчанию НЕ ставить — это маркер реальной границы, не дефолт). Три случая:
|
|
||||||
|
|
||||||
1. **Смена домена / репо** — задача завершает один трек перед переходом на несвязанный.
|
|
||||||
2. **Milestone-задача** — последняя в группе sub-tasks одной фичи.
|
|
||||||
3. **Тяжёлая инфра-задача** — shared checkout, migrations, deploy — где разумно остановиться и проверить состояние.
|
|
||||||
|
|
||||||
Значение: `true` (следующий трек = «см. STATUS.md») либо строка-hint с названием следующего трека. Потребитель — `using-tasks` v1.2.0+ (Task completion step 6): после close печатает `🔚 SESSION BOUNDARY …` и останавливается, не клеймя следующую задачу. Дизайн: `.wiki/concepts/delegate-task-session-break.md`.
|
|
||||||
|
|
||||||
**Этапные цепочки (staged breakdown):** если решение бьётся на этапы
|
|
||||||
(1 → 1b → 3), создавай каждый этап отдельной таской со `status: blocked` +
|
|
||||||
`blocker: <номера-предшественников> (#n1, #n2 — номера, не слаги; номер =
|
|
||||||
машинный ключ)`. Доска показывает порядок, поллер не возьмёт зависимую
|
|
||||||
работу раньше времени. Таски в один репо создавай последовательно, не
|
|
||||||
параллельно (иначе sha-lock конфликт — см. Failure modes).
|
|
||||||
|
|
||||||
**Почему `invoke` а не триггер-фраза:** AGENTS.md ненадёжен (уплывает при compression, слабые модели игнорируют). Тело задачи читается активно — императив `invoke` это прямая команда, не пассивный матчинг.
|
|
||||||
|
|
||||||
### 3. Dry-run preview
|
|
||||||
|
|
||||||
`tasks_create(confirm=false)` — показать пользователю preview до реального коммита.
|
|
||||||
|
|
||||||
### 4. Подтверждение и создание
|
|
||||||
|
|
||||||
После OK пользователя: `tasks_create(confirm=true)`.
|
|
||||||
|
|
||||||
### 5. Сопроводительное письмо — обязательно при кросс-проектной делегации
|
|
||||||
|
|
||||||
После создания **каждая кросс-проектная делегация** дублируется письмом в
|
|
||||||
инбокс получателя (канон — `inter-session-messaging` v2: канал Mappa, адрес
|
|
||||||
из адресной книги `~/projects/.wiki/concepts/projects-address-book.md`):
|
|
||||||
|
|
||||||
```
|
|
||||||
mcp__mappa__inbox_send(
|
|
||||||
project: <адрес-получателя>, # имя папки, из адресной книги
|
|
||||||
from: <своя-папка>,
|
|
||||||
subject: "[event: created] #n slug",
|
|
||||||
body: "1-2 строки — что за задача, почему, slug; «разбери и возьми»"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
(Мутация тасок гейтится лизом проекта — `task_claim_next`; доставка письма —
|
|
||||||
карв-аут, лиза не требует.)
|
|
||||||
|
|
||||||
Причина: таска на борде **не пингует живую сессию** получателя. Поллер
|
|
||||||
подхватит по `Weight`/`Notify`, но живая интерактивная сессия узнаёт только
|
|
||||||
через inbox-монитор — т.е. через письмо. Правило «task + letter, не только
|
|
||||||
task» — общий случай (шаг 7 — его частность для downstream-задач).
|
|
||||||
|
|
||||||
Пропуск: self-assigned задачи на своей доске; `target=agenda` (общая доска,
|
|
||||||
конкретного получателя нет — steering-loop через `Notify`).
|
|
||||||
|
|
||||||
### 6. Парная review-таска (только для impl-задач)
|
|
||||||
|
|
||||||
Если задача имплементационная — создать парную `<slug>-review` (status=blocked, blocker=`#n` — номер impl-таски). Пропустить для: pointers-тасок, ops-тасок, research-тасок, любых non-impl.
|
|
||||||
|
|
||||||
**`weight` review-таски — наследовать от impl-таски, но не ниже `needs-claude`** (проставлять явно при `tasks_create`):
|
|
||||||
|
|
||||||
- impl `needs-human` → review `needs-human` (критично-инфраструктурное изменение нельзя ревьюить слабым tier'ом — ревью наследует строгость impl).
|
|
||||||
- impl `needs-claude` → review `needs-claude`.
|
|
||||||
- impl `cheap-ok` → review `needs-claude` (флор: review дисциплинарно-критична, см. What NOT to do — cheap-ok сюда не опускать).
|
|
||||||
|
|
||||||
Без явного `weight` поллер не маршрутизирует review-таску (reconciler её пропускает) — поэтому проставлять всегда, даже когда impl и review совпадают по tier'у.
|
|
||||||
|
|
||||||
### 7. Downstream-задача для ЖИВОЙ сессии → требовать task + inbox-письмо
|
|
||||||
|
|
||||||
Если тело задачи **поручает агенту самому создать downstream-задачу** для другого проекта, где работает **живая интерактивная сессия** (напр. прог сам ставит deploy-таску админу), — в ТЗ **явно потребуй И `tasks_create`, И inbox-письмо** тому проекту (`mcp__mappa__inbox_send(project=<target>, from=<своя>, subject="[event: created] #n slug", ...)`).
|
|
||||||
|
|
||||||
Причина: таска на борде живую сессию **НЕ пингует**. Поллер подхватит по `Weight`/`Notify`, но живая интерактивная сессия узнаёт только через inbox-монитор / Stop-хук — т.е. через письмо. ТЗ, требующее лишь `tasks_create`, оставляет downstream-таску висеть незамеченной, и кто-то доделывает пинг руками.
|
|
||||||
|
|
||||||
Правило: poller-driven таргет → `Weight`/`Notify` обязательны; live-сессия → inbox-письмо обязательно; **не уверен, поллер или живой — требуй ОБА.** Это же правило применяй, когда пингуешь пира сам: task + letter, не только task.
|
|
||||||
|
|
||||||
## Failure modes
|
|
||||||
|
|
||||||
- **Пользователь отказывает на pre-flight** → abort, задачу не создавать.
|
|
||||||
- **Пользователь отклоняет dry-run preview** → abort.
|
|
||||||
- **notify не указан** → переспросить, не пропускать молча. Без notify steering-loop не замыкается.
|
|
||||||
- **weight не указан** → переспросить. Без weight поллер не знает кому отдать задачу.
|
|
||||||
- **tasks_create упал** → различить: **PushRejected** (sha-lock конфликт —
|
|
||||||
репо уехало между preview и confirm; бывает при параллельном создании в один
|
|
||||||
репо) → **retry**: повторить confirm — сервер перечитает актуальный base_sha.
|
|
||||||
Другие ошибки → сообщить пользователю, не делать retry без явного запроса.
|
|
||||||
|
|
||||||
## Side effects
|
|
||||||
|
|
||||||
- Создаёт таску в target-проекте через `mcp__projects-meta__tasks_create` (Gitea commit).
|
|
||||||
- Опционально создаёт парную review-таску (status=blocked).
|
|
||||||
|
|
||||||
## What NOT to do
|
|
||||||
|
|
||||||
- Не пропускать pre-flight gate — даже если кажется что всё очевидно.
|
|
||||||
- Не использовать пассивные триггер-фразы вместо `invoke` — «tdd-criteria» в тексте слабее чем «invoke `tdd-criteria`».
|
|
||||||
- Не пропускать `notify` — без него boss не узнает о завершении.
|
|
||||||
- Не пропускать `weight` — без него fleet routing слеп.
|
|
||||||
- Не создавать review-таску для pointers/ops/research задач — только для impl.
|
|
||||||
- Не создавать review-таску без `weight` — reconciler/поллер её пропустит. Наследовать от impl, флор `needs-claude` (см. Step 6).
|
|
||||||
- Не назначать `weight: cheap-ok` для задач где дисциплина критична (review, security, schema migration) — слабые модели могут игнорировать invoke-инструкции.
|
|
||||||
- Не назначать `weight: needs-claude` или `cheap-ok` задачам, меняющим критическую инфраструктуру (поллер, MCP серверы, deploy, CI/CD) — только `needs-human`.
|
|
||||||
- Не ставить `session_break` рутинно на каждую задачу — это маркер реальной границы (domain-switch / milestone / heavy infra), не дефолт; иначе `using-tasks` рвёт сессию после каждого close.
|
|
||||||
- **Не создавать задачи из дизайна/решения без `**Спека:**`-ссылки** —
|
|
||||||
импл-агент угадывает пороги/скоуп вместо чтения дизайна.
|
|
||||||
- **Не создавать несколько тасок в один репо параллельно** — sha-lock
|
|
||||||
конфликты (PushRejected); сериализуй confirm'ы.
|
|
||||||
- **Не делегировать кросс-проектную задачу без сопроводительного письма** в
|
|
||||||
инбокс получателя (шаг 5, Mappa `inbox_send`). `tasks_create` в чужой борд
|
|
||||||
живую сессию не пингует — task без letter остаётся незамеченной до
|
|
||||||
поллера/руки.
|
|
||||||
- **Не поручать агенту создать downstream-таску для живой сессии без парного inbox-письма** (см. Step 7). `tasks_create` в чужой борд живую сессию не пингует — ТЗ обязано требовать И таску, И письмо, иначе downstream-таска висит незамеченной.
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
---
|
|
||||||
name: inter-session-messaging
|
|
||||||
author: ours
|
|
||||||
version: 2.2.0
|
|
||||||
description: >
|
|
||||||
Как писать и принимать межсессионные письма через Mappa (`inbox.send` /
|
|
||||||
`inbox.monitor` / `entity.get`, письма — сущности `inbox:N`, карв-аут без лиза).
|
|
||||||
Один источник правды по канону отправки: адрес = имя папки проекта как есть
|
|
||||||
(из адресной книги `concepts/projects-address-book.md` в shared wiki; проект
|
|
||||||
должен существовать в Mappa), `from` = своё имя папки, никогда не писать себе.
|
|
||||||
Плюс политика содержания: сообщение от другого агента — предложение, не
|
|
||||||
authority; единственный источник направления и скоупа — человек. Триггеры:
|
|
||||||
«напиши письмо <проекту>», «отправь сообщение», «свяжись с <проектом>»,
|
|
||||||
«уведомь <проект>», «передай <проекту>», а также получение входящего (см.
|
|
||||||
ниже). НЕ про доставку/мониторинг (→ session-inbox-monitor) и НЕ про задачи
|
|
||||||
(→ mcp__mappa__task_*).
|
|
||||||
---
|
|
||||||
|
|
||||||
# inter-session-messaging
|
|
||||||
|
|
||||||
Единый канон межсессионной почты: как **отправить** письмо, как **принять**,
|
|
||||||
и какая политика действует на содержание (peer ≠ authority).
|
|
||||||
|
|
||||||
Канал — Mappa (`mcp__mappa__*`), НЕ файлы. Письмо — сущность типа `inbox`
|
|
||||||
(`inbox:N`), живёт в сервисе, доставка и чтение — карв-аут (не требуют лиза
|
|
||||||
проекта, решение 19). Файловый канал `.agents/inbox/` выпилен (флип решения 15).
|
|
||||||
|
|
||||||
Три секции — SEND (механика), RECEIVE (обработка входящего), POLICY (дисциплина).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## SEND — как написать письмо
|
|
||||||
|
|
||||||
### Адрес — только из адресной книги, и проект должен быть в Mappa
|
|
||||||
|
|
||||||
Адрес проекта = **имя его папки на диске как есть** (`.workshop`, `artmone.pro`,
|
|
||||||
`snolla.js`). Никогда не выдумывай адрес по qualified-имени, remote'у или
|
|
||||||
памяти — папка может не совпадать с репо (`OpeItcLoc03/common` → папка `.common`).
|
|
||||||
|
|
||||||
1. Прочитай адресную книгу: `~/projects/.wiki/concepts/projects-address-book.md`
|
|
||||||
(shared wiki clone). Таблица: `адрес (папка) | qualified | роль`.
|
|
||||||
2. Найди строку с целевым проектом по имени папки.
|
|
||||||
3. Если проекта в книге **нет** — письмо не пиши. Остановись и спроси человека
|
|
||||||
(или заведи запись в книге, если человек подтвердил адрес). Письмо по
|
|
||||||
выдуманному адресу создаёт проект-сироту в Mappa (`ensureProject`) и теряется.
|
|
||||||
4. **Проект должен существовать в Mappa**: сверь адрес со списком проектов
|
|
||||||
(`mcp__mappa__admin_status` → `projects[]` или `entity_search` type=project).
|
|
||||||
Несуществующего адреса нет в списке — остановись и спроси (или заведи проект).
|
|
||||||
|
|
||||||
### Вызов отправки
|
|
||||||
|
|
||||||
```
|
|
||||||
mcp__mappa__inbox_send(
|
|
||||||
project: <адрес получателя>, # имя папки проекта (из адресной книги)
|
|
||||||
from: <адрес отправителя>, # СВОЁ имя папки (только имя, без owner/темы)
|
|
||||||
subject: <тема>, # опционально — короткая тема
|
|
||||||
body: <markdown-тело> # свободный markdown
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
- `from` — **только имя своей папки**. Без owner, без описания. НЕ
|
|
||||||
`reviewer-command-index-done-ack` (тема письма — не адрес). На письмо с
|
|
||||||
выдуманным `from` нельзя ответить.
|
|
||||||
- Ответ на письмо: `inbox_send(project=<from полученного>, from=<своя папка>)`.
|
|
||||||
В `subject` — префикс `Re: `, в теле первая строка — ссылка на исходное
|
|
||||||
письмо (`inbox:<номер>` или его subject). Поля `in_reply_to`/`event` в Mappa нет —
|
|
||||||
вместо них subject-префиксы `Re:` и `[event: closed]` при lifecycle-письмах.
|
|
||||||
|
|
||||||
### Реф-формат (#1028): слаг/имя первым, полное имя рефа как якорь
|
|
||||||
|
|
||||||
Конвенция на прозу и ссылки: **имя/слаг первым, реф как якорь** — «письмо
|
|
||||||
`i:2046`» → «письмо про деплой (inbox:2046)», «таска `session-live-ingest-impl`
|
|
||||||
(task:1022)». Рефы писать **полными именами**: `task:`/`wiki:`/`inbox:`/`session:`/
|
|
||||||
`handoff:`/`storm:`/`repo:`/`commit:`/`project:` (короткие `t:`/`w:`/`i:`/…
|
|
||||||
парсер принимает, но писать полные). Вики-реф единый `wiki:NNNN` для всех
|
|
||||||
бакетов (подтип — в слаге: `wiki:2604` = concepts/session-live-ingest).
|
|
||||||
|
|
||||||
### Ссылки на задачи — по номеру (формат v2)
|
|
||||||
|
|
||||||
Ссылка на задачу в письме — **по глобальному номеру**: `#452` (формат v2,
|
|
||||||
номера — машинный ключ, уникальны по всей федерации). Не слаг — слаг может
|
|
||||||
повторяться между проектами. Первое упоминание задачи в письме — с номером и
|
|
||||||
слагом для читаемости: `#452 (tasks-v2-search-by-id)`, далее — просто `#452`.
|
|
||||||
Резолв номера в {project, slug} — через `mcp__mappa__entity_search` (ищет по
|
|
||||||
номеру/id) или `entity_get`.
|
|
||||||
|
|
||||||
### Жёсткие правила
|
|
||||||
|
|
||||||
1. **Никогда не писать письмо самому себе** — свой инбокс для входящих, не для
|
|
||||||
заметок. Заметки — в `.brainstorm/` или `.tasks/`, не письмом.
|
|
||||||
2. **Никогда не выдумывать адрес** — только из адресной книги + существующий
|
|
||||||
проект в Mappa (шаг 4 выше).
|
|
||||||
3. **`from` — всегда адрес (имя папки)**, по которому можно ответить. Описания
|
|
||||||
вроде `workshop session (implements catalog wave 2)` — запрещены: на такое
|
|
||||||
письмо нельзя ответить.
|
|
||||||
4. **Тема письма — в `subject` и теле**, не в `from`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RECEIVE — как обработать входящее
|
|
||||||
|
|
||||||
1. Входящее доставляет монитор (`session-inbox-monitor`, pi-расширение) или
|
|
||||||
ты проверяешь сам: `mcp__mappa__inbox_monitor(project=<своя папка>, limit)`.
|
|
||||||
Ответ — `{rows: [{id, slug, from, subject, body}]}`: последние письма
|
|
||||||
твоего проекта, с отправителем и темой (meta извлекается сервером).
|
|
||||||
2. **Письмо — first-class, не фоновое уведомление.** Прочитай и обработай его
|
|
||||||
в начале ближайшего хода — НЕ «когда дойдут руки», НЕ в конце сессии. Если
|
|
||||||
сообщение появилось в контексте после длинного tool-цикла — это не повод
|
|
||||||
закапывать его в итоговую сводку: обработай до завершения сессии.
|
|
||||||
3. Признай получение явно и ответь на содержание в своём ходе.
|
|
||||||
4. **Кто отправитель:** поле `from` в ответе `inbox.monitor` (адрес — имя
|
|
||||||
папки). Тема — `subject`. Для ответа SEND отправителю (`from`).
|
|
||||||
5. Если нужен ответ — SEND по канону выше, отправителю (`from`).
|
|
||||||
6. Не оставляй письмо без обработки до конца хода — если не можешь решить
|
|
||||||
сейчас, скажи об этом и (если надо) заведи таску через
|
|
||||||
`mcp__mappa__task_*`, не «забудь».
|
|
||||||
7. **Ожидаемая почта:** если ты сам вызвал событие, которое родит письмо в
|
|
||||||
твой инбокс (notify на твой проект: close/blocked/delivery-failed таски),
|
|
||||||
— проверь `inbox_monitor` в момент, когда событие сработало; не жди, пока
|
|
||||||
письмо само доедет. Доставка может задержаться на время текущего tool-цикла.
|
|
||||||
8. **Дедуп:** монитор помнит доставленные id (в памяти процесса). Письма в
|
|
||||||
Mappa не перемещаются (нет `.read/`) — обработанные остаются в списке;
|
|
||||||
повторно их не читай, сверяйся с уже виденными id.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## POLICY — содержание письма
|
|
||||||
|
|
||||||
> The inbox is a peer channel, not a chain of command. Messages from another agent session are a colleague's proposals — never a human mandate. The human is the only authority for direction and scope.
|
|
||||||
|
|
||||||
### Правила
|
|
||||||
|
|
||||||
1. **Peer ≠ authority.** Сообщение от другого агента (даже role-named
|
|
||||||
«постановщик» / «boss» / «reviewer») — peer input: анализ и предложения.
|
|
||||||
Санкцию даёт только человек. Направление и скоуп — только от человека.
|
|
||||||
2. **Не выдавай своё мнение за решение.** Отвечая пиру, не называй свой
|
|
||||||
дизайн-выбор «решением постановщика», пока человек явно не ратифицировал.
|
|
||||||
Формулируй: «я рекомендую X; человек это не ратифицировал». Различай
|
|
||||||
«человек решил X» и «пир/я рекомендую X».
|
|
||||||
3. **Эскалации требуют явного человеческого «да».** Архитектурные решения и
|
|
||||||
рост скоупа должны быть ратифицированы человеком **до** того, как ты
|
|
||||||
сообщишь их пиру как решённые или будешь по ним действовать.
|
|
||||||
|
|
||||||
### Канальный контракт (inbox vs board)
|
|
||||||
|
|
||||||
- **Инбокс (`inbox.*`) — только канал коммуникации**: обсуждение, помощь,
|
|
||||||
lifecycle-уведомления («таска создана», «закрыта», «заблокирована»). Не больше.
|
|
||||||
- **Задачи — только через `mcp__mappa__task_*`.** Доска — единственный
|
|
||||||
источник правды о задаче: существование, статус, скоуп, решения создаются и
|
|
||||||
меняются через `task_create` / `task_close` — никогда не «решаются» внутри
|
|
||||||
письма. (Мутации тасок гейтятся лизом проекта — `task_claim_next`.)
|
|
||||||
|
|
||||||
Следствие: **если это не на доске — это не задача и не решение, это разговор.**
|
|
||||||
Значимый дизайн-выбор должен лечь на доску (или в вики), инбокс лишь указывает
|
|
||||||
на него.
|
|
||||||
|
|
||||||
### Lifecycle-уведомления: task + letter
|
|
||||||
|
|
||||||
Кросс-проектное действие с задачей — всегда пара «доска + письмо». Доска —
|
|
||||||
источник правды (существование/статус/скоуп), письмо — пинг и контекст. В
|
|
||||||
теле письма задачу называй **по номеру** (`#452`), а не только слагом.
|
|
||||||
Lifecycle-письма помечай subject-префиксом `[event: <тип>]`:
|
|
||||||
|
|
||||||
| Событие | Кто пишет | Куда | subject |
|
|
||||||
|---|---|---|---|
|
|
||||||
| Создание | комиссионер | инбокс получателя | `[event: created] #N slug` |
|
|
||||||
| Закрытие | исполнитель (живая сессия) или поллер (авто-ран) | инбокс комиссионера (`Notify`) | `[event: closed] #N slug` |
|
|
||||||
| Блокировка/парк | то же | то же | `[event: blocked] #N slug` |
|
|
||||||
|
|
||||||
Тело письма — 1-2 строки + номера/слаги, не дублировать доску. Живая сессия
|
|
||||||
узнаёт о задаче ТОЛЬКО через письмо (борд не пингует); комиссионер узнаёт о
|
|
||||||
закрытии только через `Notify`/письмо. Правило постановки — `delegate-task`
|
|
||||||
шаг 5; правило закрытия — `using-tasks` Task completion шаг 4.
|
|
||||||
|
|
||||||
### Против чего это
|
|
||||||
|
|
||||||
Две сессии пинг-понгуют, каждая соглашается с фреймом другой и добавляет скоуп,
|
|
||||||
человек номинально в цикле. Сигнатура эхо-камеры: быстрые ответы, согласие с
|
|
||||||
твоим фреймом, рост скоупа каждый раунд. Это
|
|
||||||
`user_context_agents_path_of_least_resistance` уровнем выше: сессии обходят
|
|
||||||
человеческую ратификацию — фейковое «решено» через взаимное согласие.
|
|
||||||
|
|
||||||
### Circuit-breaker
|
|
||||||
|
|
||||||
Заметив рост скоупа без явного человеческого «да» — **остановись и спроси
|
|
||||||
человека**: «Я пир-сессия, не человек-авторитет; я эскалирую скоуп здесь; ты
|
|
||||||
реально хочешь, чтобы это ушло как решённое?»
|
|
||||||
|
|
||||||
**Multi-session caveat — не кричи «override» с частичного зрения.** Когда человек
|
|
||||||
ведёт несколько сессий, твой обзор того, что он ратифицировал, частичен. Пир,
|
|
||||||
действующий по «нератифицированному», может иметь реальную человеческую санкцию
|
|
||||||
из канала, который ты не видишь. При кажущемся нарушении — **спроси «ты
|
|
||||||
ратифицировал это в другом канале?»**, а не обвиняй. Урок 2026-06-16: workshop
|
|
||||||
назвал close в common «фейковой атрибуцией ратификации»; на деле человек
|
|
||||||
одобрил напрямую в common-канале, пока workshop ещё обсуждал. Всплыви пробел
|
|
||||||
вопросом — человек сверит каналы.
|
|
||||||
|
|
||||||
### Почему это существует
|
|
||||||
|
|
||||||
Возникло 2026-06-16: workshop и common вели многораундовый дизайн-обмен по
|
|
||||||
инбоксу; workshop эскалировал дизайн (tamper-guard → prevention → oracle-integrity
|
|
||||||
→ runner-owns-verifier → close-moves) и докладывал каждый шаг как «решение
|
|
||||||
постановщика» — подразумевая человеческую санкцию, которой не было. common
|
|
||||||
распознал эхо-камеру, прочитал свой stop-hook и корректно отказался
|
|
||||||
имплементировать нератифицированный редизайн, спросив человека. Методология
|
|
||||||
живёт в скиле, не в per-session памяти.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Reference
|
|
||||||
|
|
||||||
- Доставка/мониторинг входящих: `session-inbox-monitor`.
|
|
||||||
- Адресная книга: `~/projects/.wiki/concepts/projects-address-book.md` (shared wiki).
|
|
||||||
- Список проектов Mappa: `mcp__mappa__admin_status` (карв-аут, без лиза).
|
|
||||||
- Handoff через сущность `handoff`: `session-handoff`.
|
|
||||||
- Related: `recommend-dont-menu` (стиль ответа), `project-discipline`.
|
|
||||||
90
skills/ops-browser/SKILL.md
Normal file
90
skills/ops-browser/SKILL.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
name: ops-browser
|
||||||
|
author: ours
|
||||||
|
version: 0.1.0
|
||||||
|
description: >
|
||||||
|
Use when a task needs a real browser — личный кабинет, заказы, чеки, yt-digest,
|
||||||
|
скриншот живого сайта, «дёрни внутренний API». Свой СКРЫТЫЙ браузер агента:
|
||||||
|
отдельный профиль, CDP, `fetch()` ИЗ страницы, хендофф человеку для пароля/капчи.
|
||||||
|
---
|
||||||
|
|
||||||
|
# ops-browser — свой скрытый браузер агента
|
||||||
|
|
||||||
|
**Есть задача, которой нужен браузер? Работай в своём браузере, скрыто, и не подсовывай куки.**
|
||||||
|
Профиль владеет сессией сам (куки продлеваются браузером, а не руками) — это и есть лечение
|
||||||
|
боли «куки протухли».
|
||||||
|
|
||||||
|
## Когда ЭТОТ инструмент, а когда другой
|
||||||
|
|
||||||
|
| Ситуация | Чем работать |
|
||||||
|
|---|---|
|
||||||
|
| Публичная страница без логина | `web_search` / `web_extract` / curl — браузер не нужен |
|
||||||
|
| Личный кабинет, заказы, чеки, внутренний API сайта, антибот | **`ops-browser.sh`** (этот скил) |
|
||||||
|
| Нужны ЕГО логины и ЕГО Chrome (Avito, кабинеты поставщиков) | канал оператора: Hermes `browser_exec` / pi тул `browser` / CC `chrome-devtools` — всё под арендой `driver.lock` |
|
||||||
|
| Посмотреть глазами, кликнуть по живому сайту, показать ему | панель предпросмотра (`desktop_preview` + `drive_preview`) — без JS, только текст/клики |
|
||||||
|
|
||||||
|
`ops-browser` не заменяет канал оператора: там его сессии, здесь — **мой** профиль.
|
||||||
|
И то и другое живёт под правилом «один водитель» (у ops свой замок `ops.lock`).
|
||||||
|
|
||||||
|
## Команды
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OB="$HOME/.config/browser-harness/bin/ops-browser.sh"
|
||||||
|
bash "$OB" start # headless + аренда (окон нет)
|
||||||
|
bash "$OB" open https://site/path # перейти
|
||||||
|
bash "$OB" read 2000 # видимый текст страницы
|
||||||
|
bash "$OB" eval 'fetch("/api/x",{credentials:"include"}).then(r=>r.json()).then(j=>JSON.stringify(j))'
|
||||||
|
bash "$OB" screenshot [path] # PNG, печатает путь
|
||||||
|
bash "$OB" cookies https://site # имена кук (без значений)
|
||||||
|
bash "$OB" status # аренда + CDP + текущая страница
|
||||||
|
bash "$OB" stop # ШТАТНО закрыть и отпустить
|
||||||
|
bash "$OB" handoff <url> # человеку: пароль/2FA/капча (см. ниже)
|
||||||
|
```
|
||||||
|
|
||||||
|
`eval` выполняет JS **в контексте страницы** — значит `fetch()` идёт с её куками и заголовками:
|
||||||
|
так дёргают внутренние эндпоинты приложения (то, что недоступно извне и чего не умеет панель).
|
||||||
|
|
||||||
|
## Хендофф человеку (пароль, 2FA, капча, согласие)
|
||||||
|
|
||||||
|
Останавливаюсь и отдаю экран **сам**, без «скажи готово»:
|
||||||
|
|
||||||
|
1. `bash "$OB" handoff <url>` — закрывает headless (профиль нельзя открыть дважды) и поднимает
|
||||||
|
**видимое** окно ТОГО ЖЕ профиля на нужной странице;
|
||||||
|
2. человек вводит, что нужно (пароль/2FA/капчу вводит только он);
|
||||||
|
3. признак успеха ловлю сам: URL ушёл со страницы логина/auth **или** выросли куки домена;
|
||||||
|
4. штатно закрываю окно и возвращаюсь в headless — логин остался в профиле.
|
||||||
|
|
||||||
|
Скриншот делаю **до** шага (что от человека хотят) и **после** (что получилось); **во время ввода
|
||||||
|
пароля не снимаю**. Если признак успеха не увидел — окно остаётся открытым, а я говорю об этом прямо.
|
||||||
|
|
||||||
|
## Границы (не двигаются)
|
||||||
|
|
||||||
|
- Пароли, 2FA, капчу — **вводит человек**. Я к ним не подхожу.
|
||||||
|
- Деньги, оформление заказов, формы с перс.данными — только с явного согласия оператора.
|
||||||
|
- Куки не выгружаю и не расшифровываю; содержимое залогиненных страниц не уходит в логи/вику.
|
||||||
|
- Антибот-челленджи не обхожу; если сайт невзлюбил `headless` — это повод для `handoff`, а не для трюков.
|
||||||
|
|
||||||
|
## Грабли (стоили времени, проверены живьём)
|
||||||
|
|
||||||
|
- **Закрывать только штатно** (`stop` → `Browser.close`). Жёсткий kill может не сбросить профиль →
|
||||||
|
потеря логина. Сессионные куки (без срока) перезапуск не переживают по дизайну — настоящие логины живут.
|
||||||
|
- **MSYS-пути**: нативным программам нужен вид `C:/...` (`cygpath -m`), а `powershell -File` —
|
||||||
|
только `C:\...` (`cygpath -w`). Иначе «модуль не найден» / «файл .ps1 не найден».
|
||||||
|
- **Экранирование PowerShell внутри bash-строки тихо ломается** (`$_` подменяется) — PS-запросы
|
||||||
|
держим в отдельных `.ps1`.
|
||||||
|
- **Профиль нельзя открыть дважды** — перед видимым окном headless обязан остановиться (это делает `handoff`).
|
||||||
|
- **Профиль**: `~/.config/browser-harness/profiles/ops`; порт CDP: `OPS_CDP_PORT` (9346).
|
||||||
|
|
||||||
|
## Аренда
|
||||||
|
|
||||||
|
```bash
|
||||||
|
BL="$HOME/.config/browser-harness/bin/browser-lease.sh"
|
||||||
|
bash "$BL" --lock ops status # состояние ops-замка (у Chrome оператора — driver.lock)
|
||||||
|
```
|
||||||
|
|
||||||
|
Чужой держатель `ops.lock` → `start` честно отказывает (rc=1). Мёртвый держатель отпускается по PID/TTL.
|
||||||
|
Идёшь в браузер **сам** (в обход `ops-browser.sh`)? Возьми `ops.lock` так же, как любой другой харнесс.
|
||||||
|
|
||||||
|
Контракт: mappa `concepts/ops-browser-contract` (проект `pi-extensions`),
|
||||||
|
требования `requirements:42`, план `plan:35`. Исходники: репо `pi-extensions/scripts/browser/`
|
||||||
|
(установка `just install-browser`).
|
||||||
@@ -39,7 +39,7 @@ Karpathy / `.tasks/` (см. using-wiki/using-tasks, legacy-раздел).
|
|||||||
| `README.md` | minimal stub | Skipped if file exists. |
|
| `README.md` | minimal stub | Skipped if file exists. |
|
||||||
| вики | mappa (`using-wiki`) | сущности `type=wiki` в сервисе; файловый layout — только вне mappa (легаси). |
|
| вики | mappa (`using-wiki`) | сущности `type=wiki` в сервисе; файловый layout — только вне mappa (легаси). |
|
||||||
| таски | mappa (`using-tasks`) | сущности `type=task` в сервисе; файловый `.tasks/` — только вне mappa (легаси). |
|
| таски | mappa (`using-tasks`) | сущности `type=task` в сервисе; файловый `.tasks/` — только вне mappa (легаси). |
|
||||||
| `AGENTS.md` | `assets/AGENTS.md.template` | **Canon** — skill triggers (`use project wiki`, `use task management system`, etc.). On non-Windows hosts, swap the `we're on Windows` line for `we're on Linux` / `we're on macOS`. On upgrade, the template is treated as a canonical set and merged idempotently — only missing trigger lines are appended after user confirm. Re-runs are no-ops. |
|
| `AGENTS.md` | `assets/AGENTS.md.template` | **Canon** — mappa-agnostic generic triggers (caveman, pull remote before work, tdd, interns, recommend, platform). Mappa-специфичные триггеры (`inbox monitor: raise on start`, `session sync: write to mappa`, `use project wiki`, `use task management system`, `check across all projects`) инжектятся через mappa-bootstrap (Step 5.7.2). On non-Windows hosts, swap the `we're on Windows` line for `we're on Linux` / `we're on macOS`. On upgrade, the template is treated as a canonical set and merged idempotently — only missing generic trigger lines are appended after user confirm. Re-runs are no-ops. |
|
||||||
| `CLAUDE.md` | generated pointer | `Canon is AGENTS.md. Read AGENTS.md.` — legacy pointer for tooling that looks for the old name. |
|
| `CLAUDE.md` | generated pointer | `Canon is AGENTS.md. Read AGENTS.md.` — legacy pointer for tooling that looks for the old name. |
|
||||||
| `.wiki/concepts/bootstrap-manifest.md` | generated | Records which skill versions initialized the project, so cross-project layout drift is debuggable. |
|
| `.wiki/concepts/bootstrap-manifest.md` | generated | Records which skill versions initialized the project, so cross-project layout drift is debuggable. |
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ Karpathy / `.tasks/` (см. using-wiki/using-tasks, legacy-раздел).
|
|||||||
3. **Steps 1–5.** Create or skip each piece in order — git, README, вики/таски
|
3. **Steps 1–5.** Create or skip each piece in order — git, README, вики/таски
|
||||||
(mappa, см. using-wiki/using-tasks), `AGENTS.md` + `CLAUDE.md` pointer.
|
(mappa, см. using-wiki/using-tasks), `AGENTS.md` + `CLAUDE.md` pointer.
|
||||||
4. **Step 5.5.** Write `bootstrap-manifest.md` recording the versions of
|
4. **Step 5.5.** Write `bootstrap-manifest.md` recording the versions of
|
||||||
`project-bootstrap`, `project-discipline`, `setup-interns`, and
|
`project-bootstrap`, `setup-interns`, and
|
||||||
`using-interns` used.
|
`using-interns` used.
|
||||||
5. **Step 5.6.** Skill dependencies check. Walk the canonical trigger list
|
5. **Step 5.6.** Skill dependencies check. Walk the canonical trigger list
|
||||||
in `AGENTS.md`, look each up in an embedded `trigger → fulfiller` map,
|
in `AGENTS.md`, look each up in an embedded `trigger → fulfiller` map,
|
||||||
@@ -102,8 +102,9 @@ target with `CLAUDE_SKILLS_DIR=/path bash scripts/install.sh …`.
|
|||||||
|
|
||||||
- [`using-wiki`](../using-wiki/) — runtime policy for the mappa wiki (v2).
|
- [`using-wiki`](../using-wiki/) — runtime policy for the mappa wiki (v2).
|
||||||
- [`using-tasks`](../using-tasks/) — runtime policy for the mappa task board (v2).
|
- [`using-tasks`](../using-tasks/) — runtime policy for the mappa task board (v2).
|
||||||
- [`project-discipline`](../project-discipline/) — cross-project rules
|
- kzntsv-flavored cross-project discipline (activated per-project by
|
||||||
activated by the `follow project discipline` trigger.
|
`mappa-bootstrap`, which selects the methodology flavor) — moved to
|
||||||
|
`victor/mappa-vitya-skills` (легаси, поглощено монорепо) — mappa-kzntsv-project-discipline.
|
||||||
- [`setup-interns`](../setup-interns/), [`using-interns`](../using-interns/) —
|
- [`setup-interns`](../setup-interns/), [`using-interns`](../using-interns/) —
|
||||||
pair behind the `delegate to interns when allowed` trigger; cheap-LLM
|
pair behind the `delegate to interns when allowed` trigger; cheap-LLM
|
||||||
delegation under a per-session permission grant.
|
delegation under a per-session permission grant.
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
---
|
---
|
||||||
name: project-bootstrap
|
name: project-bootstrap
|
||||||
author: ours
|
author: ours
|
||||||
version: 2.1.0
|
version: 3.3.0
|
||||||
description: >
|
description: >
|
||||||
Initializes or upgrades a project in the current folder: git, .gitignore, README.md,
|
Initializes or upgrades a project in the current folder: git, .gitignore, README.md,
|
||||||
.wiki/ using Karpathy's method, .tasks/ for task tracking, AGENTS.md (canon) with
|
.wiki/ using Karpathy's method, .tasks/ for task tracking, AGENTS.md (canon) with
|
||||||
skill triggers + CLAUDE.md legacy pointer.
|
skill triggers + CLAUDE.md legacy pointer.
|
||||||
Creates remote Gitea repo and syncs projects-meta cache for greenfield projects.
|
Creates remote Gitea repo and syncs projects-meta cache for greenfield projects.
|
||||||
|
Includes the mappa-bootstrap-project module (v3, решение 4 mappa-as-product):
|
||||||
|
mappa MCP connect + mappa-конвенции + методика-install (версия в манифест).
|
||||||
|
Creates the `.mappa` marker (wiki:3340) so the folder is a mappa project.
|
||||||
Use this skill when the user says "initialize project", "bootstrap", "setup project",
|
Use this skill when the user says "initialize project", "bootstrap", "setup project",
|
||||||
"upgrade project", "add wiki", "add tasks", "start project", "set everything up",
|
"upgrade project", "add wiki", "add tasks", "start project", "set everything up",
|
||||||
"create new project", or launches the agent in a new folder and wants a full setup.
|
"create new project", or launches the agent in a new folder and wants a full setup.
|
||||||
@@ -34,6 +37,7 @@ ls -A 2>/dev/null | grep -q . && echo "empty:no" || echo "empty:yes"
|
|||||||
[ -d .tasks ] && echo "tasks:yes" || echo "tasks:no"
|
[ -d .tasks ] && echo "tasks:yes" || echo "tasks:no"
|
||||||
[ -f CLAUDE.md ] && echo "claude:yes" || echo "claude:no"
|
[ -f CLAUDE.md ] && echo "claude:yes" || echo "claude:no"
|
||||||
[ -f README.md ] && echo "readme:yes" || echo "readme:no"
|
[ -f README.md ] && echo "readme:yes" || echo "readme:no"
|
||||||
|
[ -d .mappa ] && echo "mappa-marker:yes" || echo "mappa-marker:no"
|
||||||
```
|
```
|
||||||
|
|
||||||
Determine mode:
|
Determine mode:
|
||||||
@@ -112,7 +116,7 @@ source ~/.config/projects-mcp/auth.toml 2>/dev/null || true
|
|||||||
Get-Content ~/.config/projects-mcp/auth.toml | Select-String "base_url|token"
|
Get-Content ~/.config/projects-mcp/auth.toml | Select-String "base_url|token"
|
||||||
```
|
```
|
||||||
|
|
||||||
If auth file missing → stop and tell user: run `/setup-projects-meta` first.
|
If auth file missing → stop and tell the user (нужны Gitea-креды; скил `setup-projects-meta` удалён 2026-08-25).
|
||||||
|
|
||||||
### Validate project name
|
### Validate project name
|
||||||
|
|
||||||
@@ -198,7 +202,7 @@ v2 (mappa wiki-тулы). Файловый `.wiki/` — только для пр
|
|||||||
entities/ ← entity pages (people, services, modules) — empty .gitkeep
|
entities/ ← entity pages (people, services, modules) — empty .gitkeep
|
||||||
concepts/ ← concept / design decision pages — empty .gitkeep
|
concepts/ ← concept / design decision pages — empty .gitkeep
|
||||||
packages/ ← package pages — empty .gitkeep
|
packages/ ← package pages — empty .gitkeep
|
||||||
sources/ ← one summary per ingested source — empty .gitkeep
|
summaries/ ← one summary per ingested source (LLM, raw_path) — empty .gitkeep
|
||||||
```
|
```
|
||||||
|
|
||||||
Page-level workflow (ingest, query, lint) and file formats are owned by the
|
Page-level workflow (ingest, query, lint) and file formats are owned by the
|
||||||
@@ -223,7 +227,7 @@ file overrides the skill where they conflict.
|
|||||||
- `entities/` — discrete things the project tracks (people, services, modules).
|
- `entities/` — discrete things the project tracks (people, services, modules).
|
||||||
- `concepts/` — recurring ideas, design decisions, gotchas.
|
- `concepts/` — recurring ideas, design decisions, gotchas.
|
||||||
- `packages/` — code packages this project produces or consumes.
|
- `packages/` — code packages this project produces or consumes.
|
||||||
- `sources/` — one summary page per ingested external doc; frontmatter carries `ingested:` and `raw_path:`.
|
- `summaries/` — one summary page per ingested external doc; frontmatter carries `ingested:` and `raw_path:`.
|
||||||
- `overview.md` — single project-wide overview.
|
- `overview.md` — single project-wide overview.
|
||||||
|
|
||||||
## Naming
|
## Naming
|
||||||
@@ -298,7 +302,7 @@ Parseable: `grep "^## \[" .wiki/log.md | tail -20`.
|
|||||||
|
|
||||||
**Immutable.** Read, never edit. The only allowed modification is appending a `> Status:` blockquote when the user explicitly asks for a status audit.
|
**Immutable.** Read, never edit. The only allowed modification is appending a `> Status:` blockquote when the user explicitly asks for a status audit.
|
||||||
|
|
||||||
Place raw inputs here — articles, transcripts, PDFs, screenshots — exactly as they came in. The agent reads from `raw/`, writes summaries into `../sources/`, and never modifies raw files.
|
Place raw inputs here — articles, transcripts, PDFs, screenshots — exactly as they came in. The agent reads from `raw/`, writes summaries into `../summaries/`, and never modifies raw files.
|
||||||
|
|
||||||
For large or path-sensitive sources that live outside the repo, register them here:
|
For large or path-sensitive sources that live outside the repo, register them here:
|
||||||
|
|
||||||
@@ -307,7 +311,7 @@ For large or path-sensitive sources that live outside the repo, register them he
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
```
|
```
|
||||||
|
|
||||||
The empty subdirectories (`entities/`, `concepts/`, `packages/`, `sources/`)
|
The empty subdirectories (`entities/`, `concepts/`, `packages/`, `summaries/`)
|
||||||
each get a `.gitkeep` so git tracks them.
|
each get a `.gitkeep` so git tracks them.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -385,22 +389,24 @@ Template contents (`assets/AGENTS.md.template` — source of truth):
|
|||||||
# Agent instructions. Each line is a trigger for an installed skill.
|
# Agent instructions. Each line is a trigger for an installed skill.
|
||||||
|
|
||||||
talk like a caveman
|
talk like a caveman
|
||||||
use project wiki
|
|
||||||
use task management system
|
|
||||||
check across all projects
|
|
||||||
pull remote before work
|
pull remote before work
|
||||||
follow project discipline
|
|
||||||
follow tdd-criteria
|
follow tdd-criteria
|
||||||
delegate to interns when allowed
|
delegate to interns when allowed
|
||||||
recommend, don't menu
|
recommend, don't menu
|
||||||
we're on Windows
|
we're on Windows
|
||||||
```
|
```
|
||||||
|
|
||||||
The `check across all projects` line activates the `using-projects-meta` skill
|
Mappa-специфичные триггеры (`check across all projects`, `inbox monitor:
|
||||||
so cross-project task aggregation and the shared `projects-wiki` are available
|
raise on start`, `use project wiki`, `use task management system`, `session
|
||||||
without an explicit verbal trigger. The skill is a no-op until the
|
sync: write to mappa`) **не в шаблоне** — инжектятся через mappa-bootstrap
|
||||||
`projects-meta-mcp` server is registered — install via `setup-projects-meta`
|
(Step 5.7.2), project-bootstrap mappa-agnostic. `check across all projects`
|
||||||
on a fresh machine if `mcp__projects-meta__*` tools are missing.
|
активирует **mappa** tooling (`mcp__mappa__*`) — cross-project boards, shared
|
||||||
|
wiki и реестр проектов живут в mappa.
|
||||||
|
|
||||||
|
The file-based `projects-meta-mcp` and its skills (`using-projects-meta`,
|
||||||
|
`setup-projects-meta`, `meta-host-routing`, `setup-wiki`,
|
||||||
|
`setup-tasks`) were removed 2026-08-25; the shared `projects-wiki` files are
|
||||||
|
stubs «не читать, не править» — канон mappa shared-scope.
|
||||||
|
|
||||||
The `pull remote before work` line activates the `pulling-before-work` skill,
|
The `pull remote before work` line activates the `pulling-before-work` skill,
|
||||||
which runs one `git pull --ff-only` at session start (and on explicit re-sync
|
which runs one `git pull --ff-only` at session start (and on explicit re-sync
|
||||||
@@ -410,15 +416,6 @@ upstream — never auto-merges, stashes, or pushes. Install the skill on the hos
|
|||||||
if `pulling-before-work` is not in `~/.claude/skills/`; otherwise the trigger is
|
if `pulling-before-work` is not in `~/.claude/skills/`; otherwise the trigger is
|
||||||
silently dead like any other absent skill.
|
silently dead like any other absent skill.
|
||||||
|
|
||||||
The `follow project discipline` line activates the `project-discipline` skill,
|
|
||||||
which codifies four cross-project rules: (1) project AGENTS.md / CLAUDE.md /
|
|
||||||
.wiki/CLAUDE.md / .tasks/ override defaults from any other skill; (2) all work on master/main,
|
|
||||||
no feature branches without explicit user approval; (3) version bump on every
|
|
||||||
edit of versioned artifacts per semver, recorded in commit; (4) commit freely,
|
|
||||||
push only after explicit per-session approval. Install the skill on the host
|
|
||||||
if `project-discipline` is not in `~/.claude/skills/`; otherwise the trigger is
|
|
||||||
silently dead like any other absent skill.
|
|
||||||
|
|
||||||
The `follow tdd-criteria` line activates the `tdd-criteria` skill, which enforces
|
The `follow tdd-criteria` line activates the `tdd-criteria` skill, which enforces
|
||||||
test-driven development by default with four bright-line carve-outs (visual CSS,
|
test-driven development by default with four bright-line carve-outs (visual CSS,
|
||||||
spike exploration, oneshot scripts, pure wrappers) and four anti-loophole rules
|
spike exploration, oneshot scripts, pure wrappers) and four anti-loophole rules
|
||||||
@@ -432,8 +429,8 @@ which lets Claude offload predictable bulk I/O and summarization tasks
|
|||||||
(reading 3+ files, distilling long transcripts) to cheap intern LLMs via the
|
(reading 3+ files, distilling long transcripts) to cheap intern LLMs via the
|
||||||
local `interns` MCP server (`mcp__interns__bulk_text_read`,
|
local `interns` MCP server (`mcp__interns__bulk_text_read`,
|
||||||
`mcp__interns__transcript_distill`, etc.) — saves Anthropic quota at ~125× the
|
`mcp__interns__transcript_distill`, etc.) — saves Anthropic quota at ~125× the
|
||||||
per-call cost reduction on bulk reads. Per-session permission grant mirrors
|
per-call cost reduction on bulk reads. Per-session permission grant mirrors the
|
||||||
`project-discipline` Rule 4: ask-mode default, conversational grant / revoke,
|
`mappa-kzntsv-project-discipline` Rule 4 (skill moved from `victor/mappa-vitya-skills`, легаси, поглощено монорепо): ask-mode default, conversational grant / revoke,
|
||||||
always-ask paths for `.env` / secrets / keys / SSH credentials even with an
|
always-ask paths for `.env` / secrets / keys / SSH credentials even with an
|
||||||
active grant, session-end reset. The skill is a no-op until the `interns` MCP
|
active grant, session-end reset. The skill is a no-op until the `interns` MCP
|
||||||
server is registered — install via `setup-interns` on a fresh machine if
|
server is registered — install via `setup-interns` on a fresh machine if
|
||||||
@@ -476,9 +473,14 @@ Skills used to initialize this project's `.wiki/` and `.tasks/` layout, with the
|
|||||||
| Skill | Version | Role |
|
| Skill | Version | Role |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `project-bootstrap` | <version> | orchestrator |
|
| `project-bootstrap` | <version> | orchestrator |
|
||||||
| `project-discipline` | <version> | cross-project policy |
|
|
||||||
| `setup-interns` | <version> | interns MCP server install (one-time, per machine) |
|
| `setup-interns` | <version> | interns MCP server install (one-time, per machine) |
|
||||||
| `using-interns` | <version> | interns runtime policy + per-session permission grant |
|
| `using-interns` | <version> | interns runtime policy + per-session permission grant |
|
||||||
|
| `mappa-*` (методика, модуль 5.7) | <version of reference-package skills> | mappa-циклы: session-orient / task-work / knowledge / messaging / delegation / brainstorm-promote / closing-ritual |
|
||||||
|
|
||||||
|
Модуль `mappa-bootstrap-project` (решение 4 mappa-as-product) фиксирует
|
||||||
|
версию методики в этой строке — читать `version:` из frontmatter каждого
|
||||||
|
mappa-скилла, не хардкодить. Если пакет не установлен — `unknown` (видно
|
||||||
|
в депс-чеке 5.6).
|
||||||
|
|
||||||
This file is overwritten if `project-bootstrap` is re-run on the same project. For history, use `git log .wiki/concepts/bootstrap-manifest.md`.
|
This file is overwritten if `project-bootstrap` is re-run on the same project. For history, use `git log .wiki/concepts/bootstrap-manifest.md`.
|
||||||
```
|
```
|
||||||
@@ -507,13 +509,16 @@ Mismatch between template and map → silent gaps in the recommendation.
|
|||||||
| `talk like a caveman` | `caveman` | skill | `~/.claude/skills/caveman/SKILL.md` | `bash scripts/install.sh caveman` |
|
| `talk like a caveman` | `caveman` | skill | `~/.claude/skills/caveman/SKILL.md` | `bash scripts/install.sh caveman` |
|
||||||
| `use project wiki` | `using-wiki` | skill | `~/.claude/skills/using-wiki/SKILL.md` | `bash scripts/install.sh using-wiki` |
|
| `use project wiki` | `using-wiki` | skill | `~/.claude/skills/using-wiki/SKILL.md` | `bash scripts/install.sh using-wiki` |
|
||||||
| `use task management system` | `using-tasks` | skill | `~/.claude/skills/using-tasks/SKILL.md` | `bash scripts/install.sh using-tasks` |
|
| `use task management system` | `using-tasks` | skill | `~/.claude/skills/using-tasks/SKILL.md` | `bash scripts/install.sh using-tasks` |
|
||||||
| `check across all projects` | `using-projects-meta` | skill | `~/.claude/skills/using-projects-meta/SKILL.md` | `bash scripts/install.sh using-projects-meta` |
|
| `check across all projects` | mappa (`mcp__mappa__*`) | MCP | `mcpServers.mappa` in `~/.claude.json` | — |
|
||||||
| `pull remote before work` | `pulling-before-work` | skill | `~/.claude/skills/pulling-before-work/SKILL.md` | `bash scripts/install.sh pulling-before-work` |
|
| `pull remote before work` | `pulling-before-work` | skill | `~/.claude/skills/pulling-before-work/SKILL.md` | `bash scripts/install.sh pulling-before-work` |
|
||||||
| `session handoff: read on start, write on end` | `session-handoff` | skill | `~/.claude/skills/session-handoff/SKILL.md` | `bash scripts/install.sh session-handoff` |
|
| `session handoff: read on start, write on end` | `session-handoff` | skill | `~/.claude/skills/session-handoff/SKILL.md` | `bash scripts/install.sh session-handoff` |
|
||||||
| `follow project discipline` | `project-discipline` | skill | `~/.claude/skills/project-discipline/SKILL.md` | `bash scripts/install.sh project-discipline` |
|
|
||||||
| `follow tdd-criteria` | `tdd-criteria` | skill | `~/.claude/skills/tdd-criteria/SKILL.md` | `bash scripts/install.sh tdd-criteria` |
|
| `follow tdd-criteria` | `tdd-criteria` | skill | `~/.claude/skills/tdd-criteria/SKILL.md` | `bash scripts/install.sh tdd-criteria` |
|
||||||
| `delegate to interns when allowed` | `using-interns` | skill | `~/.claude/skills/using-interns/SKILL.md` | `bash scripts/install.sh using-interns` |
|
| `delegate to interns when allowed` | `using-interns` | skill | `~/.claude/skills/using-interns/SKILL.md` | `bash scripts/install.sh using-interns` |
|
||||||
| `recommend, don't menu` | `recommend-dont-menu` | skill | `~/.claude/skills/recommend-dont-menu/SKILL.md` | `bash scripts/install.sh recommend-dont-menu` |
|
| `recommend, don't menu` | `recommend-dont-menu` | skill | `~/.claude/skills/recommend-dont-menu/SKILL.md` | `bash scripts/install.sh recommend-dont-menu` |
|
||||||
|
| `use project wiki` | `mappa-knowledge` | skill | см. mappa-bootstrap (репо mappa) | `cd <mappa-repo> && bash skills/mappa-bootstrap/assets/install.sh` |
|
||||||
|
| `use task management system` | `mappa-task-work` | skill | см. mappa-bootstrap (репо mappa) | `cd <mappa-repo> && bash skills/mappa-bootstrap/assets/install.sh` |
|
||||||
|
| `inbox monitor: raise on start` | `mappa-session-orient` | skill | см. mappa-bootstrap (репо mappa) | `cd <mappa-repo> && bash skills/mappa-bootstrap/assets/install.sh` |
|
||||||
|
| `session sync: write to mappa` | `mappa-session-orient` | skill | см. mappa-bootstrap (репо mappa) | `cd <mappa-repo> && bash skills/mappa-bootstrap/assets/install.sh` |
|
||||||
| `we're on Windows` / `we're on Linux` / `we're on macOS` | `active-platform` | skill | `~/.claude/skills/active-platform/SKILL.md` | `bash scripts/install.sh active-platform` |
|
| `we're on Windows` / `we're on Linux` / `we're on macOS` | `active-platform` | skill | `~/.claude/skills/active-platform/SKILL.md` | `bash scripts/install.sh active-platform` |
|
||||||
|
|
||||||
### Algorithm
|
### Algorithm
|
||||||
@@ -527,7 +532,11 @@ Mismatch between template and map → silent gaps in the recommendation.
|
|||||||
match any row are user-custom — skip silently. The platform line matches
|
match any row are user-custom — skip silently. The platform line matches
|
||||||
the `active-platform` row regardless of which platform is pinned.
|
the `active-platform` row regardless of which platform is pinned.
|
||||||
3. For each matched canonical line, check the detection path:
|
3. For each matched canonical line, check the detection path:
|
||||||
- `kind: skill` → does `~/.claude/skills/<name>/SKILL.md` exist?
|
- `kind: skill` → does `~/.claude/skills/<name>/SKILL.md` **or**
|
||||||
|
`~/.agents/skills/<name>/SKILL.md` exist? (Skill installs can land in
|
||||||
|
either host path — `scripts/install.sh` writes `~/.claude/skills/`, a
|
||||||
|
manual/alternate install may use `~/.agents/skills/`; a skill present in
|
||||||
|
either path fulfills the trigger. Same two-path rule as Step 5.7.3.)
|
||||||
- `kind: plugin` → does `~/.claude/plugins/installed_plugins.json` contain
|
- `kind: plugin` → does `~/.claude/plugins/installed_plugins.json` contain
|
||||||
the plugin key under `plugins`? (Treat malformed JSON as "missing" and
|
the plugin key under `plugins`? (Treat malformed JSON as "missing" and
|
||||||
continue — don't crash the bootstrap over a detection edge case.)
|
continue — don't crash the bootstrap over a detection edge case.)
|
||||||
@@ -572,12 +581,160 @@ Mismatch between template and map → silent gaps in the recommendation.
|
|||||||
`setup-X` at first use; bootstrap doesn't duplicate that detection.
|
`setup-X` at first use; bootstrap doesn't duplicate that detection.
|
||||||
- The `~/.claude/skills/` and `~/.claude/plugins/` paths resolve identically
|
- The `~/.claude/skills/` and `~/.claude/plugins/` paths resolve identically
|
||||||
on Windows / Linux / macOS — `~` works under git-bash too.
|
on Windows / Linux / macOS — `~` works under git-bash too.
|
||||||
|
- **Detection paths (unified with Step 5.7.3):** a `kind: skill` fulfiller is
|
||||||
|
considered present if its `SKILL.md` exists in `~/.claude/skills/<name>/`
|
||||||
|
OR `~/.agents/skills/<name>/`. The dependency tables below list the
|
||||||
|
canonical install path (`~/.claude/skills/`, what `scripts/install.sh`
|
||||||
|
writes); detection itself accepts both.
|
||||||
- **Hard rule — never auto-install.** Slash commands aren't callable from a
|
- **Hard rule — never auto-install.** Slash commands aren't callable from a
|
||||||
skill, and silently mutating user-level skill / plugin state without
|
skill, and silently mutating user-level skill / plugin state without
|
||||||
consent is overreach. The recommendation is informational. The user can
|
consent is overreach. The recommendation is informational. The user can
|
||||||
install some / all / none of the recommendations, or remove canonical
|
install some / all / none of the recommendations, or remove canonical
|
||||||
lines from `AGENTS.md` to lean the project's trigger set down.
|
lines from `AGENTS.md` to lean the project's trigger set down.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5.7 — mappa-bootstrap-project (модуль, решение 4 mappa-as-product)
|
||||||
|
|
||||||
|
> Спека: `.wiki/concepts/mappa-as-product.md` (wiki:2672), решение 4. Модуль
|
||||||
|
> вызывается project-bootstrap'ом как шаг в режимах greenfield-full и upgrade.
|
||||||
|
> Скоуп: connect (MCP) + mappa-конвенции в AGENTS.md (idempotent merge) +
|
||||||
|
> методика-install (пакет из репо, версия в манифест) + manifest/deps-check.
|
||||||
|
|
||||||
|
### 5.7.1 — Connect (MCP)
|
||||||
|
|
||||||
|
Проверить, что mappa MCP-сервер зарегистрирован на этой машине. Канон —
|
||||||
|
`~/.claude.json` → `mcpServers.mappa` (stdio: `node <repo>/dist/src/mcp-entry.js`,
|
||||||
|
env `MAPPA_CORE_URL` + `MAPPA_API_TOKEN`). pi-рантайм читает ту же
|
||||||
|
регистрацию через MCP-адаптер.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# POSIX / Windows (git-bash):
|
||||||
|
python -c "import json; d=json.load(open('$HOME/.claude.json')); print('mappa' in d.get('mcpServers', {}))"
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Зарегистрирован** → пропустить, идти к 5.7.2.
|
||||||
|
- **Не зарегистрирован** → печать одного информационного блока (НЕ
|
||||||
|
авто-инсталл, то же правило что 5.6):
|
||||||
|
|
||||||
|
```
|
||||||
|
ℹ️ mappa MCP не зарегистрирован (~/.claude.json mcpServers.mappa отсутствует).
|
||||||
|
Установка: собери репо mappa (npm run build) и добавь в mcpServers:
|
||||||
|
{ "type": "stdio", "command": "node",
|
||||||
|
"args": ["<mappa-repo>/dist/src/mcp-entry.js"],
|
||||||
|
"env": { "MAPPA_CORE_URL": "...", "MAPPA_API_TOKEN": "..." } }
|
||||||
|
Секреты — из pass (см. secret:<path> реф-стиль, wiki:2672 решение 11).
|
||||||
|
```
|
||||||
|
|
||||||
|
mappa-конвенции в AGENTS.md (5.7.2) можно добавлять и без MCP-регистрации
|
||||||
|
— триггеры будут ждать установки сервера (как любой absent-скилл).
|
||||||
|
|
||||||
|
### 5.7.2 — mappa-конвенции в AGENTS.md (инъекция через mappa-bootstrap)
|
||||||
|
|
||||||
|
`project-bootstrap` — mappa-agnostic: mappa-триггеры **не хардкодятся** в
|
||||||
|
шаблоне (см. `assets/AGENTS.md.template`). Инъекция канонического набора
|
||||||
|
mappa-триггеров (`inbox monitor: raise on start`, `session sync: write to
|
||||||
|
mappa`, `use project wiki`, `use task management system`, `check across all
|
||||||
|
projects`) — через скил `mappa-bootstrap` (репо mappa, единый источник):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash <mappa>/skills-core/mappa-bootstrap/assets/install.sh --triggers <project-dir>
|
||||||
|
```
|
||||||
|
|
||||||
|
После инъекции — **верифицировать** наличие строк (substring-проверка, та же
|
||||||
|
машинерия что Step 5 upgrade-merge). Если пользователь сознательно убрал
|
||||||
|
mappa-триггеры из AGENTS.md — не возвращать (уважать выбор). Источник истины
|
||||||
|
набора — mappa-bootstrap, НЕ шаблон project-bootstrap.
|
||||||
|
|
||||||
|
### 5.7.3 — методика-install (пакет из репо mappa, версия в манифест)
|
||||||
|
|
||||||
|
Методика = reference-пакет (wiki:2672 решение 3/6): mappa-скилы живут в
|
||||||
|
**репо mappa** (`mappa/skills/`, релокация task:1323, коммит 5301e85) — НЕ
|
||||||
|
в репо skills. project-bootstrap НЕ хранит тела и НЕ дублирует пути
|
||||||
|
(мёртвый маппинг на `scripts/install.sh mappa-*` убран, task:1339):
|
||||||
|
установка/триггеры/deps-check mappa-скилов делегируются скилу
|
||||||
|
`mappa-bootstrap` (репо mappa, спека wiki:3265).
|
||||||
|
|
||||||
|
1. Определить список mappa-циклов: `mappa-session-orient`,
|
||||||
|
`mappa-task-work`, `mappa-knowledge`, `mappa-messaging`,
|
||||||
|
`mappa-delegation`, `mappa-brainstorm-promote`, `mappa-closing-ritual`
|
||||||
|
(плюс остальные из `mappa/skills/`).
|
||||||
|
2. Проверить установку по правилу детекта Step 5.6 (оба пути:
|
||||||
|
`~/.claude/skills/` и `~/.agents/skills/`)? → да: пропустить
|
||||||
|
(upgrade-императив не дублировать).
|
||||||
|
3. Нет → печать информационного блока (НЕ авто-инсталл, правило 5.6):
|
||||||
|
|
||||||
|
```
|
||||||
|
ℹ️ Методика mappa не установлена. Установка (скил mappa-bootstrap,
|
||||||
|
репо mappa, НЕ skills-репо):
|
||||||
|
cd <mappa-repo> && bash skills/mappa-bootstrap/assets/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Версия методики фиксируется в bootstrap-manifest (5.7.4): читать
|
||||||
|
`SKILL.md` frontmatter каждого mappa-скилла (`version:`), не хардкодить.
|
||||||
|
|
||||||
|
### 5.7.4 — manifest/deps-check
|
||||||
|
|
||||||
|
Манифест (Step 5.5) дополняется строкой методики — версия = версия
|
||||||
|
reference-пакета (репо mappa, `version` из frontmatter скиллов; пакетная
|
||||||
|
версия — `mappa-bootstrap` из `mappa/skills/mappa-bootstrap/SKILL.md`).
|
||||||
|
Добавить в таблицу манифеста:
|
||||||
|
|
||||||
|
| Skill | Version | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| `mappa-bootstrap-project` (модуль) | <project-bootstrap version> | connect + конвенции + методика-install |
|
||||||
|
| `mappa-bootstrap` (скил, репо mappa) | <mappa-bootstrap version> | установка/триггеры/deps-check mappa-скилов |
|
||||||
|
|
||||||
|
Deps-check (Step 5.6): mappa-триггеры (`inbox monitor: raise on start`,
|
||||||
|
`use project wiki`, `use task management system`) маппятся на fulfiller'ы
|
||||||
|
через скил `mappa-bootstrap` — `bash <mappa>/skills/mappa-bootstrap/assets/install.sh --check`
|
||||||
|
(источник истины — `mappa/skills/`, НЕ репо skills; мёртвые пути
|
||||||
|
`~/.claude/skills/mappa-*/SKILL.md` из таблицы убраны, task:1339).
|
||||||
|
Недостающие mappa-скиллы → в блок рекомендаций 5.6 (тем же форматом,
|
||||||
|
install-команда — скил mappa-bootstrap, см. 5.7.3).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5.8 — `.mappa` маркер (контракт wiki:3340)
|
||||||
|
|
||||||
|
Машиночитаемый маркер проекта в корне папки (схема v1 — `.mappa/config.yaml`):
|
||||||
|
гейт mappa-скилов («без маркера папка не участвует в mappa-операциях»,
|
||||||
|
task:1546) + признак корня проекта для харнессов. Создаётся на bootstrap —
|
||||||
|
без ручного прогона генератора (task:1583). Детерминированный рендер:
|
||||||
|
фиксированный порядок полей, без секретов, без timestamp — повторный запуск
|
||||||
|
no-op (`keep`).
|
||||||
|
|
||||||
|
1. **Собрать значения** (реестр mappa → локальное знание):
|
||||||
|
- `project` — канон папки (`basename "$PWD"`); если проект уже в реестре
|
||||||
|
(`projects_resolve`) — сверить, не расходится ли;
|
||||||
|
- `tenant` — `MAPPA_TENANT` (по умолчанию `vitya`);
|
||||||
|
- `url` — `MAPPA_CORE_URL` (без trailing slash);
|
||||||
|
- `git_provider` — из реестра `projects.git_provider` (например `gitea`),
|
||||||
|
иначе из шага 1.5 (создано через Gitea API → gitea); опционально;
|
||||||
|
- `git` — `projects.qualified` (owner/repo) из реестра, иначе из remote
|
||||||
|
шага 1.5; опционально (опустить, если неизвестно).
|
||||||
|
2. **Записать маркер** (скрипт — ассет этого скила, реализует контракт
|
||||||
|
wiki:3340; в репо: `skills/project-bootstrap/assets/dot_mappa_marker.py`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python assets/dot_mappa_marker.py write \
|
||||||
|
--project "$(basename "$PWD")" --tenant vitya --url "$MAPPA_CORE_URL" \
|
||||||
|
--git-provider gitea --git "$OWNER/$REPO"
|
||||||
|
```
|
||||||
|
|
||||||
|
Без `--git-provider`/`--git`, если поля неизвестны. Повторный прогон —
|
||||||
|
no-op (`keep`); отличающийся существующий маркер без `--force` НЕ
|
||||||
|
перезаписывается — покажи diff и спроси (правило «never overwrite»).
|
||||||
|
3. **Верифицировать**: `python assets/dot_mappa_marker.py check` → exit 0.
|
||||||
|
4. **Контракт-тест** (TDD, task:1583): `python assets/test_dot_mappa_marker.py`
|
||||||
|
— «после bootstrap есть `.mappa/config.yaml`», детерминизм, без секретов,
|
||||||
|
порядок полей, идемпотентность.
|
||||||
|
|
||||||
|
Маркер публичен (без секретов) и попадает в коммит шага 6. Валидный
|
||||||
|
существующий маркер не трогаем.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Step 6 — Commit
|
## Step 6 — Commit
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -602,11 +759,13 @@ Print a final report:
|
|||||||
✅ Done! Created:
|
✅ Done! Created:
|
||||||
.wiki/ — project wiki (Karpathy method)
|
.wiki/ — project wiki (Karpathy method)
|
||||||
.tasks/ — task tracking system
|
.tasks/ — task tracking system
|
||||||
|
.mappa/ — mappa project marker (wiki:3340, schema v1)
|
||||||
AGENTS.md — skill triggers (canon)
|
AGENTS.md — skill triggers (canon)
|
||||||
CLAUDE.md — legacy pointer
|
CLAUDE.md — legacy pointer
|
||||||
.gitignore — standard template
|
.gitignore — standard template
|
||||||
README.md — starter file
|
README.md — starter file
|
||||||
remote — Gitea repo created and pushed
|
remote — Gitea repo created and pushed
|
||||||
|
mappa — mappa-bootstrap-project: connect + конвенции + методика (модуль 5.7)
|
||||||
|
|
||||||
Skipped (already existed):
|
Skipped (already existed):
|
||||||
git — left untouched
|
git — left untouched
|
||||||
@@ -622,10 +781,10 @@ Remote: <Gitea URL>
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 8 — projects-meta sync (greenfield-full mode)
|
## Step 8 — mappa registry (greenfield-full mode)
|
||||||
|
|
||||||
Only in **greenfield-full** mode. Re-sync the projects-meta cache so the new
|
Only in **greenfield-full** mode. Register the new project in mappa
|
||||||
project becomes visible to `mcp__projects-meta__*` tools.
|
(`mcp__mappa__projects_register`) so it becomes visible in the registry.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# POSIX:
|
# POSIX:
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
# AGENTS.md
|
# AGENTS.md
|
||||||
# Agent instructions. Each line is a trigger for an installed skill.
|
# Agent instructions. Each line is a trigger for an installed skill.
|
||||||
#
|
#
|
||||||
# Inter-session mail channel is Mappa (mcp__mappa__inbox_send/inbox_monitor),
|
# mappa-специфичные триггеры (inbox monitor: raise on start, session sync:
|
||||||
# NOT files. This line opts the project into inbox delivery at session start:
|
# write to mappa, use project wiki, use task management system, check across
|
||||||
inbox monitor: raise on start
|
# all projects) НЕ хардкодятся здесь — project-bootstrap mappa-agnostic. Они
|
||||||
|
# инжектятся при создании/апгрейде проекта через mappa-bootstrap:
|
||||||
|
# bash <mappa>/skills-core/mappa-bootstrap/assets/install.sh --triggers <dir>
|
||||||
|
# (см. Step 5.7.2 — mappa-конвенции в AGENTS.md, делегирование в mappa-bootstrap)
|
||||||
|
|
||||||
|
# Search rule
|
||||||
|
|
||||||
|
⛔ Never walk `node_modules/`, `dist/`, `build/`, `.nuxt/` (or any parent tree
|
||||||
|
containing them) with non-gitignore-aware search tools — measured 3701s vs rg
|
||||||
|
0s (2026-08-26). Use `rg` and NEVER `rg --no-ignore`/`-u` (those bypass the
|
||||||
|
ignore protection and walk node_modules again). Also no `grep -r`/`-R`/
|
||||||
|
`--recursive`, `ag`, `ack`, `find … -exec grep`. `grep --include` filters
|
||||||
|
result file names, NOT directory traversal — it still walks every node_modules
|
||||||
|
entry; `| grep -v node_modules` filters after the walk, doesn't save you.
|
||||||
|
|
||||||
talk like a caveman
|
talk like a caveman
|
||||||
use project wiki
|
|
||||||
use task management system
|
|
||||||
check across all projects
|
|
||||||
pull remote before work
|
pull remote before work
|
||||||
session handoff: read on start, write on end
|
|
||||||
follow project discipline
|
|
||||||
follow tdd-criteria
|
follow tdd-criteria
|
||||||
delegate to interns when allowed
|
delegate to interns when allowed
|
||||||
recommend, don't menu
|
recommend, don't menu
|
||||||
|
|||||||
263
skills/project-bootstrap/assets/dot_mappa_marker.py
Normal file
263
skills/project-bootstrap/assets/dot_mappa_marker.py
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""dot_mappa_marker.py — deterministic render + write of the `.mappa` marker.
|
||||||
|
|
||||||
|
Contract: mappa wiki:3340 (concepts/dot-mappa-marker), schema v1.
|
||||||
|
Used by project-create (step 5.5) and project-bootstrap (step 5.8) so a project
|
||||||
|
folder gets its marker at create time — no manual generator run needed
|
||||||
|
(task:1583). The batch generator (mappa `server/scripts/gen-dot-mappa-markers.ts`)
|
||||||
|
remains for registry-wide migration; this is the per-project create path.
|
||||||
|
|
||||||
|
Guarantees (the contract):
|
||||||
|
* `.mappa/config.yaml` — каталог + файл внутри
|
||||||
|
* fixed field order (schema_version, protocol_version, project, tenant, url,
|
||||||
|
git_provider?, git?)
|
||||||
|
* deterministic render — no timestamps, same input → same bytes
|
||||||
|
* NO secrets — only public registry fields; url with credentials is rejected
|
||||||
|
* optional fields (`git_provider`, `git`) omitted when absent
|
||||||
|
* idempotent write: same content → no-op (keep); different content → refuse
|
||||||
|
without --force
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python dot_mappa_marker.py render --project NAME --tenant TENANT --url URL \
|
||||||
|
[--git-provider P] [--git OWNER/REPO] # print content to stdout
|
||||||
|
python dot_mappa_marker.py write --project NAME --tenant TENANT --url URL \
|
||||||
|
[--git-provider P] [--git OWNER/REPO] [--dir PATH] [--force] # write marker
|
||||||
|
python dot_mappa_marker.py check --dir PATH # verify existing marker
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
SCHEMA_VERSION = 1
|
||||||
|
PROTOCOL_VERSION = 1
|
||||||
|
|
||||||
|
# Canonical header comment — same as the contract example (wiki:3340).
|
||||||
|
HEADER = "# mappa project marker — machine-readable identifier of a mappa project folder"
|
||||||
|
|
||||||
|
# YAML: these are indicator characters / reserved tokens — never plain.
|
||||||
|
_INDICATOR_START = set("!&*{}[],#|>@`\"'%?:~-")
|
||||||
|
_RESERVED_PLAIN = {"null", "Null", "NULL", "~", "true", "True", "TRUE", "false",
|
||||||
|
"False", "FALSE", "yes", "Yes", "YES", "no", "No", "NO",
|
||||||
|
"on", "On", "ON", "off", "Off", "OFF", "-", "?", ":"}
|
||||||
|
|
||||||
|
|
||||||
|
class MarkerConflict(Exception):
|
||||||
|
"""An existing marker differs from the requested one and --force is absent."""
|
||||||
|
|
||||||
|
|
||||||
|
def yaml_scalar(value: str) -> str:
|
||||||
|
"""YAML plain-safe scalar: plain without quotes when safe, else double-quoted.
|
||||||
|
|
||||||
|
Plain-safe = non-empty, no leading indicator, not a reserved token, no flow
|
||||||
|
chars, no embedded newlines, no surrounding whitespace. Double-quoting uses
|
||||||
|
JSON escaping, which is a valid subset of YAML double-quoted style.
|
||||||
|
"""
|
||||||
|
s = str(value)
|
||||||
|
if s == "":
|
||||||
|
return '""'
|
||||||
|
if s.strip() != s:
|
||||||
|
return json.dumps(s)
|
||||||
|
if s[0] in _INDICATOR_START or s in _RESERVED_PLAIN:
|
||||||
|
return json.dumps(s)
|
||||||
|
if s.startswith(("- ", "? ", ": ")):
|
||||||
|
return json.dumps(s)
|
||||||
|
# plain scalars stay plain unless they would confuse the parser:
|
||||||
|
# ": " (mapping indicator), trailing ":", " #" (comment), newlines/tabs
|
||||||
|
if ": " in s or s.endswith(":") or " #" in s or "\n" in s or "\t" in s:
|
||||||
|
return json.dumps(s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def validate_folder_name(name: str) -> str:
|
||||||
|
"""A folder name (canon/tenant/git_provider) must be a single sane segment."""
|
||||||
|
if not name or name in (".", ".."):
|
||||||
|
raise ValueError(f"invalid name {name!r}: must be a non-empty folder name")
|
||||||
|
if any(sep in name for sep in ("/", "\\", "\x00")):
|
||||||
|
raise ValueError(f"invalid name {name!r}: must be a single path segment")
|
||||||
|
if name != name.strip():
|
||||||
|
raise ValueError(f"invalid name {name!r}: no surrounding whitespace allowed")
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def validate_git_ref(git: str) -> str:
|
||||||
|
"""`git` = projects.qualified (owner/repo) — no credentials, no colon."""
|
||||||
|
g = str(git)
|
||||||
|
if not g or "/" not in g:
|
||||||
|
raise ValueError(f"invalid git ref {g!r}: expected owner/repo")
|
||||||
|
if any(c in g for c in ("@", ":", " ", "\t", "\n", "\\")):
|
||||||
|
raise ValueError(f"invalid git ref {g!r}: no credentials / separators allowed")
|
||||||
|
if g.startswith("/") or g.endswith("/") or ".." in g.split("/"):
|
||||||
|
raise ValueError(f"invalid git ref {g!r}: must be owner/repo, not a path")
|
||||||
|
return g
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_url(url: str) -> str:
|
||||||
|
"""Absolute http(s) URL without credentials and without trailing slash."""
|
||||||
|
u = str(url).strip()
|
||||||
|
if not (u.startswith("http://") or u.startswith("https://")):
|
||||||
|
raise ValueError(f"invalid url {u!r}: must be http(s)://host...")
|
||||||
|
authority = u.split("://", 1)[1].split("/", 1)[0]
|
||||||
|
if "@" in authority:
|
||||||
|
raise ValueError("url must not contain credentials (no secrets in the marker)")
|
||||||
|
return u.rstrip("/")
|
||||||
|
|
||||||
|
|
||||||
|
def render(
|
||||||
|
project: str,
|
||||||
|
tenant: str,
|
||||||
|
url: str,
|
||||||
|
git_provider: str | None = None,
|
||||||
|
git: str | None = None,
|
||||||
|
) -> str:
|
||||||
|
"""Deterministic `.mappa/config.yaml` content per wiki:3340 schema v1."""
|
||||||
|
project = validate_folder_name(project)
|
||||||
|
tenant = validate_folder_name(tenant)
|
||||||
|
url = normalize_url(url)
|
||||||
|
lines = [
|
||||||
|
HEADER,
|
||||||
|
f"schema_version: {SCHEMA_VERSION}",
|
||||||
|
f"protocol_version: {PROTOCOL_VERSION}",
|
||||||
|
f"project: {yaml_scalar(project)}",
|
||||||
|
f"tenant: {yaml_scalar(tenant)}",
|
||||||
|
f"url: {yaml_scalar(url)}",
|
||||||
|
]
|
||||||
|
if git_provider:
|
||||||
|
lines.append(f"git_provider: {yaml_scalar(validate_folder_name(git_provider))}")
|
||||||
|
if git:
|
||||||
|
lines.append(f"git: {yaml_scalar(validate_git_ref(git))}")
|
||||||
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _sane_dir(directory: str | Path) -> Path:
|
||||||
|
"""Resolve the target directory; reject `..` segments and non-dirs."""
|
||||||
|
p = Path(directory)
|
||||||
|
if ".." in p.parts:
|
||||||
|
raise ValueError(f"invalid directory {str(directory)!r}: '..' segments not allowed")
|
||||||
|
if p.exists() and not p.is_dir():
|
||||||
|
raise ValueError(f"invalid directory {str(directory)!r}: not a directory")
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
def write_marker(directory: str | Path, content: str, force: bool = False) -> tuple[Path, str]:
|
||||||
|
"""Write `.mappa/config.yaml` under `directory`.
|
||||||
|
|
||||||
|
Returns (marker_path, outcome) where outcome is one of
|
||||||
|
"created" | "keep" (idempotent no-op) | "overwrite" (force).
|
||||||
|
Raises MarkerConflict when an existing marker differs and force is False.
|
||||||
|
"""
|
||||||
|
marker = _sane_dir(directory) / ".mappa" / "config.yaml"
|
||||||
|
if marker.exists():
|
||||||
|
existing = marker.read_text(encoding="utf-8")
|
||||||
|
if existing == content:
|
||||||
|
return marker, "keep"
|
||||||
|
if not force:
|
||||||
|
raise MarkerConflict(
|
||||||
|
f"{marker} already exists with different content; "
|
||||||
|
"pass --force to overwrite (contract: no silent overwrite)"
|
||||||
|
)
|
||||||
|
marker.write_text(content, encoding="utf-8")
|
||||||
|
return marker, "overwrite"
|
||||||
|
marker.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
marker.write_text(content, encoding="utf-8")
|
||||||
|
return marker, "created"
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_marker_lines(body: str) -> list[tuple[str, str]]:
|
||||||
|
"""(key, value) pairs of data lines — comments skipped, first colon splits."""
|
||||||
|
pairs = []
|
||||||
|
for line in body.splitlines():
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
if ": " not in line:
|
||||||
|
raise ValueError(f"malformed marker line (no 'key: value'): {line!r}")
|
||||||
|
key, value = line.split(": ", 1)
|
||||||
|
pairs.append((key, value.strip()))
|
||||||
|
return pairs
|
||||||
|
|
||||||
|
|
||||||
|
def check_marker(directory: str | Path) -> tuple[bool, str]:
|
||||||
|
"""Gate check (wiki:3340 / task:1546): is `directory` a mappa project?
|
||||||
|
|
||||||
|
Returns (ok, message). ok means `.mappa/config.yaml` exists and its data
|
||||||
|
lines start with exactly the required fields (schema_version,
|
||||||
|
protocol_version, project, tenant, url) in canonical order with valid
|
||||||
|
values; optional `git_provider`/`git` may follow.
|
||||||
|
"""
|
||||||
|
marker = _sane_dir(directory) / ".mappa" / "config.yaml"
|
||||||
|
if not marker.is_file():
|
||||||
|
return False, f"no marker: {marker} (folder without marker is not a mappa project)"
|
||||||
|
try:
|
||||||
|
pairs = _parse_marker_lines(marker.read_text(encoding="utf-8"))
|
||||||
|
except ValueError as e:
|
||||||
|
return False, f"marker {marker}: {e}"
|
||||||
|
if len(pairs) < 5:
|
||||||
|
return False, f"marker {marker}: fewer than the 5 required fields"
|
||||||
|
required = ["schema_version", "protocol_version", "project", "tenant", "url"]
|
||||||
|
if [k for k, _ in pairs[:5]] != required:
|
||||||
|
return False, f"marker {marker}: field order mismatch ({[k for k, _ in pairs[:5]]})"
|
||||||
|
values = dict(pairs)
|
||||||
|
if values["schema_version"] != str(SCHEMA_VERSION):
|
||||||
|
return False, f"marker {marker}: schema_version must be {SCHEMA_VERSION}"
|
||||||
|
if values["protocol_version"] != str(PROTOCOL_VERSION):
|
||||||
|
return False, f"marker {marker}: protocol_version must be {PROTOCOL_VERSION}"
|
||||||
|
try:
|
||||||
|
validate_folder_name(values["project"])
|
||||||
|
validate_folder_name(values["tenant"])
|
||||||
|
normalize_url(values["url"])
|
||||||
|
if "git_provider" in values:
|
||||||
|
validate_folder_name(values["git_provider"])
|
||||||
|
if "git" in values:
|
||||||
|
validate_git_ref(values["git"])
|
||||||
|
except ValueError as e:
|
||||||
|
return False, f"marker {marker}: {e}"
|
||||||
|
return True, f"marker ok: {marker}"
|
||||||
|
|
||||||
|
|
||||||
|
def _add_common(parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.add_argument("--project", required=True, help="канон папки = реестр projects.name (slug)")
|
||||||
|
parser.add_argument("--tenant", required=True, help="тенант, где живёт проект (MAPPA_TENANT)")
|
||||||
|
parser.add_argument("--url", required=True, help="MAPPA_CORE_URL (без trailing slash)")
|
||||||
|
parser.add_argument("--git-provider", default=None, help="projects.git_provider (gitea/...) — опционально")
|
||||||
|
parser.add_argument("--git", default=None, help="projects.qualified (owner/repo) — опционально")
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=".mappa marker per wiki:3340 (schema v1)")
|
||||||
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||||
|
|
||||||
|
p_render = sub.add_parser("render", help="print deterministic marker content")
|
||||||
|
_add_common(p_render)
|
||||||
|
|
||||||
|
p_write = sub.add_parser("write", help="write .mappa/config.yaml into a folder")
|
||||||
|
_add_common(p_write)
|
||||||
|
p_write.add_argument("--dir", default=".", help="project folder (default: cwd)")
|
||||||
|
p_write.add_argument("--force", action="store_true", help="overwrite a differing marker")
|
||||||
|
|
||||||
|
p_check = sub.add_parser("check", help="gate check: is the folder a mappa project?")
|
||||||
|
p_check.add_argument("--dir", default=".", help="project folder (default: cwd)")
|
||||||
|
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
if args.cmd in ("render", "write"):
|
||||||
|
content = render(args.project, args.tenant, args.url, args.git_provider, args.git)
|
||||||
|
if args.cmd == "render":
|
||||||
|
sys.stdout.write(content)
|
||||||
|
return 0
|
||||||
|
marker, outcome = write_marker(args.dir, content, force=args.force)
|
||||||
|
print(f"{outcome}: {marker}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if args.cmd == "check":
|
||||||
|
ok, msg = check_marker(args.dir)
|
||||||
|
print(msg)
|
||||||
|
return 0 if ok else 1
|
||||||
|
|
||||||
|
return 2 # unreachable
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
290
skills/project-bootstrap/assets/test_dot_mappa_marker.py
Normal file
290
skills/project-bootstrap/assets/test_dot_mappa_marker.py
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Contract test for the `.mappa` marker — mappa wiki:3340 (concepts/dot-mappa-marker).
|
||||||
|
|
||||||
|
The contract under test (task:1583): after the project-create/bootstrap marker
|
||||||
|
step, the project folder contains `.mappa/config.yaml` matching schema v1:
|
||||||
|
fixed field order, deterministic render (no timestamps), NO secrets, optional
|
||||||
|
fields (`git_provider`, `git`) omitted when absent, idempotent write.
|
||||||
|
|
||||||
|
Run: python test_dot_mappa_marker.py (or: python -m unittest test_dot_mappa_marker)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||||
|
import dot_mappa_marker as dmm # noqa: E402
|
||||||
|
|
||||||
|
CANON = "skills" # registry projects.name — канон папки (slug)
|
||||||
|
TENANT = "vitya"
|
||||||
|
URL = "https://mappa.vds.kzntsv.site"
|
||||||
|
GIT_PROVIDER = "gitea"
|
||||||
|
GIT = "OpeItcLoc03/skills"
|
||||||
|
|
||||||
|
FIELD_ORDER = [
|
||||||
|
"schema_version",
|
||||||
|
"protocol_version",
|
||||||
|
"project",
|
||||||
|
"tenant",
|
||||||
|
"url",
|
||||||
|
"git_provider",
|
||||||
|
"git",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def field_keys(body: str) -> list[str]:
|
||||||
|
return [
|
||||||
|
line.split(":", 1)[0]
|
||||||
|
for line in body.splitlines()
|
||||||
|
if line and not line.startswith("#") and ": " in line
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def write_contract_marker(tmp: str) -> Path:
|
||||||
|
"""Helper: create a valid marker as the bootstrap step would."""
|
||||||
|
marker, outcome = dmm.write_marker(tmp, dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT))
|
||||||
|
assert outcome == "created"
|
||||||
|
return marker
|
||||||
|
|
||||||
|
|
||||||
|
class ContractTests(unittest.TestCase):
|
||||||
|
"""Contract: after bootstrap there is `.mappa/config.yaml` (task:1583)."""
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.tmp = tempfile.mkdtemp(prefix="mappa-marker-test-")
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||||
|
|
||||||
|
# --- presence / shape -------------------------------------------------
|
||||||
|
|
||||||
|
def test_bootstrap_marker_step_creates_config_yaml(self) -> None:
|
||||||
|
"""The bootstrap marker step leaves `.mappa/config.yaml` in the folder."""
|
||||||
|
content = dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT)
|
||||||
|
marker, outcome = dmm.write_marker(self.tmp, content)
|
||||||
|
self.assertEqual(outcome, "created")
|
||||||
|
self.assertTrue(marker.is_file())
|
||||||
|
self.assertEqual(marker.name, "config.yaml")
|
||||||
|
self.assertEqual(marker.parent.name, ".mappa")
|
||||||
|
|
||||||
|
def test_fixed_field_order(self) -> None:
|
||||||
|
body = dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT)
|
||||||
|
self.assertEqual(field_keys(body), FIELD_ORDER)
|
||||||
|
|
||||||
|
def test_deterministic_render_no_timestamp(self) -> None:
|
||||||
|
a = dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT)
|
||||||
|
b = dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT)
|
||||||
|
self.assertEqual(a, b)
|
||||||
|
# no ISO-date-like content
|
||||||
|
self.assertNotRegex(a, r"\d{4}-\d{2}-\d{2}")
|
||||||
|
|
||||||
|
def test_optional_fields_omitted_when_absent(self) -> None:
|
||||||
|
body = dmm.render(CANON, TENANT, URL)
|
||||||
|
self.assertEqual(field_keys(body), FIELD_ORDER[:5])
|
||||||
|
self.assertNotIn("git_provider", body)
|
||||||
|
self.assertNotIn("\ngit:", body)
|
||||||
|
|
||||||
|
def test_no_secrets_in_marker(self) -> None:
|
||||||
|
body = dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT)
|
||||||
|
lowered = body.lower()
|
||||||
|
# credentials in the url authority are rejected separately
|
||||||
|
for secret in ("token", "password", "secret", "api_key", "key:", "@"):
|
||||||
|
self.assertNotIn(secret, lowered)
|
||||||
|
|
||||||
|
# --- idempotent write --------------------------------------------------
|
||||||
|
|
||||||
|
def test_idempotent_write_keeps_same_content(self) -> None:
|
||||||
|
content = dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT)
|
||||||
|
marker, first = dmm.write_marker(self.tmp, content)
|
||||||
|
marker, second = dmm.write_marker(self.tmp, content)
|
||||||
|
self.assertEqual(first, "created")
|
||||||
|
self.assertEqual(second, "keep")
|
||||||
|
self.assertEqual(marker.read_text(encoding="utf-8"), content)
|
||||||
|
|
||||||
|
def test_refuses_overwrite_of_different_marker_without_force(self) -> None:
|
||||||
|
dmm.write_marker(self.tmp, dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT))
|
||||||
|
with self.assertRaises(dmm.MarkerConflict):
|
||||||
|
dmm.write_marker(self.tmp, dmm.render(CANON, TENANT, URL, "github", GIT))
|
||||||
|
|
||||||
|
def test_force_overwrites_different_marker(self) -> None:
|
||||||
|
dmm.write_marker(self.tmp, dmm.render(CANON, TENANT, URL, GIT_PROVIDER, GIT))
|
||||||
|
marker, outcome = dmm.write_marker(
|
||||||
|
self.tmp, dmm.render(CANON, TENANT, URL, "github", GIT), force=True
|
||||||
|
)
|
||||||
|
self.assertEqual(outcome, "overwrite")
|
||||||
|
self.assertIn("git_provider: github", marker.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
# --- input validation ---------------------------------------------------
|
||||||
|
|
||||||
|
def test_folder_name_path_segments_rejected(self) -> None:
|
||||||
|
for bad in ("../evil", "a/b", "a\\b", ".", "..", ""):
|
||||||
|
with self.assertRaises(ValueError, msg=f"name {bad!r} must be rejected"):
|
||||||
|
dmm.render(bad, TENANT, URL)
|
||||||
|
|
||||||
|
def test_url_trailing_slash_stripped_but_path_kept(self) -> None:
|
||||||
|
body = dmm.render(CANON, TENANT, URL + "//")
|
||||||
|
self.assertIn(f"url: {URL}", body)
|
||||||
|
# a trailing slash after a path must be stripped, the path kept
|
||||||
|
body2 = dmm.render(CANON, TENANT, "https://example.com/mappa/")
|
||||||
|
self.assertIn("url: https://example.com/mappa", body2)
|
||||||
|
|
||||||
|
def test_url_with_credentials_rejected(self) -> None:
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
dmm.render(CANON, TENANT, "https://user:pass@mappa.vds.kzntsv.site")
|
||||||
|
|
||||||
|
def test_url_scheme_restricted_to_http_https(self) -> None:
|
||||||
|
for bad in ("ftp://mappa.example", "javascript://x", "mappa.vds.kzntsv.site", "://x"):
|
||||||
|
with self.assertRaises(ValueError, msg=f"url {bad!r} must be rejected"):
|
||||||
|
dmm.render(CANON, TENANT, bad)
|
||||||
|
|
||||||
|
def test_git_ref_with_credentials_rejected(self) -> None:
|
||||||
|
for bad in ("user:pass@host/repo", "victor/repo@token", "../config", "/owner/repo", "owner/repo/", "owner repo", "norepo"):
|
||||||
|
with self.assertRaises(ValueError, msg=f"git {bad!r} must be rejected"):
|
||||||
|
dmm.render(CANON, TENANT, URL, GIT_PROVIDER, bad)
|
||||||
|
|
||||||
|
def test_directory_with_parent_segments_rejected(self) -> None:
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
dmm.write_marker("some/../elsewhere", dmm.render(CANON, TENANT, URL))
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
dmm.check_marker("../etc")
|
||||||
|
|
||||||
|
# --- YAML scalar edge cases -------------------------------------------
|
||||||
|
|
||||||
|
def test_yaml_scalar_quoting_edge_cases(self) -> None:
|
||||||
|
# reserved tokens / indicators must be double-quoted (never plain)
|
||||||
|
for special in ("~", "@host", "-", "?", ":", "null", "yes", "on", "true",
|
||||||
|
"a: b", "ends:", " #lead", "has tab\tinside"):
|
||||||
|
self.assertTrue(dmm.yaml_scalar(special).startswith('"'),
|
||||||
|
f"{special!r} must be double-quoted, got {dmm.yaml_scalar(special)!r}")
|
||||||
|
# plain-safe values stay plain
|
||||||
|
for plain in ("vitya", "OpeItcLoc03/skills", "https://mappa.vds.kzntsv.site",
|
||||||
|
"a:b", "x#y", "lead#ing", "my-proj"):
|
||||||
|
self.assertEqual(dmm.yaml_scalar(plain), plain)
|
||||||
|
self.assertEqual(dmm.yaml_scalar(""), '""')
|
||||||
|
|
||||||
|
# --- check_marker (gate) ----------------------------------------------
|
||||||
|
|
||||||
|
def test_check_ok_on_valid_marker(self) -> None:
|
||||||
|
write_contract_marker(self.tmp)
|
||||||
|
ok, msg = dmm.check_marker(self.tmp)
|
||||||
|
self.assertTrue(ok, msg)
|
||||||
|
|
||||||
|
def test_check_fails_on_missing_marker(self) -> None:
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertFalse(ok)
|
||||||
|
|
||||||
|
def test_check_fails_on_wrong_field_order(self) -> None:
|
||||||
|
(Path(self.tmp) / ".mappa").mkdir()
|
||||||
|
(Path(self.tmp) / ".mappa" / "config.yaml").write_text(
|
||||||
|
"# c\nproject: skills\nschema_version: 1\nprotocol_version: 1\n"
|
||||||
|
"tenant: vitya\nurl: https://mappa.vds.kzntsv.site\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertFalse(ok)
|
||||||
|
|
||||||
|
def test_check_fails_on_extra_field_before_required(self) -> None:
|
||||||
|
(Path(self.tmp) / ".mappa").mkdir()
|
||||||
|
(Path(self.tmp) / ".mappa" / "config.yaml").write_text(
|
||||||
|
"extra: sneaky\nschema_version: 1\nprotocol_version: 1\n"
|
||||||
|
"project: skills\ntenant: vitya\nurl: https://mappa.vds.kzntsv.site\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertFalse(ok)
|
||||||
|
|
||||||
|
def test_check_fails_on_wrong_versions(self) -> None:
|
||||||
|
(Path(self.tmp) / ".mappa").mkdir()
|
||||||
|
(Path(self.tmp) / ".mappa" / "config.yaml").write_text(
|
||||||
|
"schema_version: 2\nprotocol_version: 1\nproject: skills\n"
|
||||||
|
"tenant: vitya\nurl: https://mappa.vds.kzntsv.site\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertFalse(ok)
|
||||||
|
|
||||||
|
def test_check_fails_on_malicious_project_value(self) -> None:
|
||||||
|
(Path(self.tmp) / ".mappa").mkdir()
|
||||||
|
(Path(self.tmp) / ".mappa" / "config.yaml").write_text(
|
||||||
|
"schema_version: 1\nprotocol_version: 1\nproject: ../../evil\n"
|
||||||
|
"tenant: vitya\nurl: https://mappa.vds.kzntsv.site\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertFalse(ok)
|
||||||
|
|
||||||
|
def test_check_fails_on_malformed_line(self) -> None:
|
||||||
|
(Path(self.tmp) / ".mappa").mkdir()
|
||||||
|
(Path(self.tmp) / ".mappa" / "config.yaml").write_text(
|
||||||
|
"schema_version: 1\nprotocol_version: 1\nproject skills\n"
|
||||||
|
"tenant: vitya\nurl: https://mappa.vds.kzntsv.site\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertFalse(ok)
|
||||||
|
|
||||||
|
def test_check_accepts_url_with_port(self) -> None:
|
||||||
|
(Path(self.tmp) / ".mappa").mkdir()
|
||||||
|
(Path(self.tmp) / ".mappa" / "config.yaml").write_text(
|
||||||
|
"schema_version: 1\nprotocol_version: 1\nproject: skills\n"
|
||||||
|
"tenant: vitya\nurl: https://mappa.example:8443\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
ok, _ = dmm.check_marker(self.tmp)
|
||||||
|
self.assertTrue(ok)
|
||||||
|
|
||||||
|
# --- CLI end-to-end ----------------------------------------------------
|
||||||
|
|
||||||
|
def test_cli_write_creates_marker(self) -> None:
|
||||||
|
"""End-to-end: the documented CLI command produces the marker."""
|
||||||
|
proc = subprocess.run(
|
||||||
|
[
|
||||||
|
sys.executable,
|
||||||
|
str(Path(__file__).resolve().parent / "dot_mappa_marker.py"),
|
||||||
|
"write",
|
||||||
|
"--project", CANON,
|
||||||
|
"--tenant", TENANT,
|
||||||
|
"--url", URL,
|
||||||
|
"--git-provider", GIT_PROVIDER,
|
||||||
|
"--git", GIT,
|
||||||
|
"--dir", self.tmp,
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(proc.returncode, 0, proc.stderr)
|
||||||
|
marker = Path(self.tmp) / ".mappa" / "config.yaml"
|
||||||
|
self.assertTrue(marker.is_file())
|
||||||
|
self.assertEqual(field_keys(marker.read_text(encoding="utf-8")), FIELD_ORDER)
|
||||||
|
|
||||||
|
def test_cli_check_verifies_marker(self) -> None:
|
||||||
|
write_contract_marker(self.tmp)
|
||||||
|
script = Path(__file__).resolve().parent / "dot_mappa_marker.py"
|
||||||
|
ok = subprocess.run(
|
||||||
|
[sys.executable, str(script), "check", "--dir", self.tmp],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(ok.returncode, 0, ok.stderr)
|
||||||
|
# check on an empty dir fails (gate semantics: no marker → not a mappa project)
|
||||||
|
empty = tempfile.mkdtemp(prefix="mappa-marker-empty-")
|
||||||
|
try:
|
||||||
|
missing = subprocess.run(
|
||||||
|
[sys.executable, str(script), "check", "--dir", empty],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
self.assertNotEqual(missing.returncode, 0)
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(empty, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main(verbosity=2)
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# project-discipline
|
|
||||||
|
|
||||||
Policy skill that codifies four cross-project discipline rules so the same
|
|
||||||
guarantees that hold in a tightly-maintained repo apply everywhere.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- **Session start** — when `AGENTS.md` contains the line `follow project discipline` (added by `project-bootstrap` v2.0.0+).
|
|
||||||
- **In-chat** — when the user says "use project discipline", "соблюди дисциплину", "проектные правила", or close variants.
|
|
||||||
|
|
||||||
## The four rules
|
|
||||||
|
|
||||||
1. **Project conventions over skill defaults.** `AGENTS.md` / `.wiki/CLAUDE.md` / `.tasks/` override any other skill's defaults. Specs go to `.wiki/concepts/`, tasks to `.tasks/`.
|
|
||||||
2. **Master-only.** All work on `master` (or `main`). No feature branches without explicit user approval.
|
|
||||||
3. **Semver discipline.** Bump `version:` in `SKILL.md` / `package.json` / `pyproject.toml` on every edit per MAJOR / MINOR / PATCH; record in commit message; rebuild `dist/` artifacts after.
|
|
||||||
4. **Push freely by default.** No confirmation needed for push; a local push-gate skill (e.g. books — auto-deploy) overrides per project. Force / delete / non-ff push always asks.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
None. The skill is a textual policy document; it takes no actions and has no
|
|
||||||
external dependencies. Activate it by adding `follow project discipline` to
|
|
||||||
`AGENTS.md` (or use `project-bootstrap` v2.0.0+ which adds it automatically).
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- `project-bootstrap` (v2.0.0+) — adds the trigger line to new and existing projects' `AGENTS.md`.
|
|
||||||
- `pulling-before-work` — companion skill activated by the canonical template; pulls origin once at session start (`git pull --ff-only`).
|
|
||||||
- `using-tasks` / `using-wiki` — the format conventions Rule 1 routes work into.
|
|
||||||
- `.wiki/concepts/project-discipline-design.md` (in `skills`) — full design rationale.
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
---
|
|
||||||
name: project-discipline
|
|
||||||
author: ours
|
|
||||||
version: 0.2.2
|
|
||||||
description: >
|
|
||||||
Codifies five cross-project discipline rules: (1) project AGENTS.md /
|
|
||||||
.wiki/CLAUDE.md / .tasks/ override defaults from other skills (specs →
|
|
||||||
.wiki/concepts/, tasks → .tasks/); (2) master-only, no feature branches
|
|
||||||
without approval; (3) semver bump on every edit of versioned artifacts
|
|
||||||
(SKILL.md, package.json, pyproject.toml), recorded in commit;
|
|
||||||
(4) push freely by default — no confirmation needed;
|
|
||||||
a local push-gate skill (e.g. books — auto-deploy)
|
|
||||||
overrides per project; force/delete/non-ff always ask;
|
|
||||||
(5) transit/brainstorm workspaces — artifacts to .brainstorm/ or global wiki
|
|
||||||
only via explicit user direction. Activated by "follow project discipline"
|
|
||||||
trigger in AGENTS.md (added by project-bootstrap v2.0.0+).
|
|
||||||
---
|
|
||||||
|
|
||||||
# project-discipline
|
|
||||||
|
|
||||||
> Four cross-project rules. Read at session start. Apply before any other skill's defaults touch paths, branches, versions, or remote pushes.
|
|
||||||
|
|
||||||
## When this runs
|
|
||||||
|
|
||||||
**At session start** — when `AGENTS.md` contains the line `follow project discipline`. The skill is a policy document; the agent reads it and applies the four rules to all subsequent work in the session.
|
|
||||||
|
|
||||||
**On explicit reference** — when the user says "use project discipline", "соблюди дисциплину", "проектные правила", "что у меня по правилам?", or close variants asking about/applying the rules.
|
|
||||||
|
|
||||||
The skill itself takes no actions and has no external side-effects. It instructs the agent how to behave.
|
|
||||||
|
|
||||||
## Rule 1 — Project conventions override skill defaults
|
|
||||||
|
|
||||||
Before applying defaults from any other skill (frontend-design, mcp-builder, etc.), read in this order:
|
|
||||||
|
|
||||||
1. `AGENTS.md` in the project root.
|
|
||||||
2. `.wiki/CLAUDE.md` (if it exists).
|
|
||||||
3. `.tasks/STATUS.md` (if it exists).
|
|
||||||
|
|
||||||
Any path, format, or workflow explicitly stated in those files **overrides the skill default**. (CLAUDE.md, where present, is a legacy pointer — read it, then follow the canon in AGENTS.md.)
|
|
||||||
|
|
||||||
Concrete consequences:
|
|
||||||
|
|
||||||
- **Specs / design documents** go to `.wiki/concepts/<topic>-design.md`.
|
|
||||||
- **Task tracking / implementation plans** go to `.tasks/<slug>.md` plus a board entry in `.tasks/STATUS.md` (the `using-tasks` format).
|
|
||||||
- **Frontmatter, naming conventions, log format** — as described in the project's `.wiki/CLAUDE.md`.
|
|
||||||
|
|
||||||
If no convention is stated explicitly — fall back to the skill default.
|
|
||||||
|
|
||||||
## Rule 2 — Master-only
|
|
||||||
|
|
||||||
All work happens on the repo's main integration branch — usually `master`, but if a project uses `main`, treat `main` as equivalent.
|
|
||||||
|
|
||||||
- No `git checkout -b feature/foo` for solo work.
|
|
||||||
- Sync with remote: `git pull --ff-only` or `git pull --rebase`. **No merge commits** for solo work.
|
|
||||||
- If a task genuinely requires isolation (large experiment, risky refactor with rollback potential, multi-day work with intermediate WIP commits) — **ask** the user: "this needs its own branch, ok?" — and wait for explicit approval. Without approval, work continues on master.
|
|
||||||
|
|
||||||
If the agent finds itself on a non-main branch (after a manual `git checkout`) or in detached HEAD — report it and ask whether to return to master before working.
|
|
||||||
|
|
||||||
## Rule 3 — Versioning discipline
|
|
||||||
|
|
||||||
When editing any artifact with a semver field, **bump the version before committing** per:
|
|
||||||
|
|
||||||
- **MAJOR** (`X+1.0.0`) — breaks the contract. Renames, removed triggers, layout changes, removed public functions, breaking API change.
|
|
||||||
- **MINOR** (`X.Y+1.0`) — adds capability without breaking. New trigger, new optional step, new public function.
|
|
||||||
- **PATCH** (`X.Y.Z+1`) — wording / clarity / typo fixes with no behavior change.
|
|
||||||
|
|
||||||
The bump is recorded in the commit message: `feat(<artifact>): … [vX.Y.Z]` or whatever convention the project uses (see Rule 1).
|
|
||||||
|
|
||||||
**Applies to:** `skills/<name>/SKILL.md` (`version:` in frontmatter), `package.json` (`"version":`), `pyproject.toml` (`version =`), `Cargo.toml` (`version =`), and any other semver field in any other manifest.
|
|
||||||
|
|
||||||
**If the artifact is packaged** as `dist/<name>.skill`, `dist/*.tgz`, etc. — **rebuild** the package in the same or the next commit. Forgotten dist artifacts are a common cause of deploying stale binaries.
|
|
||||||
|
|
||||||
**First edit of an unversioned artifact** that COULD have a semver field (a new skill without `version:`, a new `package.json` without `"version":`) — **add** `version: 0.1.0` (or its equivalent) before committing; do not bump anything.
|
|
||||||
|
|
||||||
**Does not apply to:** artifacts with no semver field and no potential for one (wiki concept pages, README.md, shell scripts without a public interface).
|
|
||||||
|
|
||||||
## Rule 4 — Push freely, gate only where a local gate exists
|
|
||||||
|
|
||||||
**Default: push freely.** An ordinary fast-forward `git push` to the configured
|
|
||||||
upstream needs no per-push confirmation. No ask-before-push mode by default.
|
|
||||||
|
|
||||||
**Per-project push gate.** A project whose push triggers side effects carries a
|
|
||||||
LOCAL project-scope skill (convention: `push-gate`) that replaces this default
|
|
||||||
with ask-before-push for that project. Example: `books` — push to master runs
|
|
||||||
Gitea Actions auto-deploy. Respect the local gate over this rule: if the project
|
|
||||||
has a `push-gate` skill, its semantics win for that project; this rule's
|
|
||||||
free-push default does not apply there.
|
|
||||||
|
|
||||||
**Always ask:**
|
|
||||||
|
|
||||||
- `git push --force` / `--force-with-lease` (history rewrite);
|
|
||||||
- `git push origin --delete <branch>` (branch deletion);
|
|
||||||
- push to a remote/branch other than the current tracked upstream (`git push other-remote ...`, `git push origin other-branch`);
|
|
||||||
- push to the main branch that would require non-fast-forward (i.e. would need force).
|
|
||||||
|
|
||||||
Anything else is an ordinary fast-forward push and proceeds without a gate.
|
|
||||||
|
|
||||||
**What counts as "push":** only `git push` family commands. Local commits, `git stash push`, etc. are not push.
|
|
||||||
|
|
||||||
## Rule 5 — Transit-zone / brainstorm workspaces
|
|
||||||
|
|
||||||
Some workspaces are **transit zones** — discussion areas with no `.tasks/`, where brainstorm artifacts are explicitly NOT auto-promoted to project wikis.
|
|
||||||
|
|
||||||
**Default destination for brainstorm artifacts:**
|
|
||||||
- **In-progress brainstorm outputs** → `.brainstorm/<topic>.md` (or whatever the workspace's README/AGENTS.md declares)
|
|
||||||
- **Mature, cross-cutting outputs** → `~/projects/.wiki/concepts/<topic>-design.md` via `mcp__projects-meta__knowledge_ingest` — **only** when user explicitly directs this
|
|
||||||
|
|
||||||
**Agent must NOT auto-promote** brainstorm artifacts to global wikis by analogy with Rule 1. Convergence-moment (move from workspace to permanent wiki) is a user decision, not an automatic action.
|
|
||||||
|
|
||||||
**Example:** `~/projects/.meeting-room/` is a transit zone. Its AGENTS.md explicitly states "no `.tasks/`, transit zone, artifacts go to `.brainstorm/` or global wiki via user command." Rule 1's "project conventions override" applies, but the override is explicit in the workspace contract — auto-promotion by analogy would violate that contract.
|
|
||||||
|
|
||||||
**When in doubt:** ask the user "this goes to `.brainstorm/`, or should I promote to shared wiki?" rather than assuming.
|
|
||||||
|
|
||||||
## Out of scope
|
|
||||||
|
|
||||||
The skill **does not**:
|
|
||||||
|
|
||||||
- modify `AGENTS.md` (that's `project-bootstrap`'s job);
|
|
||||||
- enforce rules via git hooks / pre-commit / CI (this is agent discipline, not tooling);
|
|
||||||
- manage `settings.json` permissions (that's `update-config`);
|
|
||||||
- check the existence of `.wiki/` / `.tasks/` on disk (мета в mappa, решение 14/15: вики/таски — сущности сервиса через `using-wiki` / `using-tasks`; файловый layout — легаси); if a project has neither, Rule 1 simply finds no overrides and falls back to skill defaults.
|
|
||||||
|
|
||||||
## Why this exists
|
|
||||||
|
|
||||||
In a tightly-disciplined repo (`skills`) the four rules already hold by accident — the agent reads `.wiki/CLAUDE.md`, knows specs go to `.wiki/concepts/`, knows to bump `version:`, knows not to push without confirmation. In **other** projects of the same user, that discipline does not transfer: the agent falls back to vendor-default paths (`docs/specs/`, `docs/plans/`), branches on a whim, forgets `version:` bumps, and pushes without asking. This skill makes the discipline explicit and portable.
|
|
||||||
|
|
||||||
Full design rationale (why one skill instead of four, why a skill instead of inline `AGENTS.md` lines, scope of each rule, push-permission mechanism choice) lives in `.wiki/concepts/project-discipline-design.md` (in this repo; in other projects bootstrapped from this repo, the design lives in `skills`).
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# pulling-before-work
|
|
||||||
|
|
||||||
Policy skill that pulls the current branch from `origin` once at session start
|
|
||||||
and on explicit re-sync requests. Designed to remove the "edited on stale base"
|
|
||||||
footgun without trampling dirty work-trees or auto-merging.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- **Session start** — when `AGENTS.md` contains the line `pull remote before work` (added by `project-bootstrap` v2.0.0+).
|
|
||||||
- **In-chat** — when the user says `sync`, `resync`, `pull`, `обнови репо`, `git pull please`, or close variants.
|
|
||||||
|
|
||||||
Stays silent in non-git folders. Prints one informational line and exits in:
|
|
||||||
no `origin` remote, no upstream tracking, dirty work-tree, detached HEAD.
|
|
||||||
|
|
||||||
## What it does
|
|
||||||
|
|
||||||
`git pull --ff-only` against the configured upstream — never auto-merges, never
|
|
||||||
auto-rebases, never stashes, never commits, never pushes. On divergence it prints
|
|
||||||
a warning with manual-resolution hints and exits.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
None. The skill is a no-op outside git repos and folders without an `origin`
|
|
||||||
remote, so it's safe to leave activated everywhere.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- `project-bootstrap` (v2.0.0+) — adds the trigger line to new and existing projects' `AGENTS.md`.
|
|
||||||
- `.wiki/concepts/pulling-before-work-design.md` (in projects bootstrapped from this repo: this design lives in `skills`) — full design rationale.
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
---
|
|
||||||
name: pulling-before-work
|
|
||||||
author: ours
|
|
||||||
version: 1.1.0
|
|
||||||
description: >
|
|
||||||
Pulls the current branch from origin once at session start and on explicit
|
|
||||||
re-sync requests. Use when AGENTS.md contains the trigger line "pull remote
|
|
||||||
before work", or when the user says "sync", "resync", "pull", "обнови репо",
|
|
||||||
"git pull please", or close variants asking to refresh from the remote.
|
|
||||||
Runs `git pull --ff-only` — never auto-merges or rebases. Also sets the
|
|
||||||
repo-local pull policy (`pull.rebase=true` + `pull.ff=only`, set-if-absent)
|
|
||||||
so plain manual `git pull` never creates merge commits either. Stays silent
|
|
||||||
in non-git folders. Prints one informational line and exits when there is no
|
|
||||||
origin remote, no upstream tracking, the working tree is dirty, or HEAD is
|
|
||||||
detached. Does not stash, commit, or push. Activated by `project-bootstrap`
|
|
||||||
v1.4.0+ via the canonical AGENTS.md template.
|
|
||||||
---
|
|
||||||
|
|
||||||
# pulling-before-work
|
|
||||||
|
|
||||||
> Pull from `origin` once when work starts. Don't auto-merge. Don't trample dirty work-trees. Don't ask twice in the same session unless asked.
|
|
||||||
|
|
||||||
## When this runs
|
|
||||||
|
|
||||||
**At session start** — once, when the skill is activated by the `pull remote before work` line in `AGENTS.md`. The cycle below runs immediately.
|
|
||||||
|
|
||||||
**On explicit re-sync** — when the user says any of: `sync`, `resync`, `pull`, `обнови репо`, `pull please`, `git pull`, `подтяни`, `pull from origin`. Re-runs the full cycle. There is no per-session counter; the user is always allowed to ask.
|
|
||||||
|
|
||||||
**Never** before each commit, before each tool call, on every message, or in any other implicit cadence. Mode-3 ("start + on-demand") was the explicit design choice — see `.wiki/concepts/pulling-before-work-design.md`.
|
|
||||||
|
|
||||||
## The pull cycle
|
|
||||||
|
|
||||||
Run these checks in order. Print at most one line of chat output per run.
|
|
||||||
|
|
||||||
### 1. Inside a git work-tree?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rev-parse --is-inside-work-tree 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
If the command fails or prints anything other than `true` → **exit silently, no chat output.** This is the not-a-git-repo case; the skill must not be noisy in random folders.
|
|
||||||
|
|
||||||
### 1b. Ensure the repo's local pull policy (set-if-absent)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git config --local --get pull.rebase >/dev/null 2>&1 || git config --local pull.rebase true
|
|
||||||
git config --local --get pull.ff >/dev/null 2>&1 || git config --local pull.ff only
|
|
||||||
```
|
|
||||||
|
|
||||||
Sets the repo-local pull policy to the snolla baseline: plain `git pull` rebases instead of creating a merge commit (`pull.rebase=true`), and the merge path refuses non-fast-forwards (`pull.ff=only`). **Set-if-absent only** — an explicit local override the user wrote is never clobbered. Silent: no chat output, idempotent, works in dirty trees. Git config is untracked, so this never dirties `git status`. The skill's own pull below still uses `--ff-only` on purpose: a silent session-start pull never leaves the repo mid-rebase; divergence is always resolved by the human.
|
|
||||||
|
|
||||||
### 2. Has an `origin` remote?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote get-url origin 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
If the command fails (no such remote) → print one line and exit:
|
|
||||||
|
|
||||||
```
|
|
||||||
no origin remote — skip pull
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Is the working tree clean?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git status --porcelain
|
|
||||||
```
|
|
||||||
|
|
||||||
If the output is non-empty → print one line and exit:
|
|
||||||
|
|
||||||
```
|
|
||||||
working tree dirty — skipping pull. commit/stash, потом скажи "sync"
|
|
||||||
```
|
|
||||||
|
|
||||||
Never stash automatically. Stash-pop conflicts are exactly the friction this skill exists to remove.
|
|
||||||
|
|
||||||
### 4. Is HEAD attached?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git symbolic-ref -q HEAD
|
|
||||||
```
|
|
||||||
|
|
||||||
If the command fails (empty output, exit 1) → detached HEAD. Print:
|
|
||||||
|
|
||||||
```
|
|
||||||
detached HEAD — skip pull
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Does the current branch have an upstream?
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
Capture the upstream name (e.g. `origin/master`). If the command fails → no upstream tracking. Print:
|
|
||||||
|
|
||||||
```
|
|
||||||
no upstream tracking for <branch> — skip pull
|
|
||||||
```
|
|
||||||
|
|
||||||
(Where `<branch>` is `git rev-parse --abbrev-ref HEAD`.)
|
|
||||||
|
|
||||||
### 6. Pull, fast-forward only
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git pull --ff-only
|
|
||||||
```
|
|
||||||
|
|
||||||
(No args — uses the configured upstream captured above.)
|
|
||||||
|
|
||||||
Classify by exit code and stdout:
|
|
||||||
|
|
||||||
| Result | Print |
|
|
||||||
|---|---|
|
|
||||||
| Already up to date | `✅ already up to date with <upstream>` |
|
|
||||||
| Fast-forward, N commits | `✅ pulled N commits from <upstream>` |
|
|
||||||
| Non-fast-forward / diverged (exit non-zero with "diverged" or "non-fast-forward" in output) | `⚠️ diverged from <upstream> — resolve manually (plain git pull rebases by default; git pull --no-ff for a merge commit); skill never auto-merges/rebases` |
|
|
||||||
|
|
||||||
### Out of scope
|
|
||||||
|
|
||||||
The skill never:
|
|
||||||
|
|
||||||
- commits, stashes, or pushes
|
|
||||||
- recurses into submodules
|
|
||||||
- pulls from non-`origin` remotes
|
|
||||||
- pulls on detached HEAD
|
|
||||||
- runs auto-merge or auto-rebase
|
|
||||||
- overwrites an existing local pull policy (set-if-absent only)
|
|
||||||
- runs more than once per session unless the user asks
|
|
||||||
|
|
||||||
## Recovery hints
|
|
||||||
|
|
||||||
If the skill skipped because of a dirty tree:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Windows / PowerShell
|
|
||||||
git status # see what's dirty
|
|
||||||
git add . ; git commit -m "wip"
|
|
||||||
# then ask the agent: "sync"
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Linux / macOS
|
|
||||||
git status
|
|
||||||
git add . && git commit -m "wip"
|
|
||||||
# then say "sync"
|
|
||||||
```
|
|
||||||
|
|
||||||
If the skill reported `diverged`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Option A (repo default, set by step 1b): rebase your local commits on top of origin
|
|
||||||
git pull
|
|
||||||
|
|
||||||
# Option B: explicit merge commit
|
|
||||||
git pull --no-ff
|
|
||||||
```
|
|
||||||
|
|
||||||
The skill stays out of these decisions on purpose — both options have valid use cases and the user owns the choice.
|
|
||||||
|
|
||||||
## Why this exists
|
|
||||||
|
|
||||||
Stale local branches are a silent footgun: edits land on top of yesterday's `origin`, the divergence shows up at push time, and by then there's a chunk of work to rebase or merge on the wrong base. One pull at start covers the common case; an explicit re-sync trigger handles long sessions where someone pushed mid-flight.
|
|
||||||
|
|
||||||
Full design rationale (mode choice, dirty-tree skip vs stash, `--ff-only` vs auto-merge, the upstream-check) lives in `.wiki/concepts/pulling-before-work-design.md`.
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
---
|
|
||||||
name: report-mappa-issue
|
|
||||||
author: ours
|
|
||||||
version: 0.1.0
|
|
||||||
description: >
|
|
||||||
Use when working with mappa (MCP tools `mcp__mappa__*`, HTTP-роуты, скилы на
|
|
||||||
mappa) and anything deviates from the expected workflow: 500/5xx, «entity not
|
|
||||||
found» для id, который должен существовать, неожиданная форма ответа,
|
|
||||||
таймауты, молчаливые сбои, неверный статус, нестабильность. Report it by
|
|
||||||
mail to `mappa` AND `.workshop` — never swallow, never only-local-log, never
|
|
||||||
only in-chat. TEMPORARY skill: active while mappa is unstable; retire when
|
|
||||||
stabilized. Triggers: «маппа отдала 500», «entity not found», «неожиданный
|
|
||||||
ответ от mappa», «mappa вернула», "mappa returned 500", "entity not found",
|
|
||||||
unexpected mappa response.
|
|
||||||
---
|
|
||||||
|
|
||||||
# report-mappa-issue
|
|
||||||
|
|
||||||
Любое отклонение от ожидаемого mappa-воркфлоу репортится **почтой в `mappa`
|
|
||||||
и `.workshop`** — немедленно, с evidence. Не глотать, не прятать в локальный
|
|
||||||
лог, не откладывать «до сборника».
|
|
||||||
|
|
||||||
> ⚠️ **TEMPORARY (временный скил):** действует, пока mappa нестабильна. Это
|
|
||||||
> stopgap для сбора сигналов к стабилизации. Когда mappa стабилизируется
|
|
||||||
> (неделя без репортов) — скил отзывается: репорты становятся обычными
|
|
||||||
> баг-тасками. Владелец решения об отзыве — workshop.
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
Репортить, когда в ходе работы с mappa произошло **любое** из:
|
|
||||||
|
|
||||||
- **5xx / 500 / 502** на любом вызове (`task_*`, `wiki_*`, `inbox_*`, `entity_*`,
|
|
||||||
`admin_*`, `graph_*`, HTTP-роуты).
|
|
||||||
- **«Entity not found» / 404** для id/ref, который **должен** существовать
|
|
||||||
(знаешь, что создавал; видишь в свежем ответе; ссылается другое письмо/таска).
|
|
||||||
- **Неожиданная форма ответа** — поля не совпадают с документированными,
|
|
||||||
пустой `rows` где ожидались данные, новый/неожиданный тип в ответе.
|
|
||||||
- **Таймауты / зависания** вызова.
|
|
||||||
- **Молчаливый сбой** — вызов «успешен», но эффекта нет (таска не создалась,
|
|
||||||
письмо не ушло, статус не поменялся).
|
|
||||||
- **Ретрай сработал** — даже если повторный вызов прошёл: сама нестабильность
|
|
||||||
— сигнал для стабилизации (пометь `retry: resolved`).
|
|
||||||
- **Неверный/неожиданный статус** сущности, рассинхрон борда и реальности.
|
|
||||||
|
|
||||||
**Ретраи допустимы** (1–2 с паузой), но репорт — независимо от исхода ретрая:
|
|
||||||
случай 500 → репорт; случай 500→ретрай→ок → репорт с `retry: resolved`.
|
|
||||||
|
|
||||||
## When NOT to use
|
|
||||||
|
|
||||||
- **Ожидаемый 404** — сущность действительно не существует и не должна
|
|
||||||
(никогда не создавалась; удалена по дизайну). Проверь перед репортом, что
|
|
||||||
сущность обязана была быть.
|
|
||||||
- **Документированные известные ограничения** (например, «verify на проде
|
|
||||||
невозможен по дизайну», «прод stale до редеплоя» — если это задокументировано
|
|
||||||
и известно команде mappa).
|
|
||||||
- **Отклонения НЕ от mappa** — VDS/docker (→ using-vds-ops), projects-meta кэш
|
|
||||||
(документированная сталезность), провайдеры моделей. Только mappa.
|
|
||||||
- **Уже зарепорченный тот же инцидент** — не дублируй (см. Dedup).
|
|
||||||
|
|
||||||
## Core pattern — репорт
|
|
||||||
|
|
||||||
Каждый вызов: `mcp__mappa__inbox_send` в **оба** адреса (`mappa` и `.workshop`,
|
|
||||||
адреса из адресной книги `~/projects/.wiki/concepts/projects-address-book.md`),
|
|
||||||
`from` = своё имя папки. Формат письма:
|
|
||||||
|
|
||||||
```
|
|
||||||
Subject: [mappa-issue] <симптом> @ <тул/эндпоинт> (<дата>)
|
|
||||||
|
|
||||||
Body:
|
|
||||||
- Expected: <что должно было произойти по воркфлоу/докам>
|
|
||||||
- Actual: <ошибка/статус/ответ — текст сообщения или короткий сниппет>
|
|
||||||
- Call: <тул + ключевые параметры / эндпоинт + project>
|
|
||||||
- Retry: <сработал ли ретрай, сколько попыток>
|
|
||||||
- Recurrence: <первый раз / повторяется — сколько раз за сессию>
|
|
||||||
- Context: <проект, сессия, какой флоу шёл>
|
|
||||||
```
|
|
||||||
|
|
||||||
Одно письмо = **один инцидент** (симптом × эндпоинт). Рекуррентность — в том же
|
|
||||||
письме (`recurrence: 5 раз за 2 часа`), не новый репорт на каждый вызов.
|
|
||||||
|
|
||||||
## Common mistakes / rationalizations
|
|
||||||
|
|
||||||
| Рационализация | Реальность |
|
|
||||||
|---|---|
|
|
||||||
| «Mappa упала — письмо не дойдёт, зачем писать» | Письмо — сущность в Mappa (карв-аут, без лиза). При оживлении сервиса оно будет в инбоксе получателя. Пиши всегда. |
|
|
||||||
| «Расскажу человеку в чате» | Человек не всегда в сессии, команда mappa чат не видит. Письмо — durable и кросс-сессионно. |
|
|
||||||
| «Запишу в локальный лог» | Локальный лог не виден команде mappa. Цель репорта — видимость у получателей. (Локальная запись — дополнительно, не вместо.) |
|
|
||||||
| «Ретрай сработал — значит ок» | Нестабильность — сам по себе сигнал. Репорть с `retry: resolved`. |
|
|
||||||
| «Это мелочь, не буду спамить» | Пока mappa нестабильна — любой сигнал материал для стабилизации. Dedup защищает от спама, не молчание. |
|
|
||||||
| «Соберу несколько и отпишусь разом» | Первое вхождение — немедленно. Рекуррентность докидывай в то же письмо. |
|
|
||||||
| «Это наверняка уже известно mappa» | Неизвестно, пока не зарепорчено. Репорт — это и есть способ сделать известным. |
|
|
||||||
|
|
||||||
## Red flags — STOP
|
|
||||||
|
|
||||||
- Поймал ошибку mappa и продолжил молча (без репорта).
|
|
||||||
- Записал только локально / сказал только в чате — письма нет.
|
|
||||||
- Пропустил «entity not found», не проверив, должен ли id существовать.
|
|
||||||
- Отложил репорт «на потом» без письма и без таски.
|
|
||||||
- Зарепортил, но не в оба адреса (`mappa` и `.workshop`).
|
|
||||||
|
|
||||||
## Cross-agent
|
|
||||||
|
|
||||||
Канал — mappa inbox (`inbox_send` / `inbox.monitor`), общий для всех агентов
|
|
||||||
(pi: `mcp__mappa__inbox_send`; Claude Code: те же MCP-тулы; headless — то же).
|
|
||||||
Адресация — строго из адресной книги (`inter-session-messaging` канон).
|
|
||||||
|
|
||||||
## Out of scope
|
|
||||||
|
|
||||||
- **Не чинит mappa** — диагностика/починка сервиса отдельно; скил только
|
|
||||||
репортит. (Глубокий диагноз — `diagnosing-bugs` / `using-vds-ops` для инфры.)
|
|
||||||
- **Не репортит чужие сервисы** — только отклонения от mappa-воркфлоу.
|
|
||||||
- **Не заменяет** `inter-session-messaging` (механика отправки — там, этот скил
|
|
||||||
задаёт политику «что считать инцидентом»).
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: review-kit-pi-method
|
name: review-kit-pi-method
|
||||||
author: ours
|
author: ours
|
||||||
version: 0.1.1
|
version: 0.1.2
|
||||||
description: >
|
description: >
|
||||||
Spawn clean-context non-implementer subagents for review, trigger-testing,
|
Spawn clean-context non-implementer subagents for review, trigger-testing,
|
||||||
and spec validation under pi — the pi-native port of the review-kit method.
|
and spec validation under pi — the pi-native port of the review-kit method.
|
||||||
@@ -124,6 +124,26 @@ non-implementer subagents, anti-priming checklist, negative controls — is
|
|||||||
agent-agnostic and transfers to any runtime that can spawn a fresh-context
|
agent-agnostic and transfers to any runtime that can spawn a fresh-context
|
||||||
subprocess (claude `-p`, codex exec, hermes headless).
|
subprocess (claude `-p`, codex exec, hermes headless).
|
||||||
|
|
||||||
|
### CC-спавн (claude-code через deepseek) — live-проверен 2026-09-01 (session:974)
|
||||||
|
|
||||||
|
CC (`claude -p`) умеет субагент-ревью БЕЗ скилов: тот же чистый контекст
|
||||||
|
(флаги изоляции) через обёртку `claude-deepseek`
|
||||||
|
(`.common/scripts/claude-switch.ps1`; env `ANTHROPIC_BASE_URL=
|
||||||
|
https://api.deepseek.com/anthropic` + ключ из `~/.deepseek_api_key`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "<question>" \
|
||||||
|
--output-format stream-json --verbose \
|
||||||
|
--model deepseek-v4-flash-vision-exp \
|
||||||
|
--tools "" --disable-slash-commands --no-session-persistence
|
||||||
|
```
|
||||||
|
|
||||||
|
Флаги изоляции (аналог `-nc -ns -nt` pi): `--tools ""` (нет тулов —
|
||||||
|
не читает файлы, не самопраймится), `--disable-slash-commands` (нет
|
||||||
|
команд-интерпретатора), `--no-session-persistence` (эфемерно, без
|
||||||
|
сессионного блода). Анти-прайминг-чеклист и правила промпта — те же, что
|
||||||
|
выше (ask the behavior, one question per run, negative controls).
|
||||||
|
|
||||||
## Out of scope
|
## Out of scope
|
||||||
|
|
||||||
- Does NOT define the review criteria themselves (skill-specific acceptance —
|
- Does NOT define the review criteria themselves (skill-specific acceptance —
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
---
|
|
||||||
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` — 3–5 последних коммитов (`<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 любую её часть.
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
# session-handoff hooks
|
|
||||||
|
|
||||||
Opt-in PostToolUse hook that detects substantive `git commit` invocations and signals the agent ("consider running session-handoff write-mode") via a system reminder. Replaces the agent-side commit-detection heuristic in the SKILL.md `When to use` section with a deterministic harness-side trigger.
|
|
||||||
|
|
||||||
## Why opt-in (not auto-installed)
|
|
||||||
|
|
||||||
`install.sh` deliberately does **not** mutate `~/.claude/settings.json`. Auto-rewriting the user's hook config on every skill install is the wrong shape — user expects `install.sh` to copy files, nothing more. The hook is shipped as scripts; user enables it once per machine.
|
|
||||||
|
|
||||||
## Enable on Windows (PowerShell)
|
|
||||||
|
|
||||||
Add to `~/.claude/settings.json`. Use `powershell` for stock Windows (PS 5.1, always present); use `pwsh` if you have PowerShell 7+ installed. The hook script runs cleanly under both.
|
|
||||||
|
|
||||||
**Substitute `C:\\Users\\<you>` with your actual home path before pasting** — see "Why literal path" below.
|
|
||||||
|
|
||||||
```jsonc
|
|
||||||
{
|
|
||||||
"hooks": {
|
|
||||||
"PostToolUse": [
|
|
||||||
{
|
|
||||||
"matcher": "Bash",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"C:\\Users\\<you>\\.claude\\skills\\session-handoff\\hooks\\commit-detector.ps1\""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Swap `powershell` for `pwsh` if you prefer PS 7+. To check which you have: `Get-Command pwsh -ErrorAction SilentlyContinue` (empty → PS 7 not installed → use `powershell`).
|
|
||||||
|
|
||||||
If `hooks.PostToolUse` already exists — append the matcher block to the array. Don't overwrite existing entries.
|
|
||||||
|
|
||||||
**Restart Claude Code after editing `settings.json`** — hooks are loaded at session start. A running session won't pick up the new hook until it's restarted (close + reopen the CC instance). Verify the hook is active by making a substantive commit and checking for a `Substantive commit detected on ...` system reminder in the next turn.
|
|
||||||
|
|
||||||
### Why literal path (no `$env:USERPROFILE` / `%USERPROFILE%` / `~`)
|
|
||||||
|
|
||||||
Claude Code on Windows invokes hook commands through **git-bash**, not PowerShell or cmd.exe directly. The outer-shell layer mangles shell-specific variable references before PowerShell ever sees the args:
|
|
||||||
|
|
||||||
- `$env:USERPROFILE` (PowerShell syntax) → bash treats `$env` as an empty variable and the rest `:USERPROFILE\...` becomes a literal, so PowerShell receives `-File ":USERPROFILE\..."` and fails with `неверный формат имени` / "invalid filename format".
|
|
||||||
- `%USERPROFILE%` (cmd syntax) → bash passes through literally, PowerShell doesn't expand it, same failure.
|
|
||||||
- `~/.claude/...` → bash expands `~` to git-bash-style `/c/Users/<you>/...`, which PowerShell's `-File` can't resolve to a real Windows path.
|
|
||||||
|
|
||||||
Literal absolute path with `C:\\Users\\<you>\\...` (escaped backslashes for JSON) survives every outer shell unchanged. `settings.json` is per-user anyway — portability across machines isn't a concern at this layer.
|
|
||||||
|
|
||||||
## Enable on Linux / macOS (bash)
|
|
||||||
|
|
||||||
```jsonc
|
|
||||||
{
|
|
||||||
"hooks": {
|
|
||||||
"PostToolUse": [
|
|
||||||
{
|
|
||||||
"matcher": "Bash",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "bash ~/.claude/skills/session-handoff/hooks/commit-detector.sh"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The bash variant needs `python3` on PATH (used to parse the PostToolUse JSON stdin).
|
|
||||||
|
|
||||||
## What gets signalled
|
|
||||||
|
|
||||||
On a successful `git commit` whose subject prefix is not in {`meta`, `docs`, `style`, `chore`} or `fix typo`, **and** whose body exceeds 200 characters or which touches more than 3 files — the hook emits a `hookSpecificOutput.additionalContext` system reminder of shape:
|
|
||||||
|
|
||||||
> Substantive commit detected on `<cwd>`: `<subject>` (N files changed, body M chars). Consider invoking session-handoff write-mode to update `.tasks/NEXT_SESSION.md`.
|
|
||||||
|
|
||||||
On any of these → silent skip (exit 0, no JSON):
|
|
||||||
|
|
||||||
- malformed PostToolUse stdin
|
|
||||||
- Bash command isn't `git commit`
|
|
||||||
- command is `git commit --amend`
|
|
||||||
- commit returned non-zero exit
|
|
||||||
- cwd isn't a git work-tree
|
|
||||||
- subject prefix is in trivial set
|
|
||||||
- body ≤ 200 chars AND files ≤ 3
|
|
||||||
|
|
||||||
## Smoke test (without enabling the hook)
|
|
||||||
|
|
||||||
Pipe a synthetic PostToolUse JSON to the script. On Windows:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$payload = @{
|
|
||||||
tool_input = @{ command = 'git commit -m "subject"' }
|
|
||||||
tool_response = @{ exit_code = 0 }
|
|
||||||
cwd = (Get-Location).Path
|
|
||||||
} | ConvertTo-Json -Compress
|
|
||||||
|
|
||||||
$payload | pwsh -NoProfile -File .\skills\session-handoff\hooks\commit-detector.ps1
|
|
||||||
```
|
|
||||||
|
|
||||||
If your `HEAD` is a non-trivial commit (e.g. recent `feat:` with > 200-char body or > 3 files), output is JSON containing `additionalContext`. Otherwise — empty stdout (silent skip).
|
|
||||||
|
|
||||||
## Caveats
|
|
||||||
|
|
||||||
- **Rebase / cherry-pick noise.** Every commit in a rebase or cherry-pick batch will re-fire the hook. Deferred to a follow-up if it actually annoys in practice; the hook is opt-in so the cost is bounded.
|
|
||||||
- **First-non-trivial commit of session.** The agent-side heuristic in SKILL.md treats the *first* non-trivial commit of a session as "always substantive" regardless of thresholds. The hook can't see session boundaries — uses only body/file thresholds. Slight under-detection on small first commits; acceptable trade-off for harness-side determinism.
|
|
||||||
- **No automatic write-mode invocation.** Hook only signals. The agent still decides whether to run session-handoff write-mode in response — keeps the user-agency invariant from SKILL.md `What NOT to do`.
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#!/usr/bin/env pwsh
|
|
||||||
# session-handoff PostToolUse hook (PowerShell).
|
|
||||||
#
|
|
||||||
# Reads PostToolUse JSON from stdin, detects whether the just-completed
|
|
||||||
# Bash tool call was a substantive `git commit`, and on hit emits JSON to
|
|
||||||
# stdout with `additionalContext` so Claude Code surfaces a system reminder
|
|
||||||
# in the next agent iteration ("substantive commit — consider session-handoff
|
|
||||||
# write-mode").
|
|
||||||
#
|
|
||||||
# Substantive heuristic (mirrors session-handoff SKILL.md):
|
|
||||||
# prefix NOT in (meta:|docs:|style:|chore:|fix typo) AND
|
|
||||||
# (body > 200 chars OR files > 3)
|
|
||||||
#
|
|
||||||
# Silent skip on: malformed JSON, no command, --amend, failed commit,
|
|
||||||
# non-git cwd, trivial prefix, below thresholds. Never blocks the tool call
|
|
||||||
# (PostToolUse cannot, by design).
|
|
||||||
|
|
||||||
$ErrorActionPreference = 'Stop'
|
|
||||||
|
|
||||||
# Read stdin
|
|
||||||
try {
|
|
||||||
$raw = [Console]::In.ReadToEnd()
|
|
||||||
if ([string]::IsNullOrWhiteSpace($raw)) { exit 0 }
|
|
||||||
$hook = $raw | ConvertFrom-Json -ErrorAction Stop
|
|
||||||
} catch {
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Only Bash tool, only git commit (not --amend)
|
|
||||||
$cmd = $hook.tool_input.command
|
|
||||||
if (-not $cmd) { exit 0 }
|
|
||||||
if ($cmd -notmatch '(?<![\w-])git\s+commit(?![\w-])') { exit 0 }
|
|
||||||
if ($cmd -match '(?<![\w-])git\s+commit\b.*--amend') { exit 0 }
|
|
||||||
|
|
||||||
# Only on successful commit
|
|
||||||
if ($null -ne $hook.tool_response.exit_code -and $hook.tool_response.exit_code -ne 0) { exit 0 }
|
|
||||||
|
|
||||||
# Resolve cwd; require a git work-tree
|
|
||||||
$cwd = $hook.cwd
|
|
||||||
if (-not $cwd) { $cwd = (Get-Location).Path }
|
|
||||||
$inside = & git -C $cwd rev-parse --is-inside-work-tree 2>$null
|
|
||||||
if ($inside -ne 'true') { exit 0 }
|
|
||||||
|
|
||||||
# Parse last commit
|
|
||||||
$subject = (& git -C $cwd log -1 --format='%s').Trim()
|
|
||||||
# PowerShell collapses multi-line subprocess output into string[] — join back so
|
|
||||||
# .Length below is char count, not line count.
|
|
||||||
$body = ((& git -C $cwd log -1 --format='%b') -join "`n")
|
|
||||||
$files = ((& git -C $cwd diff-tree --no-commit-id --name-only -r HEAD) | Measure-Object).Count
|
|
||||||
|
|
||||||
# Trivial-prefix check (Conventional Commits prefix before optional scope + colon)
|
|
||||||
$prefix = $subject -replace '^([a-z]+)(\([^)]+\))?:.*$','$1'
|
|
||||||
$trivial = @('meta','docs','style','chore')
|
|
||||||
if ($trivial -contains $prefix) { exit 0 }
|
|
||||||
if ($subject -match 'fix\s+typo') { exit 0 }
|
|
||||||
|
|
||||||
# Threshold check (chars for body, count for files)
|
|
||||||
$bodyLen = if ($body) { $body.Length } else { 0 }
|
|
||||||
if ($bodyLen -le 200 -and $files -le 3) { exit 0 }
|
|
||||||
|
|
||||||
|
|
||||||
# Substantive — emit JSON
|
|
||||||
$msg = "Substantive commit detected on " + $cwd + ": ``" + $subject + "`` (" + $files + " files changed, body " + $bodyLen + " chars). Consider invoking session-handoff write-mode to update .tasks/NEXT_SESSION.md."
|
|
||||||
|
|
||||||
@{
|
|
||||||
hookSpecificOutput = @{
|
|
||||||
hookEventName = 'PostToolUse'
|
|
||||||
additionalContext = $msg
|
|
||||||
}
|
|
||||||
systemMessage = 'session-handoff: substantive commit detected'
|
|
||||||
suppressOutput = $false
|
|
||||||
} | ConvertTo-Json -Compress -Depth 5 | Write-Output
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# session-handoff PostToolUse hook (POSIX). See commit-detector.ps1 for prose.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
raw=$(cat)
|
|
||||||
[[ -z "$raw" ]] && exit 0
|
|
||||||
|
|
||||||
# Helper: extract a JSON path via python3
|
|
||||||
jget() {
|
|
||||||
python3 -c "
|
|
||||||
import sys, json
|
|
||||||
try:
|
|
||||||
d = json.loads(sys.argv[1])
|
|
||||||
out = d
|
|
||||||
for k in sys.argv[2].split('.'):
|
|
||||||
if isinstance(out, dict):
|
|
||||||
out = out.get(k)
|
|
||||||
else:
|
|
||||||
out = None
|
|
||||||
break
|
|
||||||
print('' if out is None else out)
|
|
||||||
" "$raw" "$1" 2>/dev/null || echo ''
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd=$(jget tool_input.command)
|
|
||||||
[[ -z "$cmd" ]] && exit 0
|
|
||||||
|
|
||||||
# Only `git commit`, not `--amend`
|
|
||||||
if ! echo "$cmd" | grep -qE '(^|[^[:alnum:]_-])git[[:space:]]+commit($|[^[:alnum:]_-])'; then exit 0; fi
|
|
||||||
if echo "$cmd" | grep -qE '(^|[^[:alnum:]_-])git[[:space:]]+commit\b.*--amend'; then exit 0; fi
|
|
||||||
|
|
||||||
# Only on successful commit (if exit_code present and non-zero, skip)
|
|
||||||
exit_code=$(jget tool_response.exit_code)
|
|
||||||
if [[ -n "$exit_code" && "$exit_code" != "0" ]]; then exit 0; fi
|
|
||||||
|
|
||||||
cwd=$(jget cwd)
|
|
||||||
[[ -z "$cwd" ]] && cwd=$(pwd)
|
|
||||||
|
|
||||||
# Require git work-tree
|
|
||||||
git -C "$cwd" rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
|
||||||
|
|
||||||
subject=$(git -C "$cwd" log -1 --format='%s')
|
|
||||||
body=$(git -C "$cwd" log -1 --format='%b')
|
|
||||||
files=$(git -C "$cwd" diff-tree --no-commit-id --name-only -r HEAD | wc -l | tr -d ' ')
|
|
||||||
|
|
||||||
# Trivial-prefix check
|
|
||||||
prefix=$(echo "$subject" | sed -E 's/^([a-z]+)(\([^)]+\))?:.*$/\1/')
|
|
||||||
case "$prefix" in
|
|
||||||
meta|docs|style|chore) exit 0 ;;
|
|
||||||
esac
|
|
||||||
echo "$subject" | grep -qE 'fix[[:space:]]+typo' && exit 0
|
|
||||||
|
|
||||||
# Threshold
|
|
||||||
body_len=${#body}
|
|
||||||
if [[ "$body_len" -le 200 && "$files" -le 3 ]]; then exit 0; fi
|
|
||||||
|
|
||||||
# Substantive — emit JSON via python3 to handle quoting safely
|
|
||||||
python3 -c "
|
|
||||||
import json, sys
|
|
||||||
msg = (
|
|
||||||
'Substantive commit detected on $cwd: \`' + '''$subject''' + '\` '
|
|
||||||
+ '($files files changed, body $body_len chars). '
|
|
||||||
+ 'Consider invoking session-handoff write-mode to update .tasks/NEXT_SESSION.md.'
|
|
||||||
)
|
|
||||||
print(json.dumps({
|
|
||||||
'hookSpecificOutput': {
|
|
||||||
'hookEventName': 'PostToolUse',
|
|
||||||
'additionalContext': msg,
|
|
||||||
},
|
|
||||||
'systemMessage': 'session-handoff: substantive commit detected',
|
|
||||||
'suppressOutput': False,
|
|
||||||
}))
|
|
||||||
"
|
|
||||||
@@ -16,9 +16,10 @@ description: >
|
|||||||
|
|
||||||
# session-health
|
# session-health
|
||||||
|
|
||||||
Что делать, когда поллер pi (`extensions/session-health.ts`) прислал
|
Что делать, когда поллер pi (`extensions/mappa.ts`, секция session-health —
|
||||||
предупреждение о размере контекста — или когда сам агент подозревает, что
|
консолидация 6 расширений, task:1486, wiki:3325) прислал предупреждение о
|
||||||
сессия раздулась. Поллер — единственный источник точных цифр: footer-статус
|
размере контекста — или когда сам агент подозревает, что сессия раздулась.
|
||||||
|
Поллер — единственный источник точных цифр: footer-статус
|
||||||
(`14.6%/1.0M`) и `/session` агент (LLM) **не видит** — это TUI для человека.
|
(`14.6%/1.0M`) и `/session` агент (LLM) **не видит** — это TUI для человека.
|
||||||
|
|
||||||
## When to use
|
## When to use
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
---
|
|
||||||
name: session-inbox-monitor
|
|
||||||
author: ours
|
|
||||||
version: 1.0.0
|
|
||||||
description: >
|
|
||||||
Raises a persistent Monitor on the project's Mappa inbox (poll
|
|
||||||
`mcp__mappa__inbox_monitor` / HTTP `GET /inbox?project=<cwd>`), so
|
|
||||||
inter-session messages page the session in real time; the monitor dies on
|
|
||||||
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` / `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 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).** 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.
|
|
||||||
- **On request.** AGENTS.md line `inbox monitor: raise on start`, or «подними
|
|
||||||
монитор почты», «настрой авто-монитор инбокса», «raise inbox monitor»,
|
|
||||||
«auto-arm inbox watcher».
|
|
||||||
- **NOT for** handling the content of a received message (→
|
|
||||||
`inter-session-messaging`). This skill is only the monitor's *lifecycle*.
|
|
||||||
|
|
||||||
## Inputs
|
|
||||||
|
|
||||||
- `<project>` — своё имя папки (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.** 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=<cwd-имя-папки>, 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).
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Pi (pi-coding-agent) support — session-scoped global extension
|
|
||||||
|
|
||||||
Same contract, pi-native, session-scoped: the extension polls ONLY the current
|
|
||||||
session's project inbox (`GET /inbox?project=<basename cwd>`); it never reads
|
|
||||||
other projects' inboxes (vitya's rule: an agent may only read its own
|
|
||||||
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`.
|
|
||||||
- **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 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`.
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
- **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).
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
# 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=<name>`.
|
|
||||||
# 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 directory - so we never touch unrelated processes.
|
|
||||||
# (b) INJECT - additionalContext telling the agent to raise a persistent
|
|
||||||
# Monitor (Monitor TOOL, not background Bash) polling the Mappa
|
|
||||||
# inbox of this project (HTTP GET /inbox).
|
|
||||||
#
|
|
||||||
# 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).
|
|
||||||
# So the hook injects unconditionally and the SKILL instructs the agent to skip
|
|
||||||
# when headless. A Monitor raised in headless is harmless (killed ~5s after the
|
|
||||||
# run ends); a false-skip in an interactive session would silently lose the
|
|
||||||
# feature - so the default errs toward raising.
|
|
||||||
#
|
|
||||||
# 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]$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.
|
|
||||||
# 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
|
|
||||||
|
|
||||||
$projectName = Split-Path $ProjectDir -Leaf
|
|
||||||
$agentsMd = Join-Path $ProjectDir 'AGENTS.md'
|
|
||||||
$claudeMd = Join-Path $ProjectDir 'CLAUDE.md'
|
|
||||||
|
|
||||||
# --- opt-in gate (line in AGENTS.md or CLAUDE.md) ---------------------------
|
|
||||||
$optedIn = $false
|
|
||||||
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 project dir: the Monitor poll command (Git Bash) uses this form,
|
|
||||||
# so both the sweep match and the injected command share one literal.
|
|
||||||
$dirFwd = ($ProjectDir -replace '\\', '/')
|
|
||||||
|
|
||||||
# --- (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 "*$dirFwd*"
|
|
||||||
} |
|
|
||||||
ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
|
|
||||||
} catch { }
|
|
||||||
|
|
||||||
# --- (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. 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 = @"
|
|
||||||
[session-inbox-monitor] This project participates in inter-session messaging. As your FIRST action, raise a persistent inbox watcher so messages from other sessions page you in real time.
|
|
||||||
|
|
||||||
Use the Monitor tool with persistent: true, description "inbox watcher", and this EXACT command:
|
|
||||||
|
|
||||||
$cmd
|
|
||||||
|
|
||||||
Do NOT use a background Bash for this - it leaks across /clear. The Monitor tool is session-bound and tears down on its own at session end. The paired SessionStart hook already swept any orphaned watcher before this, so raise exactly one.
|
|
||||||
|
|
||||||
If you are running headless (claude -p / non-interactive), SKIP this - the Stop-hook inbox pickup plus Notify cover delivery there. See the session-inbox-monitor skill for the full contract.
|
|
||||||
"@
|
|
||||||
|
|
||||||
@{ hookSpecificOutput = @{ hookEventName = 'SessionStart'; additionalContext = $ctx } } | ConvertTo-Json -Compress -Depth 5
|
|
||||||
exit 0
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# setup-projects-meta
|
|
||||||
|
|
||||||
One-time skill that brings up the local `projects-meta-mcp` stdio server on a
|
|
||||||
new (or freshly broken) machine. Clones the server repo, builds it, writes
|
|
||||||
`~/.config/projects-mcp/auth.toml` with the user's Gitea token, clones the
|
|
||||||
shared wiki to `~/projects/.wiki`, and registers `mcpServers.projects-meta`
|
|
||||||
in `~/.claude.json`.
|
|
||||||
|
|
||||||
The runtime policy for *using* the resulting tools lives in
|
|
||||||
[`using-projects-meta`](../using-projects-meta/) — `setup-projects-meta` is the
|
|
||||||
only place that touches user-level config or installs the server.
|
|
||||||
|
|
||||||
`projects-meta-mcp` reference (full):
|
|
||||||
`mcp__projects-meta__knowledge_get slug=packages/projects-meta-mcp`
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- User says: "install projects-meta", "set up projects-meta", "configure projects-meta",
|
|
||||||
"настрой projects-meta", "установи projects-meta", "projects-meta не работает",
|
|
||||||
"projects-meta isn't working".
|
|
||||||
- [`using-projects-meta`](../using-projects-meta/) detects missing
|
|
||||||
`mcp__projects-meta__*` tools and delegates here via its Prerequisites
|
|
||||||
section.
|
|
||||||
- A new machine in the multi-machine fleet — install once per machine.
|
|
||||||
|
|
||||||
## What it installs
|
|
||||||
|
|
||||||
| Path | Role |
|
|
||||||
|---|---|
|
|
||||||
| `~/projects/.common/lib/projects-meta-mcp/` | server repo (cloned from Gitea) |
|
|
||||||
| `~/projects/.common/lib/projects-meta-mcp/dist/server.js` | built stdio entry point |
|
|
||||||
| `~/.config/projects-mcp/auth.toml` | Gitea credentials (token-bearing) |
|
|
||||||
| `~/.cache/projects-mcp/tasks.json` | aggregated tasks cache |
|
|
||||||
| `~/projects/.wiki/` | shared wiki clone (Gitea repo `projects-wiki`, content in root) |
|
|
||||||
| `~/.claude.json` (`mcpServers.projects-meta`) | MCP registration |
|
|
||||||
|
|
||||||
## Hard rules
|
|
||||||
|
|
||||||
- **Never auto-mutate.** Phase 1 (discovery) and Phase 2 (plan) always pause
|
|
||||||
for explicit confirmation. A trigger phrase grants permission to inspect,
|
|
||||||
not to clone or write secrets.
|
|
||||||
- **Never echo the Gitea token in chat.** Edit / Write tool calls inevitably
|
|
||||||
contain it (that's how it lands in `auth.toml`); chat output must not.
|
|
||||||
- **Never clone over an unrelated `~/projects/.wiki/`.**
|
|
||||||
If it exists with a non-matching `origin`, stop and ask — the user
|
|
||||||
may have an unrelated wiki there.
|
|
||||||
- **Always `chmod 600` `auth.toml` on Linux / macOS.** Token leak otherwise.
|
|
||||||
|
|
||||||
## Procedure (high-level)
|
|
||||||
|
|
||||||
1. **Phase 0** — environment sanity (Node ≥ 18, git, npm, network to Gitea).
|
|
||||||
2. **Phase 1** — discovery (token / repo / wiki clone / MCP registration / cache).
|
|
||||||
3. **Phase 2** — plan + confirm. Wait for explicit "ok"/"go"/"поехали".
|
|
||||||
4. **Phase 3** — backup (`~/.claude.json`, existing `auth.toml`).
|
|
||||||
5. **Phase 4** — clone / pull repo + `npm install && npm run build`; clone
|
|
||||||
shared wiki if absent.
|
|
||||||
6. **Phase 5** — write `~/.config/projects-mcp/auth.toml` with `gitea_token`.
|
|
||||||
7. **Phase 6** — register `mcpServers.projects-meta` in `~/.claude.json` with
|
|
||||||
absolute path to `dist/server.js`.
|
|
||||||
8. **Phase 7** — smoke test (`mcp__projects-meta__meta_status`) + `node dist/sync.js`
|
|
||||||
to populate the cache.
|
|
||||||
9. **Phase 8** — restart guidance + final report.
|
|
||||||
|
|
||||||
Full procedure with shell snippets and templates lives in [`SKILL.md`](SKILL.md).
|
|
||||||
|
|
||||||
## Rollback
|
|
||||||
|
|
||||||
1. Stop. Don't fix forward.
|
|
||||||
2. `cp <file>.bak-<ts> <file>` for `~/.claude.json` and `~/.config/projects-mcp/auth.toml`.
|
|
||||||
3. Optional: `rm -rf ~/projects/.common/lib/projects-meta-mcp` and `rm -rf ~/.cache/projects-mcp`.
|
|
||||||
Keep `~/projects/.wiki/` — it's a useful clone regardless of MCP state.
|
|
||||||
4. Restart Claude Code.
|
|
||||||
5. Confirm `mcp__projects-meta__*` tools are gone (or back to the prior version).
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
From the repo root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/install.sh setup-projects-meta
|
|
||||||
```
|
|
||||||
|
|
||||||
Works on Windows under git-bash, Linux, macOS.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [`using-projects-meta`](../using-projects-meta/) — runtime policy for
|
|
||||||
cross-project task aggregation and shared-wiki query / ingest.
|
|
||||||
- [`setup-context7`](../setup-context7/) — companion pattern for the context7
|
|
||||||
MCP plugin (similar 8-phase shape).
|
|
||||||
- Per-project вики/таски живут в mappa (мета в сервисе, решения 14/15) —
|
|
||||||
setup-скилов `.wiki/`/`.tasks/` больше нет; операции — `using-wiki` /
|
|
||||||
`using-tasks`.
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
---
|
|
||||||
name: setup-projects-meta
|
|
||||||
author: ours
|
|
||||||
version: 1.1.0
|
|
||||||
description: Installs and configures the local `projects-meta-mcp` stdio server — clones the repo to `~/projects/.common/lib/projects-meta-mcp`, builds it, writes `~/.config/projects-mcp/auth.toml` with the user's Gitea token, clones the shared wiki to `~/projects/.wiki/` (content lives in root), and registers `mcpServers.projects-meta` in `~/.claude.json`. Use this skill when the user says "install projects-meta", "set up projects-meta", "configure projects-meta", "настрой projects-meta", "установи projects-meta", "projects-meta не работает", "projects-meta isn't working", or whenever the `mcp__projects-meta__*` tools are missing in a session that needs cross-project task aggregation or the shared Gitea wiki. Cross-platform — Windows / Linux / macOS. Mutates user-level config and writes secrets; pauses for confirmation before every write.
|
|
||||||
---
|
|
||||||
|
|
||||||
# setup-projects-meta
|
|
||||||
|
|
||||||
> One-time skill that gets the local `projects-meta-mcp` server running with the user's Gitea credentials. Stops at confirmation gates because the procedure clones a repo, writes a secret-bearing TOML file, and edits `~/.claude.json`.
|
|
||||||
|
|
||||||
Reference: full `projects-meta-mcp` docs live in the shared wiki at `packages/projects-meta-mcp` (fetch via `mcp__projects-meta__knowledge_get` once the server is up).
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
- User explicitly asks: install / set up / configure projects-meta.
|
|
||||||
- A `using-projects-meta`-driven task fails because `mcp__projects-meta__*` tools aren't available.
|
|
||||||
- Migrating a stale install (token expired, repo moved, broken cache) — same procedure, Phase 1 detects what's already in place.
|
|
||||||
- New machine in the user's multi-machine fleet (recall: this is a cross-machine workflow).
|
|
||||||
|
|
||||||
## Out of scope
|
|
||||||
|
|
||||||
- Issuing or rotating Gitea tokens. This skill *uses* a token the user already has; if there's no token, point them at Gitea's settings page (`https://git.kzntsv.site/user/settings/applications`) and stop until they paste one.
|
|
||||||
- Running `projects-meta-mcp` itself (the MCP harness spawns it).
|
|
||||||
- Editing `.tasks/STATUS.md` or wiki content — that's `using-projects-meta` / `using-tasks` / `using-wiki`.
|
|
||||||
- Any other MCP server.
|
|
||||||
|
|
||||||
## Hard rule: don't auto-mutate config
|
|
||||||
|
|
||||||
The procedure clones a repo, writes `~/.config/projects-mcp/auth.toml` (carries the Gitea token), and edits `~/.claude.json`. **Always pause for explicit confirmation between Phase 1 (discovery, read-only) and Phase 2 (plan), and again before Phase 3 (backup + writes).** A trigger phrase is permission to run discovery, not permission to clone or write secrets.
|
|
||||||
|
|
||||||
## Procedure
|
|
||||||
|
|
||||||
### Phase 0 — Environment sanity
|
|
||||||
|
|
||||||
- Confirm Claude Code is the current harness (need `mcpServers` registration in `~/.claude.json`).
|
|
||||||
- Confirm `git`, `node`, `npm` are on `PATH`. Node ≥ 18 (the server uses ES modules).
|
|
||||||
- Confirm network reachability to `https://git.kzntsv.site` (the Gitea host). On HTTP 401/403 later, the token is dead — stop and ask for a new one.
|
|
||||||
- Pick paths: `~/projects/.common/lib/projects-meta-mcp`, `~/.config/projects-mcp/`, `~/.cache/projects-mcp/`, `~/projects/.wiki/` (shared wiki clone). POSIX-style `~/...` resolves correctly under git-bash on Windows.
|
|
||||||
|
|
||||||
### Phase 1 — Discovery (read-only)
|
|
||||||
|
|
||||||
Search, in order. Report only "found at <path>", never echo token values.
|
|
||||||
|
|
||||||
**Existing Gitea token.** Look in priority order:
|
|
||||||
|
|
||||||
1. `~/.config/projects-mcp/auth.toml` → `gitea_token = "..."`
|
|
||||||
2. Env var `PROJECTS_META_GITEA_TOKEN`
|
|
||||||
3. Existing `~/.claude.json` → `mcpServers.projects-meta` block (rare; legacy installs sometimes inline `env.GITEA_TOKEN`)
|
|
||||||
|
|
||||||
The first hit wins. Capture internally for Phase 5; **never echo it in chat**.
|
|
||||||
|
|
||||||
**Repo install state.** Check whether `~/projects/.common/lib/projects-meta-mcp/.git` exists. If yes, `git -C ~/projects/.common/lib/projects-meta-mcp rev-parse HEAD` → record the SHA so Phase 4 can decide *clone* vs *pull*.
|
|
||||||
|
|
||||||
**Build artifact.** Check `~/projects/.common/lib/projects-meta-mcp/dist/server.js`. If absent, Phase 4 will run `npm install && npm run build`.
|
|
||||||
|
|
||||||
**Shared wiki clone.** Check if `~/projects/.wiki/.git` exists and `origin` matches `https://git.kzntsv.site/OpeItcLoc03/projects-wiki(.git)?`. If non-matching `origin`, stop and ask — the user may have an unrelated wiki there.
|
|
||||||
|
|
||||||
**MCP registration.** Read `~/.claude.json` and check `mcpServers.projects-meta`. Note the command + args. If args point at a stale path, Phase 6 will fix it.
|
|
||||||
|
|
||||||
**Cache state.** List `~/.cache/projects-mcp/` (if it exists). Just for the report — don't rely on it.
|
|
||||||
|
|
||||||
### Phase 2 — Plan + confirm
|
|
||||||
|
|
||||||
Present a single-block plan to the user:
|
|
||||||
|
|
||||||
```
|
|
||||||
Token: <found at <path> | NOT FOUND — will ask>
|
|
||||||
Repo: <installed at ~/projects/.common/lib/projects-meta-mcp@<sha> | will clone>
|
|
||||||
Build artifact: <present | will run npm install && npm run build>
|
|
||||||
Wiki clone: <present at ~/projects/.wiki | will clone | wrong remote — STOP>
|
|
||||||
MCP entry: <present in ~/.claude.json | will add | will fix path>
|
|
||||||
Backups: ~/.claude.json.bak-<ts>, ~/.config/projects-mcp/auth.toml.bak-<ts> (if exists)
|
|
||||||
```
|
|
||||||
|
|
||||||
Wait for explicit confirmation ("ok", "go", "поехали"). Anything else → stop.
|
|
||||||
|
|
||||||
If no token was found in Phase 1 — first ask: "Paste a Gitea personal access token (scope: `read:repository` for read-only, `write:repository` to enable mutations), or open `https://git.kzntsv.site/user/settings/applications` to create one." Don't proceed past Phase 2 without a token.
|
|
||||||
|
|
||||||
### Phase 3 — Backup
|
|
||||||
|
|
||||||
Copy each file we will modify to `<file>.bak-YYYYMMDD-HHMMSS`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
TS=$(date +%Y%m%d-%H%M%S)
|
|
||||||
[ -f ~/.claude.json ] && cp ~/.claude.json ~/.claude.json.bak-$TS
|
|
||||||
[ -f ~/.config/projects-mcp/auth.toml ] && cp ~/.config/projects-mcp/auth.toml ~/.config/projects-mcp/auth.toml.bak-$TS
|
|
||||||
```
|
|
||||||
|
|
||||||
Confirm both backups exist (when their source existed) before any further edit. The repo and wiki clones don't need backup — git is the backup.
|
|
||||||
|
|
||||||
### Phase 4 — Clone + build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Server
|
|
||||||
if [ -d ~/projects/.common/lib/projects-meta-mcp/.git ]; then
|
|
||||||
git -C ~/projects/.common/lib/projects-meta-mcp pull --ff-only
|
|
||||||
else
|
|
||||||
git clone https://git.kzntsv.site/OpeItcLoc03/projects-meta-mcp ~/projects/.common/lib/projects-meta-mcp
|
|
||||||
fi
|
|
||||||
cd ~/projects/.common/lib/projects-meta-mcp
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Shared wiki
|
|
||||||
mkdir -p ~/projects
|
|
||||||
if [ -d ~/projects/.wiki/.git ]; then
|
|
||||||
git -C ~/projects/.wiki pull --ff-only
|
|
||||||
else
|
|
||||||
git clone https://git.kzntsv.site/OpeItcLoc03/projects-wiki ~/projects/.wiki
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
Verify `~/projects/.common/lib/projects-meta-mcp/dist/server.js` exists after build. If not — abort, the build failed; ask the user to run `npm run build` manually and paste the output.
|
|
||||||
|
|
||||||
### Phase 5 — Write `auth.toml`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p ~/.config/projects-mcp
|
|
||||||
```
|
|
||||||
|
|
||||||
If `~/.config/projects-mcp/auth.toml` already exists and Phase 1 found a valid `gitea_token` line — skip the write. Otherwise, write the file with the token captured in Phase 1 (or freshly pasted in Phase 2):
|
|
||||||
|
|
||||||
```toml
|
|
||||||
gitea_url = "https://git.kzntsv.site"
|
|
||||||
gitea_user = "OpeItcLoc03" # acting identity (commit author)
|
|
||||||
gitea_token = "<TOKEN>"
|
|
||||||
gitea_owners = ["victor", "cancel_music"] # additional Gitea owners to sync
|
|
||||||
agenda_tasks_repo = "OpeItcLoc03/agenda" # cross-project meta-board (qualified)
|
|
||||||
# gitea_aggregate_skip_owners = ["OpeItcLoc03"] # opt: sync but hide from `tasks_aggregate`
|
|
||||||
```
|
|
||||||
|
|
||||||
**Schema notes (v2.x server):**
|
|
||||||
|
|
||||||
- `gitea_owners` is an array of owners whose repos are scanned by `sync.js` and surfaced in aggregation views. `gitea_user` is acting identity only (commit author footer), not necessarily aggregated.
|
|
||||||
- `agenda_tasks_repo` is **qualified** (`<owner>/<repo>`). The literal `agenda` in `target_project` resolves through this field.
|
|
||||||
- `gitea_aggregate_skip_owners` (optional, v2.2.0+) — visited by sync (so mutations work via cache lookup) but hidden from `tasks_aggregate` / `tasks_search`. Useful for keeping infra repos write-able without polluting the dashboard.
|
|
||||||
- Backwards-compat: legacy installs with only `gitea_user = "X"` and no `gitea_owners` → server reads as `gitea_owners = ["X"]`.
|
|
||||||
- Legacy `meta_tasks_repo` / `meta_wiki_repo` → renamed to `agenda_tasks_repo` / built-in `projects-wiki`. Old keys ignored on v2.x.
|
|
||||||
|
|
||||||
Permissions: on Linux / macOS run `chmod 600 ~/.config/projects-mcp/auth.toml`. On Windows the default ACL is per-user, no extra step.
|
|
||||||
|
|
||||||
### Phase 6 — Register in `~/.claude.json`
|
|
||||||
|
|
||||||
Edit `~/.claude.json`. Add or update the `mcpServers.projects-meta` block:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"projects-meta": {
|
|
||||||
"command": "node",
|
|
||||||
"args": ["<ABSOLUTE_PATH_TO>/dist/server.js"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Absolute path resolution:
|
|
||||||
|
|
||||||
| Platform | `<ABSOLUTE_PATH_TO>` |
|
|
||||||
|---|---|
|
|
||||||
| Windows | `C:/Users/<USER>/projects/.common/lib/projects-meta-mcp` (forward slashes; works in JSON without escaping) |
|
|
||||||
| Linux | `/home/<USER>/projects/.common/lib/projects-meta-mcp` |
|
|
||||||
| macOS | `/Users/<USER>/projects/.common/lib/projects-meta-mcp` |
|
|
||||||
|
|
||||||
After each edit, validate JSON:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Windows (git-bash)
|
|
||||||
powershell.exe -NoProfile -c "Get-Content '<file>' -Raw | ConvertFrom-Json | Out-Null"
|
|
||||||
# Linux / macOS
|
|
||||||
jq empty <file>
|
|
||||||
# fallback
|
|
||||||
python -c "import json; json.load(open('<file>'))"
|
|
||||||
```
|
|
||||||
|
|
||||||
If validation fails → restore from `.bak-*` and abort.
|
|
||||||
|
|
||||||
### Phase 7 — Smoke test (best-effort) + run initial sync
|
|
||||||
|
|
||||||
Best-effort: call `mcp__projects-meta__meta_status`. If it returns a JSON blob with `synced_at` / `wiki_pages_count` — the server is reachable in *this* session.
|
|
||||||
|
|
||||||
Then run a one-shot sync to populate the cache:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/projects/.common/lib/projects-meta-mcp
|
|
||||||
node dist/sync.js
|
|
||||||
```
|
|
||||||
|
|
||||||
Expect a non-zero `projects_count` and a fresh `~/.cache/projects-mcp/tasks.json`. On 401 / 403 → token is wrong scope or expired; rotate via `https://git.kzntsv.site/user/settings/applications` and re-edit `auth.toml`.
|
|
||||||
|
|
||||||
**Important caveat to relay to the user:** in the *same* session that just ran setup, the MCP server you're talking to is whatever was bound at session start. So a passing `meta_status` only proves "some projects-meta is alive" — not "the registration we just wrote is what's serving it". The real test is after Claude Code restart.
|
|
||||||
|
|
||||||
### Phase 8 — Restart guidance + final report
|
|
||||||
|
|
||||||
Tell the user:
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ Setup complete. Restart Claude Code so the new mcpServers.projects-meta
|
|
||||||
registration binds to a fresh stdio session.
|
|
||||||
|
|
||||||
After restart:
|
|
||||||
• mcp__projects-meta__* tools serve from ~/projects/.common/lib/projects-meta-mcp/dist/server.js
|
|
||||||
• Cache lives at ~/.cache/projects-mcp/tasks.json (refresh: node dist/sync.js)
|
|
||||||
• Shared wiki clone at ~/projects/.wiki/ — `git -C ~/projects/.wiki pull --ff-only` for fresh anchors
|
|
||||||
• Backups saved at ~/.claude.json.bak-<ts> (and auth.toml.bak-<ts> if it existed before)
|
|
||||||
|
|
||||||
If something breaks after restart:
|
|
||||||
• Restore from .bak-* and tell me — we'll roll back together.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollback procedure
|
|
||||||
|
|
||||||
If a problem surfaces (now or after restart):
|
|
||||||
|
|
||||||
1. Stop. Don't try to fix forward.
|
|
||||||
2. Find the most recent `.bak-YYYYMMDD-HHMMSS` next to `~/.claude.json` (and `~/.config/projects-mcp/auth.toml` if applicable).
|
|
||||||
3. `cp <file>.bak-<ts> <file>` for each.
|
|
||||||
4. Optional: `rm -rf ~/projects/.common/lib/projects-meta-mcp` and `rm -rf ~/.cache/projects-mcp`. Keep `~/projects/.wiki/` — it's a useful clone regardless of MCP state.
|
|
||||||
5. Restart Claude Code.
|
|
||||||
6. Confirm `mcp__projects-meta__*` is gone (or back to the pre-existing version).
|
|
||||||
7. Report what went wrong so we can fix the procedure.
|
|
||||||
|
|
||||||
## Cross-platform notes
|
|
||||||
|
|
||||||
The procedure is platform-agnostic. Only auxiliary tooling differs:
|
|
||||||
|
|
||||||
| | JSON validate | Backup | Permissions on auth.toml |
|
|
||||||
|---|---|---|---|
|
|
||||||
| Windows (git-bash) | `powershell.exe -NoProfile -c "Get-Content '<f>' -Raw \| ConvertFrom-Json \| Out-Null"` | `cp` | per-user ACL by default |
|
|
||||||
| Linux | `jq empty <f>` (or `python -c "import json; json.load(open('<f>'))"`) | `cp` | `chmod 600` |
|
|
||||||
| macOS | same as Linux | `cp` | `chmod 600` |
|
|
||||||
|
|
||||||
Path forms (`~/.local/...`, `~/.config/...`, `~/projects/...`) are identical on all three.
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
- **Skipping Phase 1.** "User just said 'install projects-meta' — let's go." No — find existing token / repo / wiki first; re-cloning over an existing install loses any local commits in the wiki.
|
|
||||||
- **Echoing the token.** It's a secret. Edit / Write tool calls inevitably contain it (that's how it gets into `auth.toml`), but no chat output should.
|
|
||||||
- **Cloning over an unrelated `~/projects/.wiki/`.** If it exists with a different `origin`, stop. The user may have an unrelated wiki there.
|
|
||||||
- **Writing `auth.toml` with `0644` perms on Linux/macOS.** Token leak. Always `chmod 600` after write.
|
|
||||||
- **Treating in-session `meta_status` as proof.** Same as the context7 caveat — the active MCP connection was bound at session start.
|
|
||||||
- **Auto-running on every "use projects-meta".** This skill is intrusive. Trigger only on explicit "install/setup/configure projects-meta", or when MCP tools are missing and the user is blocked.
|
|
||||||
- **Forgetting `node dist/sync.js`.** Without an initial sync, the cache is empty and `tasks_aggregate` returns nothing — the user thinks setup failed.
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
---
|
|
||||||
name: task-format
|
|
||||||
author: ours
|
|
||||||
version: 0.4.0
|
|
||||||
description: >
|
|
||||||
Use when creating or editing a task so it is actually claimable and routed —
|
|
||||||
not silently skipped. Primary channel: **mappa** — create via
|
|
||||||
`mcp__mappa__task_create` (схема ниже), не руками. Legacy: пока файловый
|
|
||||||
поллер (agents-task-runner) не переключён на mappa (#984), блоки в
|
|
||||||
`.tasks/STATUS.md` обязаны совпадать со строгим форматом (шапка, поля
|
|
||||||
Weight/Notify), иначе поллер молча пропускает. Triggers: «оформить таску для
|
|
||||||
поллера», «формат таски», «task block format», «make a task the poller will
|
|
||||||
pick up», «add Weight/Notify», poller / agent-runner not claiming a task.
|
|
||||||
---
|
|
||||||
|
|
||||||
# task-format
|
|
||||||
|
|
||||||
Канон создания задачи — **через тул**, не рукописным блоком. Поллер (автономный
|
|
||||||
раннер) разбирает задачи строгими правилами; формат задаёт, какая таска будет
|
|
||||||
взята, отмаршрутизирована и зарепорчена, а какая молча пропущена.
|
|
||||||
|
|
||||||
> Создаёшь задачу для **другого** проекта/агента? См. `delegate-task` — он ведёт
|
|
||||||
> через тул + письмо. Работа с бордом (claim/close/status) — `using-tasks`.
|
|
||||||
|
|
||||||
## Primary: mappa task.create
|
|
||||||
|
|
||||||
Создание задач в mappa (решение 14/15: мета в сервисе) — только через
|
|
||||||
`mcp__mappa__task_create`, никогда руками вставляй блоки. Тул сам назначает
|
|
||||||
per-type номер (`t:N`, решение 20) и пишет сущность.
|
|
||||||
|
|
||||||
```
|
|
||||||
mcp__mappa__task_create(
|
|
||||||
project: <имя проекта>, // обязателен
|
|
||||||
slug: <kebab-case>, // обязателен, латиница
|
|
||||||
title: <одна строка>, // опционально
|
|
||||||
description: <markdown>, // тело; [[refs]] → рёбра (решение 4)
|
|
||||||
status: ready | active | paused | blocked | done, // по умолчанию ready
|
|
||||||
priority: P0 | P1 | P2, // важность; отсутствует → P1 (task-priority-due)
|
|
||||||
due: yyyy-mm-dd, // дедлайн; отсутствует = нет (task-priority-due)
|
|
||||||
claim_token: <токен лиза проекта> // мутация под лизом (решение 19)
|
|
||||||
)
|
|
||||||
|
|
||||||
**Priority/Due (task-priority-due, #1045):** задаются **только при создании**
|
|
||||||
— либо явными параметрами `priority`/`due`, либо строками в description
|
|
||||||
(`**Priority:** P0|P1|P2`, `**Due:** yyyy-mm-dd`; явные параметры переопределяют
|
|
||||||
парсинг). После создания агент приоритет и дедлайн **не меняет** — прецедент
|
|
||||||
человека структурный (update агентами отклоняется сервером). Обнаружил, что
|
|
||||||
таска на самом деле P0 → паркуй вопрос человеку, не бампай сам.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Мутация под лизом (решение 19):** `task_create` требует `claim_token`
|
|
||||||
активного лиза проекта (берётся `mcp__mappa__task_claim_next`). Без лиза —
|
|
||||||
422 busy. (Карв-аут: чтения и инбокс-доставка лиза не требуют.)
|
|
||||||
|
|
||||||
**Per-type номер (решение 20):** номер — канонический машинный реф `t:N`
|
|
||||||
(см. ответы — поле `ref`). Глобальный id — internal, только для addressing
|
|
||||||
(#1037). Ссылки на задачу в тексте — `[[t:N]]`, не `#<глобальный id>`.
|
|
||||||
|
|
||||||
**Slug-правила:** короткий, lowercase, kebab-case, латиница
|
|
||||||
(`fix-nl-vds-reality-pq-dest`, не `Fix_this_TASK #1`).
|
|
||||||
|
|
||||||
## Status emoji ↔ state
|
|
||||||
|
|
||||||
| Emoji | State | Значение |
|
|
||||||
|---|---|---|
|
|
||||||
| ⚪ | `ready` | единственное состояние, которое поллер берёт |
|
|
||||||
| 🔴 | `active` | взято / в работе |
|
|
||||||
| 🟡 | `paused` | возобновляемо |
|
|
||||||
| 🔵 | `blocked` | ждёт (указать почему в description/where_stopped) |
|
|
||||||
| 🟢 | `done` | закрыто |
|
|
||||||
|
|
||||||
Не путай: 🟢 — это *done*, не «готово».
|
|
||||||
|
|
||||||
## Legacy: блок .tasks/STATUS.md (интерм до #984)
|
|
||||||
|
|
||||||
Пока файловый поллер (agents-task-runner) не переключён на mappa-лиз (#984),
|
|
||||||
блоки в `.tasks/STATUS.md`, создаваемые руками/миграцией, обязаны совпадать со
|
|
||||||
строгим форматом — иначе поллер молча пропускает или паркует. **Это
|
|
||||||
переходный канон; новые задачи создавай через task_create.**
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## ⚪ [#1234 my-task-slug] — One-line description.
|
|
||||||
|
|
||||||
**Status:** ready
|
|
||||||
**Created:** 2026-08-23
|
|
||||||
**Where I stopped:** (not started)
|
|
||||||
**Next action:** First concrete step the claiming agent runs.
|
|
||||||
**Branch:** master
|
|
||||||
**Weight:** needs-claude
|
|
||||||
**Notify:** OpeItcLoc03/workshop
|
|
||||||
<!-- created-by: you@machine / from: OpeItcLoc03/workshop / 2026-08-23 -->
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Три load-bearing правила:
|
|
||||||
|
|
||||||
1. **Шапка точно:** `## <emoji> [#<n> <slug>] — <description>` — h2, один emoji,
|
|
||||||
`[#<n> <slug>]` (глобальный номер, без ведущих нулей), разделитель
|
|
||||||
` — ` (пробел + em-dash + пробел). Несовпавшая шапка = задача не видна вообще.
|
|
||||||
2. **Поля — строки `**Label:** value`.** Буллеты и проза игнорируются.
|
|
||||||
3. **`**Created:** yyyy-mm-dd` обязателен** — пишется один раз при создании.
|
|
||||||
|
|
||||||
Номера legacy-блоков назначает сервер (`tasks_create` из счётчика
|
|
||||||
`OpeItcLoc03/agenda/task-counter`) — **никогда не выдумывай номер руками**.
|
|
||||||
|
|
||||||
### Поля, которые поллер разбирает
|
|
||||||
|
|
||||||
| Field | Format | Meaning |
|
|
||||||
|---|---|---|
|
|
||||||
| `**Weight:**` | `cheap-ok` \| `needs-claude` \| `needs-human` | Тир маршрутизации. **Обязателен** для авто-взятия. |
|
|
||||||
| `**Notify:**` | `<owner>/<repo>` | Инбокс-адрес для событий close/park/delivery-failure. |
|
|
||||||
| `**Requirements:**` | CSV (`needs-db, needs-secrets`) | Capability-гейт: агент должен держать ВСЕ. |
|
|
||||||
| `**Runtime allowed:**` | CSV (`claude-opus`) | Runtime-whitelist. |
|
|
||||||
| `**Consult policy:**` | `auto` \| `human-only` \| `strict-human` | Эскалация consult; default `human-only`. |
|
|
||||||
| `**Blocker:**` | CSV blocker-slug'ов | Только на 🔵; авто-unblock при 🟢 всех. |
|
|
||||||
| `**Priority:**` | `P0` \| `P1` \| `P2` | Важность (task-priority-due). Отсутствует = `P1`. Влияет на порядок выдачи `claim_next` (P0-пул первый, внутри по дедлайну). **Ставится только при создании** — после агенты не меняют. |
|
|
||||||
| `**Due:**` | `yyyy-mm-dd` | Дедлайн (task-priority-due). Просроченные (due < today, ready/active) → overdue-scan уведомляет в инбокс однократно. Отсутствует = нет дедлайна. |
|
|
||||||
| `**Next action:** / **Where I stopped:** / **Branch:**` | free text | Резюмируемость. |
|
|
||||||
|
|
||||||
`**Owner:** / **Claim token:** / **Claim expires at:**` — claim-штамп, пишет и
|
|
||||||
чистит поллер. Не автори руками; залипший штамп на ⚪ блокирует поллер.
|
|
||||||
|
|
||||||
**Weight — поле, решающее взятие:** без `**Weight:**` поллер берёт задачу, не
|
|
||||||
находит тир и паркует в 🔵 (`no backend for weight_tier: unknown`). Обычный код
|
|
||||||
→ `needs-claude`; критикал-инфра (поллер, MCP-серверы, деплой, CI, git-хуки) →
|
|
||||||
`needs-human` (никогда не авто).
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
| Mistake | Fix |
|
|
||||||
|---|---|
|
|
||||||
| Рукописный блок вместо `task_create` | Создавай через тул — номер/формат серверные. |
|
|
||||||
| `### Title` / буллеты вместо полей | `## <emoji> [#n slug] — desc` + `**Field:** value`. |
|
|
||||||
| 🟢 для ready | 🟢 — done. Ready — ⚪. |
|
|
||||||
| Шапка `[slug]` без номера | `[#n slug]` — номер машинный ключ. |
|
|
||||||
| Выдуманный номер | Номер — только от сервера (task_create). |
|
|
||||||
| `**Created:**` отсутствует (legacy) | Добавить — обязательное поле. |
|
|
||||||
| Ссылка `#<глобальный id>` | Ссылайся `[[t:N]]` (решение 20/#1037). |
|
|
||||||
| Без `**Weight:**` (legacy) | Ставь всегда, или задача паркуется. |
|
|
||||||
| Агент бампает `**Priority:**`/`**Due:**` после создания | Нельзя — прецедент человека структурный; ставь только при создании, иначе сервер отклоняет. |
|
|
||||||
| Дефис/двоеточие вместо ` — ` в шапке | Разделитель — пробел + em-dash + пробел. |
|
|
||||||
|
|
||||||
## Verify
|
|
||||||
|
|
||||||
Задача корректна, когда: создана через `task_create` (или legacy-блок: шапка
|
|
||||||
`## <emoji> [#n slug] — …`, emoji = `**Status:**`, `**Created:**` есть, поля —
|
|
||||||
`**Label:**` строки, есть `**Weight:**` и `**Notify:**`); slug kebab-case;
|
|
||||||
ссылки на неё — `[[t:N]]`.
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
---
|
|
||||||
name: task-loop
|
|
||||||
author: ours
|
|
||||||
version: 0.1.0
|
|
||||||
description: >
|
|
||||||
Use when the user asks you to work the task board yourself, in this
|
|
||||||
session, one task after another — «поработай очередь», «прогони доску»,
|
|
||||||
«бери задачи по очереди», «работай пока не скажу стоп», «work the queue»,
|
|
||||||
«drain the board», «keep working tasks until I say stop». Does NOT apply
|
|
||||||
to delegating work to another agent/project (→ delegate-task), to one
|
|
||||||
named task you already know (→ using-tasks), or to configuring the
|
|
||||||
background poller.
|
|
||||||
---
|
|
||||||
|
|
||||||
# task-loop
|
|
||||||
|
|
||||||
Work the board **in this session**: claim the next ready task, do it, close it, claim the next — until the queue is empty or the user says stop.
|
|
||||||
|
|
||||||
**Core principle:** an interactive loop, not a daemon. You stay in the chair. Empty queue → **stop and report**, never spin a wait-timer. No subprocess, no `CronCreate` (that schedules a *separate* session — exactly the daemon you're replacing), no short `ScheduleWakeup` poll — those are the unattended poller's job, not yours here.
|
|
||||||
|
|
||||||
**REQUIRED SUB-SKILL:** `using-tasks` owns the board, the `.tasks/.lock` session lock, the `session_break` gate, and the pre-close coverage check. This skill drives the loop *through* those rules — it does not replace them.
|
|
||||||
**REQUIRED SUB-SKILL:** `project-discipline` — commit/push gate (Rule 4) and sensitive-artifact handling apply to every task you touch.
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
**Activates:** «поработай очередь», «прогони доску», «бери задачи по очереди», «работай пока не скажу стоп», «work the queue», «drain the board», «keep working tasks until I say stop».
|
|
||||||
|
|
||||||
**Does NOT apply:**
|
|
||||||
- Delegating work to another agent/project → `delegate-task`.
|
|
||||||
- One specific task you already named → `using-tasks` (switch/resume that task).
|
|
||||||
- Setting up / debugging the background poller or agent-runner → that is infra, not this loop.
|
|
||||||
|
|
||||||
## The loop
|
|
||||||
|
|
||||||
Run this cycle. One task at a time.
|
|
||||||
|
|
||||||
```dot
|
|
||||||
digraph task_loop {
|
|
||||||
rankdir=TB;
|
|
||||||
claim [shape=box, label="tasks_claim_next\n(current project, confirm=true)"];
|
|
||||||
empty [shape=diamond,label="task returned?"];
|
|
||||||
stop [shape=box, label="STOP — report board drained"];
|
|
||||||
work [shape=box, label="do the work this session"];
|
|
||||||
done [shape=diamond,label="completed?"];
|
|
||||||
park [shape=box, label="park: blocked (external) | paused (resumable)"];
|
|
||||||
gate [shape=diamond,label="consult_policy = human-only/strict-human?"];
|
|
||||||
consult [shape=box, label="STOP before close/commit — consult user"];
|
|
||||||
close [shape=box, label="pre-close coverage check → tasks_close"];
|
|
||||||
brk [shape=diamond,label="session_break marker on closed task?"];
|
|
||||||
boundary[shape=box, label="STOP — print SESSION BOUNDARY"];
|
|
||||||
|
|
||||||
claim -> empty;
|
|
||||||
empty -> stop [label="no ready tasks"];
|
|
||||||
empty -> work [label="yes"];
|
|
||||||
work -> done;
|
|
||||||
done -> park [label="no"];
|
|
||||||
done -> gate [label="yes"];
|
|
||||||
gate -> consult [label="yes"];
|
|
||||||
gate -> close [label="auto"];
|
|
||||||
close -> brk;
|
|
||||||
brk -> boundary [label="yes"];
|
|
||||||
brk -> claim [label="no"];
|
|
||||||
park -> claim;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. **Claim** the next ready task with `tasks_claim_next(claimer_identity, filter, confirm=true)`.
|
|
||||||
- `claimer_identity` = `<machine>:<runtime>:<session>` (e.g. `DESKTOP-NSEF0UK:claude-opus:<session>`).
|
|
||||||
- `filter.project` = **the current project** (qualified `<owner>/<repo>`) by default. Only widen to other projects when the user explicitly asks ("прогони все доски" / passes a project list).
|
|
||||||
- The server already excludes `weight: needs-human` and anti-self-review tasks — you will never claim those.
|
|
||||||
2. **No task returned** → the queue is drained. **STOP** and report (see *Empty queue*). Do not poll.
|
|
||||||
3. **Do the work this session.** All your tools are available. Read the task description and per-task `<slug>.md`. Set the task `active` if it isn't already.
|
|
||||||
4. **Honor the gate before the irreversible step.** Use the `consult_policy` returned by the claim:
|
|
||||||
- `auto` → full autopilot through close.
|
|
||||||
- `human-only` / `strict-human` → do the work, then **STOP before `tasks_close` / commit** and consult the user. Don't barrel through.
|
|
||||||
- **Push is never automatic** regardless of policy — `project-discipline` Rule 4 (commit freely, push only on an explicit per-session grant).
|
|
||||||
5. **Close** with the `using-tasks` pre-close coverage check, then `tasks_close(target_project, slug, confirm=true, note=…)`.
|
|
||||||
6. **session_break gate.** After the close, **before claiming the next task**, honor the `using-tasks` `session_break` check: if the closed task carries the marker → print the `🔚 SESSION BOUNDARY` line and **STOP** (do not claim next). Otherwise → back to step 1.
|
|
||||||
|
|
||||||
## When a task can't be finished
|
|
||||||
|
|
||||||
Never leave a claimed task hanging (its claim expires in 10 min and it returns as a zombie), and never `tasks_close` unfinished work (that lies to the board).
|
|
||||||
|
|
||||||
- **External / unresolvable blocker** discovered mid-task (missing upstream, needs a human decision, scope change) → `tasks_update(slug, status="blocked", blocker="<concrete fact + what's needed>")`. Roll back partial work that would break the build. Then continue the loop (the blocker is isolated; the next claim won't return this task).
|
|
||||||
- **Interrupted or resumable by you** (you ran out of budget, the user stops you mid-task) → `tasks_update(slug, status="paused", where_stopped=…, next_action=…)`.
|
|
||||||
|
|
||||||
A single failing task does not stop the loop — park it and move to the next.
|
|
||||||
|
|
||||||
## Empty queue & stopping
|
|
||||||
|
|
||||||
The loop ends on the **first** of:
|
|
||||||
- **Empty queue** — `tasks_claim_next` returns no ready task → stop, report what you closed/parked, and wait for the user. Do **not** `ScheduleWakeup`, `CronCreate`, or sleep-poll for new tasks.
|
|
||||||
- **Explicit user signal** — «стоп», «хватит», «отбой». Park any in-flight claimed task (paused) before stopping.
|
|
||||||
- **Budget** — `budget.remaining()` near zero → park the current task (paused) and report.
|
|
||||||
|
|
||||||
**Long-running watch (opt-in only).** If the user explicitly says «работай пока не скажу стоп» *and* wants you to keep checking for newly-arrived tasks, use **`ScheduleWakeup`** — it re-invokes *this* session — with a **long** interval (≥1200 s). **Never `CronCreate`** even here: it starts a *separate* scheduled session, i.e. the daemon this skill exists to avoid. And never a short poll. Default is still stop-on-empty; only arm a wakeup on an explicit standing request.
|
|
||||||
|
|
||||||
## Heartbeat
|
|
||||||
|
|
||||||
A claim lives 10 minutes. If a single task will take longer than ~8 minutes, call `tasks_heartbeat(slug, claim_token)` periodically to keep the claim alive. Short tasks need no heartbeat. (The in-session `.tasks/.lock` is a separate 2-hour lock owned by `using-tasks` session start/end — don't manage it from the loop.)
|
|
||||||
|
|
||||||
## What NOT to do
|
|
||||||
|
|
||||||
- **No daemon, no `CronCreate`, no spawned claude, no subprocess** to "run the queue" — `CronCreate` starts a separate scheduled session; the whole point is you do it in *this* session.
|
|
||||||
- **No busy-poll on empty** — empty queue is a natural stop, not a wait-loop. A short `ScheduleWakeup` loop burns tokens for nothing. The only exception is the explicit long-watch opt-in above (a single ≥1200 s `ScheduleWakeup`, never `CronCreate`).
|
|
||||||
- **Don't widen scope silently** — default to the current project; claim other boards only when the user asks.
|
|
||||||
- **Don't `tasks_close` unfinished work** and **don't leave a task claimed** when blocked — park it (blocked/paused).
|
|
||||||
- **Don't skip the `session_break` gate** between tasks — a milestone/domain-switch marker means stop, even if more tasks are ready.
|
|
||||||
- **Don't autopilot through a `human-only`/`strict-human` task's close/commit**, and **never auto-push** — consult first.
|
|
||||||
- **Don't blind-retry** a task that failed for an external reason — diagnose once, record the blocker, move on.
|
|
||||||
|
|
||||||
## Red flags — STOP
|
|
||||||
|
|
||||||
- "I'll set a timer to check for new tasks" → no. Stop on empty; report.
|
|
||||||
- "I'll spawn a background worker to drain faster" → no. One task at a time, this session.
|
|
||||||
- "User said work-until-stop, I'll `CronCreate` a recurring run" → no. `CronCreate` is a separate scheduled session = the daemon. Long-watch uses a single long `ScheduleWakeup` on *this* session.
|
|
||||||
- "It's sensitive but consult_policy says auto, I'll just commit" → push still needs a grant; sensitive close still respects the gate.
|
|
||||||
- "The task isn't done but I'll close it and note it" → never close unfinished. Park it.
|
|
||||||
@@ -85,11 +85,10 @@ setup; pi loads `~/.agents/skills` by default. Verify with `pi --help` / a fresh
|
|||||||
The update scripts (`scripts/update.sh` and `scripts/update.ps1`) handle:
|
The update scripts (`scripts/update.sh` and `scripts/update.ps1`) handle:
|
||||||
|
|
||||||
1. **git pull --ff-only** in `~/projects/skills/` (stash if dirty, pop after).
|
1. **git pull --ff-only** in `~/projects/skills/` (stash if dirty, pop after).
|
||||||
2. **Conditionally rebuild projects-meta-mcp** — if `~/projects/.common/lib/projects-meta-mcp/` has a `.git` directory and source changed (`git pull` fetched new commits), run `npm run build`.
|
2. **Conditionally rebuild interns-mcp** — same pattern, `pip install -e .`.
|
||||||
3. **Conditionally rebuild interns-mcp** — same pattern, `pip install -e .`.
|
3. **Install all skills** via `install.sh` / `install.ps1`.
|
||||||
4. **Install all skills** via `install.sh` / `install.ps1`.
|
4. **Show version diff** — before/after `version:` frontmatter for each skill.
|
||||||
5. **Show version diff** — before/after `version:` frontmatter for each skill.
|
5. **Print reload hints** — `/reload-mcp` if MCP changed, new session otherwise.
|
||||||
6. **Print reload hints** — `/reload-mcp` if MCP changed, new session otherwise.
|
|
||||||
|
|
||||||
## Out of scope
|
## Out of scope
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: using-markitdown
|
name: using-markitdown
|
||||||
author: ours
|
author: ours
|
||||||
version: 1.0.1
|
version: 1.1.0
|
||||||
description: Use when capturing external content into a markdown-based knowledge base, wiki `raw/` directory, or any pipeline that must preserve the source's full text — for web pages, PDFs, DOCX/PPTX/XLSX, EPUB, CSV/JSON/XML, ZIP archives, images (with OCR/EXIF), audio (with transcription), or YouTube URLs. Also use when WebFetch returned an LLM-summarized version but the raw content is what's needed.
|
description: Use when capturing external content into a markdown-based knowledge base, wiki `raw/` directory, or any pipeline that must preserve the source's full text — for web pages, PDFs, DOCX/PPTX/XLSX, EPUB, CSV/JSON/XML, ZIP archives, images (with OCR/EXIF), audio (with transcription), or YouTube URLs. Also use when WebFetch returned an LLM-summarized version but the raw content is what's needed.
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ No mount caveats: the CLI is a normal local process. The old Docker `-v` mount t
|
|||||||
1. markitdown "https://example.com/foo.pdf" -o .wiki/raw/<slug>.md (kebab-case, Latin only)
|
1. markitdown "https://example.com/foo.pdf" -o .wiki/raw/<slug>.md (kebab-case, Latin only)
|
||||||
2. Inspect the head of the result. If it looks like a sign-in/cookie/consent page, abort — ask the user for an alternative (manual save, paste, authenticated source).
|
2. Inspect the head of the result. If it looks like a sign-in/cookie/consent page, abort — ask the user for an alternative (manual save, paste, authenticated source).
|
||||||
3. Register the new file in .wiki/raw/README.md.
|
3. Register the new file in .wiki/raw/README.md.
|
||||||
4. Hand off to the wiki ingest workflow (creates sources/<slug>.md summary + entity/concept updates).
|
4. Hand off to the wiki ingest workflow (creates summaries/<slug>.md summary + entity/concept updates).
|
||||||
```
|
```
|
||||||
|
|
||||||
For a huge (book-length) document, write straight to a file with `-o` and summarize *from the saved file* — do not pipe the whole markdown through working context.
|
For a huge (book-length) document, write straight to a file with `-o` and summarize *from the saved file* — do not pipe the whole markdown through working context.
|
||||||
@@ -63,7 +63,7 @@ For a huge (book-length) document, write straight to a file with `-o` and summar
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Output is a Google/Microsoft sign-in page in some random language | URI behind auth wall | Ask user to export the content manually (Save as PDF, copy-paste) and put it in `raw/` |
|
| Output is a Google/Microsoft sign-in page in some random language | URI behind auth wall | Ask user to export the content manually (Save as PDF, copy-paste) and put it in `raw/` |
|
||||||
| Output is mostly nav/cookie banner text | Site is JS-rendered or anti-bot | Try the cached or print URL; or ask user for HTML export |
|
| Output is mostly nav/cookie banner text | Site is JS-rendered or anti-bot | Try the cached or print URL; or ask user for HTML export |
|
||||||
| Output lacks images / diagrams | Markdown is text-only by design | Save the original asset separately under `raw/assets/`; reference it from the `sources/` summary |
|
| Output lacks images / diagrams | Markdown is text-only by design | Save the original asset separately under `raw/assets/`; reference it from the `summaries/` summary |
|
||||||
| `markitdown: command not found` | CLI not on `PATH` | Confirm with `markitdown --version` (expect `markitdown 0.1.6`); install with `pip install markitdown[all]` if missing |
|
| `markitdown: command not found` | CLI not on `PATH` | Confirm with `markitdown --version` (expect `markitdown 0.1.6`); install with `pip install markitdown[all]` if missing |
|
||||||
| Huge output (book-length) | Whole document converted in one call | Use `-o <file>` to save raw, then summarize *from the saved file* — do not hold the entire markdown in working context |
|
| Huge output (book-length) | Whole document converted in one call | Use `-o <file>` to save raw, then summarize *from the saved file* — do not hold the entire markdown in working context |
|
||||||
|
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
# using-projects-meta
|
|
||||||
|
|
||||||
Runtime policy for the local `projects-meta-mcp` stdio server. Two
|
|
||||||
responsibilities, one server:
|
|
||||||
|
|
||||||
1. **Cross-project task aggregation** — reads / writes `.tasks/STATUS.md` in
|
|
||||||
any of the user's Gitea repos.
|
|
||||||
2. **Shared knowledge wiki** — query / ingest a single Gitea-backed wiki at
|
|
||||||
`~/projects/projects-wiki/.wiki/` (clone root: `~/projects/projects-wiki/`,
|
|
||||||
Gitea repo: `projects-wiki`).
|
|
||||||
|
|
||||||
`using-projects-meta` governs *usage* of an installed server. Initial setup
|
|
||||||
(clone, build, `auth.toml`, MCP registration) is owned by
|
|
||||||
[`setup-projects-meta`](../setup-projects-meta/).
|
|
||||||
|
|
||||||
Full server reference:
|
|
||||||
`mcp__projects-meta__knowledge_get slug=packages/projects-meta-mcp`.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- User asks for cross-project state ("what's on the boards", "across all
|
|
||||||
projects", "что у меня на досках", "по всем проектам").
|
|
||||||
- User wants to query / ingest the shared wiki ("check shared wiki", "search
|
|
||||||
projects-wiki", "ingest into shared wiki", "общая вики", "заингесть в общую").
|
|
||||||
- User wants to create / update / close a task in *another* project from the
|
|
||||||
current cwd ("заведи в проекте X задачу", "close task Y in project Z").
|
|
||||||
- User asks for sync diagnostics ("when did the cache last refresh", "are there
|
|
||||||
sync errors").
|
|
||||||
- If `mcp__projects-meta__*` tools are missing, this skill delegates to
|
|
||||||
[`setup-projects-meta`](../setup-projects-meta/) before doing anything else.
|
|
||||||
|
|
||||||
## Local-first rule (critical)
|
|
||||||
|
|
||||||
For the **current** project — read disk directly (`.tasks/STATUS.md`,
|
|
||||||
`.wiki/index.md`). The MCP cache:
|
|
||||||
|
|
||||||
- May be stale (sync runs only when triggered).
|
|
||||||
- Hides `🟢 done` by default.
|
|
||||||
- May not contain unpushed projects.
|
|
||||||
|
|
||||||
Use MCP only for **other** projects, **other** machines, or the **shared**
|
|
||||||
wiki content. See the table below.
|
|
||||||
|
|
||||||
| Question | Where to read |
|
|
||||||
|---|---|
|
|
||||||
| "What's the status of *this* project?" | local `.tasks/STATUS.md` |
|
|
||||||
| "What's on all my boards?" | `mcp__projects-meta__tasks_aggregate` |
|
|
||||||
| "Has *this* project's wiki got X?" | local `.wiki/index.md` |
|
|
||||||
| "Has the **shared** wiki got X?" | `mcp__projects-meta__knowledge_search` |
|
|
||||||
| "Sync state across machines?" | `mcp__projects-meta__meta_status` |
|
|
||||||
|
|
||||||
## Step 0 — Freshness gate (v1.1.0, mandatory pre-flight)
|
|
||||||
|
|
||||||
`projects-meta` is a bus between machines — another host may have pushed
|
|
||||||
minutes ago. Without this gate, reads return stale data and writes hit
|
|
||||||
sha-based optimistic-lock 422s with no explanation.
|
|
||||||
|
|
||||||
Before **any** `tasks_*` or `knowledge_*` call:
|
|
||||||
|
|
||||||
1. `mcp__projects-meta__meta_status` — probe cache age + errors.
|
|
||||||
2. If `cache_age_minutes` > 10 OR `errors_count` > 0 →
|
|
||||||
`node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js`.
|
|
||||||
3. For shared-wiki **writes** (`knowledge_ingest`, `knowledge_promote`) →
|
|
||||||
**also** `git -C ~/projects/projects-wiki pull --ff-only`. Unconditional.
|
|
||||||
The MCP server uses sha-based optimistic locking on the wiki repo;
|
|
||||||
without an up-to-date local SHA the commit is rejected with a 422.
|
|
||||||
4. For tasks-mutations (`tasks_create`/`update`/`close`) → sync via
|
|
||||||
`dist/sync.js` is enough; there's no local clone of the target tasks repo.
|
|
||||||
5. If sync returns **401 / 403** → STOP. Token is dead. Send the user to
|
|
||||||
`~/.config/projects-mcp/auth.toml` to rotate `gitea_token`. Don't
|
|
||||||
pretend success, don't retry silently.
|
|
||||||
|
|
||||||
**Don't sync unconditionally** on every call — overhead + 401-risk for
|
|
||||||
casual reads. The 10-minute window is the chosen threshold.
|
|
||||||
|
|
||||||
**Don't apply Step 0 to `meta_status` itself** — it's the probe.
|
|
||||||
|
|
||||||
## Two operation classes
|
|
||||||
|
|
||||||
### Read (no confirmation)
|
|
||||||
|
|
||||||
`tasks_aggregate`, `tasks_search`, `tasks_get`, `knowledge_search`,
|
|
||||||
`knowledge_get`, `knowledge_suggest_promote`, `meta_status` — all
|
|
||||||
side-effect-free. Call directly, cite the result.
|
|
||||||
|
|
||||||
### Mutate (always two-step)
|
|
||||||
|
|
||||||
`tasks_create`, `tasks_update`, `tasks_close`, `knowledge_ingest`,
|
|
||||||
`knowledge_promote` — write to Gitea. Procedure:
|
|
||||||
|
|
||||||
1. Call **without** `confirm: true` → returns dry-run preview (proposed file
|
|
||||||
diff + commit message).
|
|
||||||
2. Show the preview to the user. Wait for explicit "ok" / "go" / "поехали".
|
|
||||||
3. Re-call with `confirm: true` → committed.
|
|
||||||
|
|
||||||
**Never inline `confirm: true` on the first call.** A trigger phrase is
|
|
||||||
permission to plan, not to commit.
|
|
||||||
|
|
||||||
## Tool quick reference
|
|
||||||
|
|
||||||
### Read
|
|
||||||
|
|
||||||
| Tool | Required args | Purpose |
|
|
||||||
|---|---|---|
|
|
||||||
| `mcp__projects-meta__tasks_aggregate` | — | All active tasks across cached projects |
|
|
||||||
| `mcp__projects-meta__tasks_search` | `query` | Substring search across slug + next_action |
|
|
||||||
| `mcp__projects-meta__tasks_get` | `project` | Raw STATUS.md of one project (cache snapshot) |
|
|
||||||
| `mcp__projects-meta__knowledge_search` | `query`; opt `domain`, `limit` | Shared-wiki search; default domain auto-detected from cwd |
|
|
||||||
| `mcp__projects-meta__knowledge_get` | `slug` | Full text of one wiki page |
|
|
||||||
| `mcp__projects-meta__knowledge_suggest_promote` | — | Local `.wiki/concepts/` candidates for shared promotion |
|
|
||||||
| `mcp__projects-meta__meta_status` | — | Sync diagnostics (cache age, project / page / error counts) |
|
|
||||||
|
|
||||||
### Mutate (need `write:repository` Gitea scope)
|
|
||||||
|
|
||||||
| Tool | Required args | Effect |
|
|
||||||
|---|---|---|
|
|
||||||
| `mcp__projects-meta__tasks_create` | `target_project`, `slug`, `description`, `next_action` | Append block to target's `.tasks/STATUS.md` via Gitea commit |
|
|
||||||
| `mcp__projects-meta__tasks_update` | `target_project`, `slug` + ≥1 mutable field | Sha-based optimistic lock; 422 on conflict |
|
|
||||||
| `mcp__projects-meta__tasks_close` | `target_project`, `slug` (+ opt `note`) | Marks task 🟢 done with identity-footer |
|
|
||||||
| `mcp__projects-meta__knowledge_ingest` | `target_project`, `type`, `slug`, `body` | Three commits: `<type>/<slug>.md` + `index.md` + `log.md` |
|
|
||||||
| `mcp__projects-meta__knowledge_promote` | `target_project`, `slug`, `body` | Move `raw/<slug>.md` → `sources/<slug>.md` |
|
|
||||||
|
|
||||||
`type` ∈ `entities` / `concepts` / `packages` / `sources` / `raw`.
|
|
||||||
`target_project` = Gitea repo name, or `_meta` (meta-tasks / meta-wiki repos
|
|
||||||
from `auth.toml`).
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
- **Reading current project's tasks via `tasks_get`.** Read `.tasks/STATUS.md`
|
|
||||||
on disk; the MCP cache is for *other* projects.
|
|
||||||
- **Inlining `confirm: true` on first call.** Always preview first; show user;
|
|
||||||
only then `confirm: true`.
|
|
||||||
- **Confusing the local `.wiki/` with the shared `projects-wiki`.** They are
|
|
||||||
two different stores. `using-wiki` operates on the local one;
|
|
||||||
`using-projects-meta` queries / ingests the shared one.
|
|
||||||
- **Acting on stale `tasks_aggregate`.** If `meta_status.age_seconds` > 3600,
|
|
||||||
either run `node dist/sync.js` (in `~/projects/.common/lib/projects-meta-mcp`) or warn the
|
|
||||||
user about staleness.
|
|
||||||
- **Vague `knowledge_search` queries.** "auth" returns noise. Multi-word,
|
|
||||||
specific queries return targeted snippets.
|
|
||||||
- **Wrong `type` on `knowledge_ingest`.** Mis-typed pages land in the wrong
|
|
||||||
section and break `index.md`. Pick from the five canonical types.
|
|
||||||
|
|
||||||
## When NOT to use
|
|
||||||
|
|
||||||
- The current project's own tasks — read `.tasks/STATUS.md`.
|
|
||||||
- The current project's own wiki — read `.wiki/`.
|
|
||||||
- Library / framework documentation — that's [`using-context7`](../using-context7/).
|
|
||||||
- Repo-internal code search — that's `Glob` / `Grep`.
|
|
||||||
- One-off git history questions — `git log`.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
From the repo root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/install.sh using-projects-meta
|
|
||||||
```
|
|
||||||
|
|
||||||
Works on Windows under git-bash, Linux, macOS.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- [`setup-projects-meta`](../setup-projects-meta/) — companion, owns server
|
|
||||||
install + MCP registration.
|
|
||||||
- [`using-context7`](../using-context7/) — sister skill for library docs (same
|
|
||||||
using-X structure).
|
|
||||||
- [`using-tasks`](../using-tasks/), [`using-wiki`](../using-wiki/) —
|
|
||||||
per-project policies for in-repo `.tasks/` and `.wiki/`. Orthogonal to this
|
|
||||||
skill; together they cover both per-project and cross-project state.
|
|
||||||
@@ -1,238 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-projects-meta
|
|
||||||
author: ours
|
|
||||||
version: 1.2.0
|
|
||||||
description: Use when working across multiple projects on one or many machines — cross-project task aggregation (`mcp__projects-meta__tasks_*`), shared Gitea-backed wiki query / ingest (`mcp__projects-meta__knowledge_*`), or sync diagnostics (`mcp__projects-meta__meta_status`). Triggers on phrases like "across all projects", "what's on the boards", "check shared wiki", "search projects-wiki", "ingest into shared wiki", "что у меня на досках", "по всем проектам", "общая вики", "cross-project status", or any time the user wants to see / mutate state in another repo than the current cwd. v1.1.0 mandates a Step 0 freshness gate (probe `meta_status`, sync if stale, pull `projects-wiki` before shared-wiki writes) — see SKILL body. Mutation tools require two-step preview → confirm. Skip for the **current** project's tasks/wiki — those live on disk in `.tasks/` / `.wiki/`.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Using the projects-meta MCP server
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
`projects-meta-mcp` is a local stdio MCP server. Two responsibilities:
|
|
||||||
|
|
||||||
1. **Cross-project task aggregation** — parses `.tasks/STATUS.md` from every repo on the user's Gitea, caches them in `~/.cache/projects-mcp/tasks.json`. Read tools (`tasks_aggregate`, `tasks_search`, `tasks_get`) hit the cache. Mutations (`tasks_create`, `tasks_update`, `tasks_close`) commit back to Gitea with sha-based optimistic lock.
|
|
||||||
2. **Shared knowledge wiki** — single Gitea repo (`projects-wiki`) cloned at `~/projects/projects-wiki/` with content at `~/projects/projects-wiki/.wiki/`, structured as packages / concepts / entities / sources / raw. `knowledge_search` + `knowledge_get` for queries, `knowledge_ingest` + `knowledge_promote` for writes.
|
|
||||||
|
|
||||||
Source of truth: Gitea (`https://git.kzntsv.site`, owner `OpeItcLoc03`). Cache and clone are local convenience.
|
|
||||||
|
|
||||||
Full reference: `mcp__projects-meta__knowledge_get slug=packages/projects-meta-mcp`.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
This skill assumes `mcp__projects-meta__*` tools are available. If they aren't (tools missing from the session, or calls fail with a connection error), the server isn't running for this session. Trigger the **`setup-projects-meta`** skill to clone, build, write `auth.toml`, and register `mcpServers.projects-meta` in `~/.claude.json`. It's a one-time procedure with confirmation gates.
|
|
||||||
|
|
||||||
## Local-first rule
|
|
||||||
|
|
||||||
**For the current project — read disk directly.** `.tasks/STATUS.md` and `.wiki/` files in cwd are always fresher than the MCP cache. The cache:
|
|
||||||
|
|
||||||
- May be stale (default sync runs only when triggered).
|
|
||||||
- Hides 🟢 done by default.
|
|
||||||
- May not contain locally-developed projects that aren't pushed to Gitea yet.
|
|
||||||
|
|
||||||
Use MCP only for **other** projects, **other** machines, or **shared** wiki content.
|
|
||||||
|
|
||||||
| Question | Where to read |
|
|
||||||
|---|---|
|
|
||||||
| "What's the status of *this* project?" | local `.tasks/STATUS.md` |
|
|
||||||
| "What's on all my boards?" | `mcp__projects-meta__tasks_aggregate` |
|
|
||||||
| "Has *this* project's wiki got a page on X?" | local `.wiki/index.md` + relevant file |
|
|
||||||
| "Has the **shared** wiki got a page on X?" | `mcp__projects-meta__knowledge_search` |
|
|
||||||
| "Sync state across machines?" | `mcp__projects-meta__meta_status` |
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
- Cross-project task overview ("what am I working on across projects", "по всем проектам", "across the board").
|
|
||||||
- Hopping into another repo's task state without cloning it ("what's the status of project X").
|
|
||||||
- Querying the shared wiki for cross-cutting concepts (patterns, package references, design notes that apply to several repos).
|
|
||||||
- Ingesting a finished design / decision into the shared wiki so other machines / projects can see it.
|
|
||||||
- Creating a task in another project's `.tasks/STATUS.md` from the current repo (cross-project handoff).
|
|
||||||
- Sync diagnostics (when did the cache last refresh, are there errors, how many projects).
|
|
||||||
|
|
||||||
## When NOT to use
|
|
||||||
|
|
||||||
- The current project's own tasks or wiki — read disk.
|
|
||||||
- Anything inside a single project — `.tasks/<task>.md` and `.wiki/<page>.md` are always closer.
|
|
||||||
- One-off questions answered by `git log` or a single file.
|
|
||||||
- Library / framework documentation — that's `using-context7`.
|
|
||||||
- Code search — that's `Glob` / `Grep`.
|
|
||||||
|
|
||||||
## Step 0 — Freshness gate (run before any tool)
|
|
||||||
|
|
||||||
`projects-meta` is a bus between machines. Another host may have pushed minutes ago. Without this gate, reads return stale data and writes hit sha-based optimistic-lock 422s with no explanation. Mandatory pre-flight, every session, every workflow:
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Call mcp__projects-meta__meta_status.
|
|
||||||
|
|
||||||
2. Branch on cache freshness:
|
|
||||||
• If cache_age_minutes > 10 OR errors_count > 0:
|
|
||||||
run `node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js`
|
|
||||||
(or `npm run sync` from ~/projects/.common/lib/projects-meta-mcp).
|
|
||||||
• Else: cache is fresh enough — skip sync, no need to hit the network.
|
|
||||||
|
|
||||||
3. For shared-wiki WRITES (knowledge_ingest, knowledge_promote):
|
|
||||||
ALWAYS additionally run `git -C ~/projects/projects-wiki pull --ff-only`
|
|
||||||
regardless of cache age. The MCP server uses sha-based optimistic locking;
|
|
||||||
without an up-to-date local file SHA, the commit will be rejected (422)
|
|
||||||
and the failure mode is opaque to the user.
|
|
||||||
|
|
||||||
4. For tasks-mutations (tasks_create, tasks_update, tasks_close):
|
|
||||||
sync via dist/sync.js is enough — there's no local clone of the target
|
|
||||||
tasks repo, mutations go straight through Gitea API. Sync only refreshes
|
|
||||||
the local view so you reason from current state.
|
|
||||||
|
|
||||||
5. If sync returns 401 or 403:
|
|
||||||
STOP. The Gitea token in ~/.config/projects-mcp/auth.toml is dead or
|
|
||||||
wrong-scoped. Tell the user explicitly:
|
|
||||||
"Gitea sync failed with <401|403>. Rotate gitea_token in
|
|
||||||
~/.config/projects-mcp/auth.toml (Gitea: settings/applications)
|
|
||||||
and rerun."
|
|
||||||
Do not pretend sync succeeded. Do not retry silently.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Don't sync unconditionally on every call.** Network overhead + risk of 401 even on a casual "what's on my boards". The 10-minute cache window is the right balance — catches multi-machine drift without burning Gitea round-trips for back-to-back questions.
|
|
||||||
|
|
||||||
**Don't apply Step 0 to `meta_status` itself** — it's the freshness probe, not a downstream read.
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
### Read (no confirmation needed)
|
|
||||||
|
|
||||||
```
|
|
||||||
0. Run Step 0 — Freshness gate (above) first.
|
|
||||||
1. Identify what you need: cross-project tasks? shared wiki page? sync state?
|
|
||||||
2. Pick the right read tool (table below).
|
|
||||||
3. Cite the result with the source slug / project name.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mutate (always two-step)
|
|
||||||
|
|
||||||
```
|
|
||||||
0. Run Step 0 — Freshness gate (above) first.
|
|
||||||
For shared-wiki writes (knowledge_ingest, knowledge_promote): unconditional
|
|
||||||
`git -C ~/projects/projects-wiki pull --ff-only` is part of Step 0.
|
|
||||||
1. Identify the mutation: tasks_create / tasks_update / tasks_close / knowledge_ingest / knowledge_promote.
|
|
||||||
2. Call the tool WITHOUT `confirm: true` → returns a dry-run preview (the proposed file diff and the Gitea commit message).
|
|
||||||
3. Show the preview to the user. Wait for explicit "ok" / "go" / "поехали".
|
|
||||||
4. Re-call with `confirm: true` to commit.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Never inline `confirm: true` on the first call.** A trigger phrase ("create a task in project X") is permission to *plan*, not to *commit*.
|
|
||||||
|
|
||||||
## Tool quick reference
|
|
||||||
|
|
||||||
### Read tools
|
|
||||||
|
|
||||||
| Tool | Required args | Purpose |
|
|
||||||
|---|---|---|
|
|
||||||
| `mcp__projects-meta__tasks_aggregate` | — | All active tasks across all cached projects |
|
|
||||||
| `mcp__projects-meta__tasks_search` | `query` | Substring search across slug + next_action |
|
|
||||||
| `mcp__projects-meta__tasks_get` | `project` | Raw STATUS.md of one project (cached snapshot) |
|
|
||||||
| `mcp__projects-meta__knowledge_search` | `query`; opt `domain`, `limit` | Shared-wiki search; auto-detects domain from cwd, pass `domain="all"` to disable |
|
|
||||||
| `mcp__projects-meta__knowledge_get` | `slug` | Full text of one wiki page (e.g. `packages/projects-meta-mcp`) |
|
|
||||||
| `mcp__projects-meta__knowledge_suggest_promote` | — | Local `.wiki/concepts/` candidates for shared-wiki promotion |
|
|
||||||
| `mcp__projects-meta__meta_status` | — | Sync diagnostics: cache age, project count, error count, page count |
|
|
||||||
|
|
||||||
### Mutation tools (need `write:repository` Gitea scope; preview → confirm)
|
|
||||||
|
|
||||||
| Tool | Required args | Effect |
|
|
||||||
|---|---|---|
|
|
||||||
| `mcp__projects-meta__tasks_create` | `target_project`, `slug`, `description`, `next_action` (+ opt `where_stopped`, `status`, `blocker`, `branch`, `source_project`) | Append block to `<target>/.tasks/STATUS.md` via Gitea commit |
|
|
||||||
| `mcp__projects-meta__tasks_update` | `target_project`, `slug` + ≥1 of `where_stopped` / `next_action` / `blocker` / `branch` / `description` / `status` | Sha-based optimistic lock; 422 on conflict |
|
|
||||||
| `mcp__projects-meta__tasks_close` | `target_project`, `slug` (+ opt `note`) | Sets task to 🟢 done; appends identity-footer |
|
|
||||||
| `mcp__projects-meta__knowledge_ingest` | `target_project`, `type`, `slug`, `body` (+ opt `frontmatter`, `source_project`) | Three commits: `<type>/<slug>.md` + `index.md` + `log.md`. `type` ∈ entities / concepts / packages / sources / raw |
|
|
||||||
| `mcp__projects-meta__knowledge_promote` | `target_project`, `slug`, `body` (+ opt `frontmatter`, `source_project`) | Move `raw/<slug>.md` → `sources/<slug>.md` with auto `raw_path` link |
|
|
||||||
|
|
||||||
`target_project` is **qualified** `<owner>/<repo>` (e.g. `victor/books`, `OpeItcLoc03/skills`), or the literal `agenda` for the cross-project meta-board (resolves via `agenda_tasks_repo` in `auth.toml`). Bare names (`books`) are rejected with a hint to use the qualified form. Cross-cutting design: shared wiki → `concepts/projects-meta-multi-owner`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Read example: cross-project status
|
|
||||||
|
|
||||||
User: "что у меня на досках?"
|
|
||||||
|
|
||||||
```
|
|
||||||
1. mcp__projects-meta__tasks_aggregate
|
|
||||||
→ 7 projects, 12 active tasks
|
|
||||||
|
|
||||||
2. Group by project, summarize 1 line per active task.
|
|
||||||
Cite project name; if a task is stale (cache age > 1h), flag it.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Read example: shared wiki query
|
|
||||||
|
|
||||||
User: "есть ли в общей вики что-то про setup-using паттерн?"
|
|
||||||
|
|
||||||
```
|
|
||||||
1. mcp__projects-meta__knowledge_search
|
|
||||||
query: "setup-using skill pair pattern"
|
|
||||||
domain: "all"
|
|
||||||
→ hits include concepts/setup-using-skill-pair
|
|
||||||
|
|
||||||
2. mcp__projects-meta__knowledge_get
|
|
||||||
slug: "concepts/setup-using-skill-pair"
|
|
||||||
→ full text
|
|
||||||
|
|
||||||
3. Summarize, link with markdown to the slug.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mutation example: create cross-project task
|
|
||||||
|
|
||||||
User: "заведи в проекте books задачу на миграцию `settings.json`"
|
|
||||||
|
|
||||||
```
|
|
||||||
1. mcp__projects-meta__tasks_create
|
|
||||||
target_project: "victor/books"
|
|
||||||
slug: "settings-json-migration"
|
|
||||||
description: "<...>"
|
|
||||||
next_action: "<...>"
|
|
||||||
(no `confirm`)
|
|
||||||
→ preview: proposed STATUS.md diff + commit message
|
|
||||||
|
|
||||||
2. Show preview to user.
|
|
||||||
|
|
||||||
3. User: "ok, go"
|
|
||||||
|
|
||||||
4. mcp__projects-meta__tasks_create
|
|
||||||
(same args + confirm: true)
|
|
||||||
→ committed to Gitea
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mutation example: closing a cross-project task
|
|
||||||
|
|
||||||
User: "close `[projects-meta-skills]` in skills"
|
|
||||||
|
|
||||||
```
|
|
||||||
1. mcp__projects-meta__tasks_close
|
|
||||||
target_project: "OpeItcLoc03/skills"
|
|
||||||
slug: "projects-meta-skills"
|
|
||||||
note: "<one-line summary>"
|
|
||||||
(no `confirm`)
|
|
||||||
→ preview
|
|
||||||
|
|
||||||
2. User confirms.
|
|
||||||
|
|
||||||
3. Re-call with confirm: true.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
| Mistake | Fix |
|
|
||||||
|---|---|
|
|
||||||
| Reading current project's tasks via `tasks_get` instead of disk | Read `.tasks/STATUS.md` directly. MCP is for *other* projects. |
|
|
||||||
| Inlining `confirm: true` on the first mutation call | Always preview first; show user; only then `confirm: true`. |
|
|
||||||
| Using `knowledge_search` for the project's own wiki | The shared wiki is a separate Gitea repo. Local `.wiki/` is in cwd. |
|
|
||||||
| Acting on a stale `tasks_aggregate` without checking `meta_status` | Step 0 — Freshness gate is mandatory. If `cache_age_minutes` > 10 (or errors > 0), run `node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js` first. |
|
|
||||||
| Skipping `git -C ~/projects/projects-wiki pull` before `knowledge_ingest` / `knowledge_promote` | sha-based optimistic lock will reject the commit (422) and the failure is opaque. Pull is unconditional for shared-wiki writes — fast-forward is a no-op when current. |
|
|
||||||
| Treating sync 401/403 as "MCP is fine, the page just doesn't exist yet" | 401/403 means the Gitea token is dead. Stop, tell the user to rotate `gitea_token` in `~/.config/projects-mcp/auth.toml`. Never guess on stale data. |
|
|
||||||
| Calling `knowledge_ingest` with the wrong `type` | `type` must be one of `entities` / `concepts` / `packages` / `sources` / `raw`. Mis-typed pages land in the wrong section and break `index.md`. |
|
|
||||||
| Vague `knowledge_search` queries ("auth", "config") | Specific multi-word queries return targeted snippets; vague ones return noise. |
|
|
||||||
| Forgetting `domain="all"` when searching across families | Default `domain` is auto-detected from cwd; use `"all"` if the wiki page lives in a different family. |
|
|
||||||
| Passing bare project name (`target_project: "books"`) to mutation tools | v2.x rejects bare names. Use qualified `<owner>/<repo>` (e.g. `victor/books`, `OpeItcLoc03/skills`). Literal `agenda` is the only exception (cross-project meta-board). |
|
|
||||||
|
|
||||||
## Red flags
|
|
||||||
|
|
||||||
- "I'll just commit it directly" → no. Mutation tools have a preview step for a reason — silent writes to another repo are a recipe for drift.
|
|
||||||
- "The cache is fresh enough" → run Step 0. The 10-minute window is the threshold; below it skip sync, above it sync. Don't eyeball this — the bus moves fast in cross-machine sessions.
|
|
||||||
- "I'll skip the pull, my last write was 30 seconds ago" → another machine pushed in between. Always pull before shared-wiki writes; the sha-lock check is your only safety net.
|
|
||||||
- "I'll skip the wiki page" → if you're answering a cross-cutting question and there's no wiki page, that's a `knowledge_ingest` candidate. Surface it to the user.
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-system-snapshot
|
|
||||||
author: ours
|
|
||||||
version: 1.0.0
|
|
||||||
description: "Use at the start of an ops-context session, and ALWAYS before asserting anything about the mappa meta-service, the agent poller, local docker containers, or cross-project task load — call `mcp__mappa__meta_health` + `mcp__mappa__admin_status` (сервис жив, нагрузка) and `mcp__projects-meta__meta_system_snapshot` (поллер/докер/таски) instead of running `tasklist` / `docker ps` / guessing by hand. Triggers on «что запущено», «что сейчас крутится», «состояние системы», «состояние машины», «поллер работает?», «поллер живой?», «что с докером», «сводка по задачам», «what's running», «system status», «system snapshot», «is the poller up», «is the runner alive», «what containers are up». Read-only — no per-session grant needed. Skip for deep single-container docker diagnosis (that's using-vds-ops for the VDS / docker logs locally) and for mutating or precise per-task work (that's using-projects-meta / mappa task.*)."
|
|
||||||
---
|
|
||||||
|
|
||||||
# using-system-snapshot
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Two layers, one mental model: **mappa meta-service** (решение 14/15 — мета в сервисе) + **машина** (поллер/докер/таск-нагрузка — внешняя инфра).
|
|
||||||
|
|
||||||
1. Сервис жив и как загружен: `mcp__mappa__meta_health` (no args → `{ok}`) + `mcp__mappa__admin_status` (счётчики сущностей по типам/проектам — живая нагрузка).
|
|
||||||
2. Машина: `mcp__projects-meta__meta_system_snapshot` — поллер agents-task-runner, локальные docker-контейнеры, сводка таск-нагрузки из кэша.
|
|
||||||
|
|
||||||
Заменяет старый разброс `tasklist` / `docker ps` / ручного `meta_status` одной-двумя зондами.
|
|
||||||
|
|
||||||
**Core rule: never assert состояние сервиса, поллера, контейнеров или таск-нагрузки без вызова тула в этом же turn.** Память и «он же работал ранее» — не evidence.
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
- Session start в **ops-контексте** — ориентация перед infra/раннер/борд-работой.
|
|
||||||
- User спрашивает что живо: «что запущено», «состояние системы», «поллер работает?», «что с докером», «what's running», «is the poller up».
|
|
||||||
- **Перед любым claim** о живости mappa-сервиса, поллера, контейнера или числа активных/блокированных тасок.
|
|
||||||
- Быстрый взгляд на таск-нагрузку (где сейчас сконцентрирована работа).
|
|
||||||
|
|
||||||
## When NOT to use
|
|
||||||
|
|
||||||
- Глубокая диагностика **одного** контейнера (logs/inspect/stats/restart-loop) — это using-vds-ops для Rusonyx VDS или `docker logs` локально.
|
|
||||||
- **Мутации** тасок или чтение полного борда/тела задачи — using-projects-meta (и mappa task.* / локальный `.tasks/` для текущего проекта).
|
|
||||||
- Библиотечные доки, поиск по коду — не сюда.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- `mcp__mappa__*` — mappa MCP (сервис meta; установка — setup-проект mappa).
|
|
||||||
- `mcp__projects-meta__meta_system_snapshot` — projects-meta-mcp (поллер/докер/кэш-таски). Если тула нет — `setup-projects-meta`.
|
|
||||||
|
|
||||||
## The calls
|
|
||||||
|
|
||||||
`mcp__mappa__meta_health` — no args, read-only. `{ok: true, service: "mappa"}` — сервис жив.
|
|
||||||
`mcp__mappa__admin_status` — no args, read-only. Счётчики по типам и проектам.
|
|
||||||
`mcp__projects-meta__meta_system_snapshot` — no args, read-only. Три ключа:
|
|
||||||
|
|
||||||
| Key | Shape | Liveness |
|
|
||||||
|---|---|---|
|
|
||||||
| `poller` | `{ running: bool, projects: "<owner/repo …>" }` | **live** на момент вызова |
|
|
||||||
| `docker` | `[{ name, status }]` — локальные контейнеры | **live** на момент вызова |
|
|
||||||
| `tasks` | `{ "<owner>/<repo>": { active, blocked }, … }` | **из кэша** projects-meta — может быть stale |
|
|
||||||
|
|
||||||
`docker` — **локальная** машина (включая `agents-task-runner-*`), НЕ VDS. `tasks` — кэш; для точного состояния — using-projects-meta Step 0 или mappa/локальный `.tasks/`.
|
|
||||||
|
|
||||||
## Output format — одна строка на секцию
|
|
||||||
|
|
||||||
Сожми в 3–4 строки, не дампи raw-object.
|
|
||||||
|
|
||||||
```
|
|
||||||
🟢 Mappa alive — 42 wiki / 18 tasks, 12 проектов
|
|
||||||
🟢 Poller running — OpeItcLoc03/skills (🔴 если running:false)
|
|
||||||
🟢 Docker — 8/8 up (иначе только проблемные)
|
|
||||||
📋 Tasks — 23 active / 41 blocked, 17 проектов (назвать 2–3 самых загруженных)
|
|
||||||
```
|
|
||||||
|
|
||||||
Правила на строку:
|
|
||||||
|
|
||||||
- **Mappa** — 🟢/🔴 + admin_status-сводка (счётчики по типам или проектам — кратко). Сервис упал = заголовок.
|
|
||||||
- **Poller** — 🟢/🔴 + running-flag + projects-строка. Остановлен — скажи прямо.
|
|
||||||
- **Docker** — если всё `Up` (вкл. `Up … (healthy)`) — `N/N up`. Иначе только проблемные (`Restarting`, `Exited`, `(unhealthy)`, `Created`, `Paused`) по имени + статусу.
|
|
||||||
- **Tasks** — суммы (Σ active / Σ blocked) + 2–3 проекта с наибольшей активностью. Полный расклад — только по запросу.
|
|
||||||
|
|
||||||
## What NOT to do
|
|
||||||
|
|
||||||
- **НЕ** утверждай «поллер работает» / «все контейнеры up» / «N активных тасок» по памяти или прошлому снапшоту. Зови тулы в текущем turn — liveness требует свежих данных.
|
|
||||||
- **НЕ** падай на `tasklist` / `docker ps` / ручной `meta_status` — это scatter, который скил заменяет. (`docker logs` — только для глубокой диагностики одного контейнера.)
|
|
||||||
- **НЕ** вставляй raw-JSON. Строки, по одной на секцию.
|
|
||||||
- **НЕ** подавай `tasks`-счётчики как точные — они из кэша. При важности точности — флаг сталезности + using-projects-meta.
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
| Mistake | Fix |
|
|
||||||
|---|---|
|
|
||||||
| «Сервис жив» без вызова в этом turn | Зови `meta_health`/`admin_status` — liveness требует текущих данных. |
|
|
||||||
| «Poller up» без вызова | `meta_system_snapshot` в текущем turn. |
|
|
||||||
| `docker ps` / `tasklist` вместо зондов | Один-два вызова тула; в этом смысл. |
|
|
||||||
| Читать снапшот-`docker` как VDS-флот | Это **локальная** машина. VDS — using-vds-ops. |
|
|
||||||
| `tasks`-счётчики как авторитетные | Они кэшированы. Точность — using-projects-meta Step 0 / mappa / `.tasks/`. |
|
|
||||||
| Дампить raw-объект | Сожми в строки (mappa / poller / docker / tasks). |
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
# using-tasks
|
|
||||||
|
|
||||||
Runtime policy for keeping compressed working context across parallel tasks
|
|
||||||
in a monorepo. The agent reads and updates `.tasks/` so every session starts
|
|
||||||
oriented and every switch costs seconds, not minutes.
|
|
||||||
|
|
||||||
`using-tasks` governs the task board. **Канал — mappa** (решение 14/15): борд =
|
|
||||||
сущности `type=task` в сервисе (см. SKILL.md v2.0.0). Файловый `.tasks/` — легаси;
|
|
||||||
`setup-tasks` умер.
|
|
||||||
|
|
||||||
> Renamed from `task-status-wiki` at v1.0.0.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- User is switching between tasks, resuming a paused task, starting a new
|
|
||||||
one, or asks "where were we" / "what's the status".
|
|
||||||
- User says: "use task management system", "pause", "switch to X",
|
|
||||||
"update status".
|
|
||||||
- Any context-switching or multi-task coordination question in a code
|
|
||||||
project.
|
|
||||||
- Борд читается из mappa (`entity_search(type='task', project=…)`);
|
|
||||||
файловый `.tasks/` — легаси, ничего настраивать не нужно.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
<monorepo-root>/
|
|
||||||
└── .tasks/
|
|
||||||
├── STATUS.md ← board: one block per task, sorted by priority
|
|
||||||
└── <task-slug>.md ← deep context per task, one file each
|
|
||||||
```
|
|
||||||
|
|
||||||
Commit `.tasks/` to git — decision history is valuable, diffs show how
|
|
||||||
thinking evolved.
|
|
||||||
|
|
||||||
## STATUS.md format
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Task Board
|
|
||||||
_Updated: YYYY-MM-DD_
|
|
||||||
|
|
||||||
## 🔴 [task-slug] — short description
|
|
||||||
**Status:** active | paused | blocked | done
|
|
||||||
**Where I stopped:** one sentence — the exact thought or action interrupted
|
|
||||||
**Next action:** one concrete step to resume immediately
|
|
||||||
**Blocker:** (only if blocked) what is preventing progress
|
|
||||||
**Branch:** git branch name
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Status legend:
|
|
||||||
|
|
||||||
| Emoji | State | Notes |
|
|
||||||
|---|---|---|
|
|
||||||
| 🔴 | Active | Currently worked on. **Only one at a time.** |
|
|
||||||
| 🟡 | Paused | In progress, resumable. |
|
|
||||||
| ⚪ | Ready | Defined, not started. |
|
|
||||||
| 🟢 | Done | Kept until merged. |
|
|
||||||
| 🔵 | Blocked | Waiting on external input. |
|
|
||||||
|
|
||||||
## Per-task file format (`<task-slug>.md`)
|
|
||||||
|
|
||||||
Sections, in order: **Goal** (one paragraph — what this achieves and why),
|
|
||||||
**Key files** (`path/to/file.ts:42` style — specific lines when relevant),
|
|
||||||
**Decisions log** (reverse-chronological, append-only — past entries are
|
|
||||||
immutable), **Open questions**, **Completed steps**, **Notes** (temporary
|
|
||||||
hypotheses, links).
|
|
||||||
|
|
||||||
## Operations
|
|
||||||
|
|
||||||
### Session start
|
|
||||||
|
|
||||||
1. Check the mappa board: `entity_search(type='task', project=<имя>)`.
|
|
||||||
Файлового `.tasks/STATUS.md` больше нет — setup-tasks умер.
|
|
||||||
2. Read `STATUS.md`.
|
|
||||||
3. If user names a task, read its `<task-slug>.md`.
|
|
||||||
4. Confirm in one sentence: "We're in the middle of X, next step is Y."
|
|
||||||
5. Ask if the plan is still correct before doing anything.
|
|
||||||
6. If `_Updated` is more than 3 days old, flag it and ask the user to
|
|
||||||
confirm current state.
|
|
||||||
|
|
||||||
### Session end / pause / switch
|
|
||||||
|
|
||||||
1. Update `STATUS.md`: set the current task to 🟡, refresh "Where I stopped"
|
|
||||||
and "Next action".
|
|
||||||
2. Append non-obvious decisions to `<task-slug>.md` Decisions log.
|
|
||||||
3. Move finished items to "Completed steps".
|
|
||||||
4. Commit: `git add .tasks/ && git commit -m "chore: update task status [<task-slug>]"`.
|
|
||||||
|
|
||||||
### Task switch
|
|
||||||
|
|
||||||
1. Run session-end ops for the current task.
|
|
||||||
2. Read the target `<task-slug>.md`.
|
|
||||||
3. Set the target to 🔴 in `STATUS.md` (demote previous active to 🟡).
|
|
||||||
4. Confirm orientation before starting work.
|
|
||||||
|
|
||||||
### New task
|
|
||||||
|
|
||||||
1. Ask: slug, goal, known key files, branch.
|
|
||||||
2. Create `<task-slug>.md` with Goal and Key files populated.
|
|
||||||
3. Add a ⚪ block to `STATUS.md`.
|
|
||||||
4. Create / checkout the branch if missing.
|
|
||||||
|
|
||||||
### Task completion
|
|
||||||
|
|
||||||
1. **Pre-close coverage check** — list acceptance criteria, locate
|
|
||||||
evidence (tests, smoke-test artefacts, manual checklist ticks, design
|
|
||||||
doc refs). Missing evidence → ask the user before closing; never auto-close.
|
|
||||||
2. Resolve or drop all open questions.
|
|
||||||
3. Set status to 🟢 in `STATUS.md`.
|
|
||||||
4. Append a final summary line to the Decisions log.
|
|
||||||
5. Remind the user to delete the branch after merge.
|
|
||||||
|
|
||||||
### Post-commit task closure prompt
|
|
||||||
|
|
||||||
After a `feat:` / `fix:` commit the agent prompts:
|
|
||||||
"эта работа закрывает таску `<slug>`?". Slug candidates: commit-message
|
|
||||||
scope, current branch, most recent `Where I stopped`. If yes → run the
|
|
||||||
coverage check above. Skips `chore:` / `meta:` / `docs:` commits.
|
|
||||||
|
|
||||||
Forces a fresh-while-fresh decision, instead of letting shipped code sit
|
|
||||||
under a stale ⚪ block.
|
|
||||||
|
|
||||||
### Recommendations / "what's next" trigger
|
|
||||||
|
|
||||||
When the user asks «что дальше», «срочные», «куда копаем», "what next",
|
|
||||||
"status", or on session-start — recommend in this order:
|
|
||||||
|
|
||||||
1. **Local cwd-project board** ranked 🔴 → 🟡 → ⚪. Cite slugs.
|
|
||||||
2. **One footnote line** if relevant: `Cross-project: N 🔴 in other repos
|
|
||||||
(см. mcp__projects-meta__tasks_aggregate).` Only if N>0 and no local 🔴.
|
|
||||||
|
|
||||||
Explicit "по всем проектам" / "across all projects" flips the order.
|
|
||||||
Pairs with `using-projects-meta`'s local-first rule (which covers reads;
|
|
||||||
this one covers recommendations).
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
|
|
||||||
- **Never lose "Where I stopped".** Most critical field. If unclear, ask
|
|
||||||
before ending the session.
|
|
||||||
- **One sentence per `STATUS.md` field.** Compress, don't write prose.
|
|
||||||
- **Key files must be specific** — not "auth module" but
|
|
||||||
`packages/auth/src/useAuth.ts:87`.
|
|
||||||
- **Decisions log is append-only.** Past entries are immutable.
|
|
||||||
- **Commit after every session end.** `git log` is the history of thinking.
|
|
||||||
- **Always confirm orientation at session start.** State understanding
|
|
||||||
before acting.
|
|
||||||
- **One active task at a time** — only one 🔴 in `STATUS.md`.
|
|
||||||
- **Never close without coverage check.** See "### Task completion"
|
|
||||||
step 1.
|
|
||||||
- **Local-first recommendations.** cwd-project first; cross-project at
|
|
||||||
most one footnote line.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
From the repo root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/install.sh using-tasks
|
|
||||||
```
|
|
||||||
|
|
||||||
Works on Windows under git-bash, Linux, macOS.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- mappa — сервис-хост борда (`task_create`/`task_claim_next`/`task_close`,
|
|
||||||
per-type `t:N`).
|
|
||||||
- [`project-bootstrap`](../project-bootstrap/) — mappa-режим для новых проектов.
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-tasks
|
|
||||||
author: ours
|
|
||||||
version: 2.0.0
|
|
||||||
description: >
|
|
||||||
Policy skill for working with the project task board in Mappa (решения 14/15:
|
|
||||||
мета в сервисе). Use whenever switching between tasks, resuming a paused task,
|
|
||||||
starting a new task, asking «where were we», says «use task management system»,
|
|
||||||
«pause», «switch to X», «what's the status», «update status», or tracking
|
|
||||||
progress across parallel workstreams. Board = сущности `type=task` в mappa
|
|
||||||
(чтение — карв-аут лиза; мутации — под лизом проекта, решение 19). Файловый
|
|
||||||
`.tasks/` — легаси; `setup-tasks` умер (нечего настраивать).
|
|
||||||
---
|
|
||||||
|
|
||||||
# using-tasks
|
|
||||||
|
|
||||||
> Policy для поддержания сжатого рабочего контекста параллельных тасок.
|
|
||||||
> Борд проекта — сущности mappa: каждая таска `t:N` (per-type номер, решение 20)
|
|
||||||
> со статусом `ready|active|paused|blocked|done`, телом, owner'ом и рёбрами
|
|
||||||
> ([[refs]] → parent_of/ref, решения 4/6). Чтение — карв-аут лиза (решение 19);
|
|
||||||
> **любая мутация — под лизом проекта**.
|
|
||||||
|
|
||||||
## MCP-поверхность
|
|
||||||
|
|
||||||
| Операция | Тул | Примечание |
|
|
||||||
|---|---|---|
|
|
||||||
| Взять следующую ready-таску | `mcp__mappa__task_claim_next(project, owner)` | атомарно: лиз + таска; → `{ok, token, task}` |
|
|
||||||
| Продлить лиз | `mcp__mappa__task_heartbeat(project, claim_token)` | долгие таски |
|
|
||||||
| Создать таску | `mcp__mappa__task_create(project, slug, title?, description?, status?, claim_token)` | под лизом |
|
|
||||||
| Закрыть таску | `mcp__mappa__task_close(project, id, claim_token)` | под лизом |
|
|
||||||
| Прочитать таску | `mcp__mappa__entity_get(id)` | id internal из search/claim |
|
|
||||||
| Список борда | `mcp__mappa__entity_search(q, type='task', project=<имя>, limit)` | все статусы |
|
|
||||||
| Дерево parent_of | `mcp__mappa__graph_tree(root, depth?, fields?, limit?)` | зонтики/иерархия (решение 6) |
|
|
||||||
| Связанные сущности | `mcp__mappa__graph_neighbors/backlinks(id)` | рефы к таске |
|
|
||||||
| Уведомление при закрытии | `mcp__mappa__inbox_send(project=<notify>, from=<своя>, subject, body)` | письмо комиссионеру |
|
|
||||||
|
|
||||||
**Лиз = лок на запись (решение 19).** Одна строка leases на проект: если другой
|
|
||||||
агент держит лиз — `task_claim_next` вернёт **422 busy**. Это серверный аналог
|
|
||||||
старого `.tasks/.lock`: проверять «а не поллер ли работает» руками не нужно —
|
|
||||||
сам claim скажет. Чтения лиза не требуют.
|
|
||||||
|
|
||||||
**Рефы и id (#1037).** Таски наружу несут `ref: "t:N"` первым полем, `num`
|
|
||||||
следом, глобальный `id` — internal (последним, для addressing в тулах).
|
|
||||||
Ссылайся на таску `[[t:N]]` (в body → рёбра автоматически), никогда
|
|
||||||
`#<глобальный id>`.
|
|
||||||
|
|
||||||
## Статусы (эмодзи для презентации)
|
|
||||||
|
|
||||||
| Эмодзи | Статус | Значение |
|
|
||||||
|---|---|---|
|
|
||||||
| ⚪ | `ready` | не начата, полностью определена |
|
|
||||||
| 🔴 | `active` | в работе (обычно одна) |
|
|
||||||
| 🟡 | `paused` | в процессе, возобновляема |
|
|
||||||
| 🔵 | `blocked` | ждёт внешнего входа |
|
|
||||||
| 🟢 | `done` | закрыта |
|
|
||||||
|
|
||||||
## Операции агента
|
|
||||||
|
|
||||||
### Ориентация (session start)
|
|
||||||
|
|
||||||
1. **Инбокс-свип** — `mcp__mappa__inbox_monitor(project=<имя>)`: непрочитанные
|
|
||||||
письма могут менять план. Обработай каждое по `inter-session-messaging`.
|
|
||||||
2. **Борд** — `mcp__mappa__entity_search(q='', type='task', project=<имя>, limit=50)`:
|
|
||||||
отсортируй по статусу (🔴 → 🟡 → ⚪), по одной строке на таску, цитируй slug.
|
|
||||||
3. Если user назвал таску — `entity_get(id)` по её рефу/номеру.
|
|
||||||
4. Подтверди одним предложением: «Мы в середине X, следующий шаг — Y».
|
|
||||||
5. Спроси, верен ли план, перед действиями.
|
|
||||||
|
|
||||||
### Переключение / пауза / конец сессии
|
|
||||||
|
|
||||||
1. Текущая 🔴 → `task_close` если завершена (см. закрытие), иначе пометь
|
|
||||||
`status=paused` через update-механику (owner остаётся; «where stopped» —
|
|
||||||
в body или handoff).
|
|
||||||
2. **Инбокс-свип** на границе тасок (`inbox_monitor`).
|
|
||||||
3. Возьми следующую: `task_claim_next` (лиз + таска). Прежняя остаётся 🟡.
|
|
||||||
4. Подтверди ориентацию перед стартом.
|
|
||||||
|
|
||||||
> Примечание про «Where I stopped»: у mappa-таски нет отдельного поля — держи
|
|
||||||
> место остановки в `description` (последний абзац) или, для сессионного
|
|
||||||
> контекста, в **handoff-сущности** (`session-handoff`: summary/open_treks).
|
|
||||||
> Перед концом сессии обязательно запиши handoff — это аналог
|
|
||||||
> «Never lose Where I stopped».
|
|
||||||
|
|
||||||
### Создание таски
|
|
||||||
|
|
||||||
1. **Через тул, не руками** (решение 20): сначала лиз (`task_claim_next`) →
|
|
||||||
`task_create(project, slug, title, description, status='ready', claim_token)`.
|
|
||||||
Номер `t:N` назначает сервер — не выдумывай.
|
|
||||||
2. Slug: kebab-case, латиница. Description: markdown, `[[refs]]` на связанное.
|
|
||||||
3. Закрыть лиз не нужно — экспирится по TTL; мутации идут одним циклом.
|
|
||||||
|
|
||||||
### Закрытие таски
|
|
||||||
|
|
||||||
1. **Pre-close coverage check.** Собери acceptance criteria из description.
|
|
||||||
Для каждого — evidence: тест в диффе, артефакт, ссылка на дизайн.
|
|
||||||
Нет evidence на критерий → спроси user'а «закрывать или подождать coverage'а».
|
|
||||||
2. Resolve/drop открытые вопросы.
|
|
||||||
3. `task_close(project, id, claim_token)` → статус `done`.
|
|
||||||
4. **Notify-письмо (кросс-проектные таски).** Если таска пришла из другого
|
|
||||||
проекта (в description/meta есть `from:`/`notify:`) — `inbox_send`
|
|
||||||
комиссионеру: `project=<notify>`, `subject="[event: closed] <slug>"`,
|
|
||||||
body = итог (сделано, acceptance, ссылки). Живая сессия пишет сама.
|
|
||||||
5. Дополни summary-строку в handoff/вики при наличии.
|
|
||||||
|
|
||||||
### Рекомендации / «что дальше»
|
|
||||||
|
|
||||||
User спросил «что дальше», «status», «куда копаем» — рекомендую в порядке:
|
|
||||||
|
|
||||||
1. **Локальный борд текущего проекта** (cwd): `entity_search(type='task',
|
|
||||||
project=<имя>)` — 🔴 → 🟡 → ⚪, по строке на таску, цитируй slug.
|
|
||||||
2. Одна footnote-строка если кросс-проектно релевантно: `Cross-project: N 🔴
|
|
||||||
active (см. mcp__projects-meta__tasks_aggregate).` Только если N>0 и в cwd
|
|
||||||
нет активной 🔴.
|
|
||||||
|
|
||||||
Кросс-проектные ургенты — информация, не драйвер «что делать здесь».
|
|
||||||
|
|
||||||
## Правила
|
|
||||||
|
|
||||||
- **Лиз-дисциплина.** Мутации — только под лизом; 422 busy = кто-то другой
|
|
||||||
пишет, не параллель.
|
|
||||||
- **Never lose Where I stopped** — критичное поле: в description + handoff.
|
|
||||||
- **Одна активная таска** — только одна 🔴 на проект.
|
|
||||||
- **Не выдумывай номера** — `t:N` назначает сервер.
|
|
||||||
- **Never close без coverage check** — evidence на каждый acceptance criterion,
|
|
||||||
иначе спросить.
|
|
||||||
- **Notify-письмо при закрытии** кросс-проектных тасок — статус 🟢 ≠ комиссионер
|
|
||||||
узнал.
|
|
||||||
- **Чтения — карв-аут.** `entity_search`/`entity_get`/`graph_*` не требуют лиза
|
|
||||||
и не блокируются чужим лизом.
|
|
||||||
- **Локально-первая рекомендация** — борд cwd первым; кросс-проект — футонота.
|
|
||||||
- **Ссылайся `[[t:N]]`**, не глобальным id (#1037).
|
|
||||||
|
|
||||||
## Legacy (переходное)
|
|
||||||
|
|
||||||
Файловый `.tasks/` (STATUS.md + per-task файлы) — легаси-канал, живёт пока
|
|
||||||
миграция/поллер не доедут. Не смешивай: новые таски — через mappa task_create;
|
|
||||||
старые борды читай напрямую (`.tasks/STATUS.md`), если они ещё в файлах.
|
|
||||||
`setup-tasks` умер — файловые борды больше не настраиваются.
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-wiki-graph
|
|
||||||
author: ours
|
|
||||||
version: 1.1.0
|
|
||||||
description: >
|
|
||||||
Use when a question is RELATIONAL about a wiki or any entities in Mappa —
|
|
||||||
«что связывает X и Y», «как связаны», «путь между X и Y», «what connects X
|
|
||||||
and Y», «shortest path» — or about STRUCTURE/HEALTH — «что ссылается на X»,
|
|
||||||
«backlinks of X», «сироты», «битые ссылки», «orphan pages». Triggers
|
|
||||||
`mcp__mappa__graph_neighbors|graph_backlinks|graph_path|graph_stats` —
|
|
||||||
детерминированный BFS по рёбрам графа на стороне сервиса (решение 4/7:
|
|
||||||
[[refs]] в body → рёбра). Guarded failure-mode: на реляционные вопросы агент
|
|
||||||
читает одну страницу и ОСТАНАВЛИВАЕТСЯ, никогда не ходит по многохоповым
|
|
||||||
цепочкам сам. Адресация — internal id (из wiki_get/entity_search); ответы
|
|
||||||
несут per-type refs полными именами (task:N/inbox:N/wiki:N, решение 20/#1037,
|
|
||||||
конвенция #1028). Read-only, без лиза
|
|
||||||
(карв-аут, решение 19). Skip для одно-страничных контентных вопросов.
|
|
||||||
---
|
|
||||||
|
|
||||||
# using-wiki-graph
|
|
||||||
|
|
||||||
Stop and call the graph. On a **relational** or **structural** question about
|
|
||||||
wiki-страницы или любые сущности mappa (таски, письма, сессии), не отвечай,
|
|
||||||
прочитав одну страницу — связи образуют граф, который LLM не обходит надёжно
|
|
||||||
чтением. Сервис ходит по рёбрам детерминированно (BFS) и возвращает ответ в
|
|
||||||
нескольких строках; контекст не засоряется.
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
Вопрос о **связях между сущностями** или **структуре графа**, не о содержании
|
|
||||||
одной страницы:
|
|
||||||
|
|
||||||
- relational — "what connects X and Y", "path between X and Y", «что связывает»,
|
|
||||||
«как связаны», «путь между»;
|
|
||||||
- neighbourhood — "neighbours of X", «соседи X», «что рядом с X»;
|
|
||||||
- incoming — "what links to X", "who references X", «кто ссылается на X»,
|
|
||||||
«backlinks»;
|
|
||||||
- health — "orphan pages", "dangling links", «сироты», «битые ссылки»,
|
|
||||||
«здоровье вики».
|
|
||||||
|
|
||||||
## Precondition — граф реально связан
|
|
||||||
|
|
||||||
Граф полезен, когда рёбра есть. Если сомневаешься — сначала
|
|
||||||
`mcp__mappa__graph_stats()`: `edges` ≈ 0 ⇒ граф пуст, отвечай чтением.
|
|
||||||
(Слаги без [[линков]] рёбер не создают; сироты — норма для разреженных вики.)
|
|
||||||
|
|
||||||
## Адресация: slug → id (internal)
|
|
||||||
|
|
||||||
Тулы graph принимают **internal id** (SQL PK), который наружу помечен internal
|
|
||||||
(решение 20/#1037). Резолв:
|
|
||||||
|
|
||||||
1. `mcp__mappa__wiki_get(project, slug)` (или `entity_search(q, type='wiki')`) —
|
|
||||||
из ответа бери `id` (последнее поле; публичные `ref`/`num` — для показа).
|
|
||||||
2. Передавай `id` в graph-тулы.
|
|
||||||
3. Ответы graph несут `ref` (task:N/inbox:N/wiki:N — полные имена, #1028) на
|
|
||||||
узлах и рёбрах (`from_ref`/`to_ref`) — реферируй по ним в ответе, не по id.
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
1. Выбери тул по форме вопроса:
|
|
||||||
- relational / "what connects" → `mcp__mappa__graph_path({from, to})` —
|
|
||||||
кратчайшая неориентированная цепочка.
|
|
||||||
- neighbourhood → `mcp__mappa__graph_neighbors({id})` — исходящие рёбра
|
|
||||||
узла с резолвом целей (to_ref/kind).
|
|
||||||
- "who links to" → `mcp__mappa__graph_backlinks({id})` — входящие рёбра.
|
|
||||||
- health → `mcp__mappa__graph_stats()` (nodes/edges/components); сирота
|
|
||||||
конкретной страницы = `graph_backlinks(id)` пусто.
|
|
||||||
2. Резолвь id (см. выше), зови graph, отдавай цепочку/список как есть.
|
|
||||||
3. Пустой `path` = связи реально нет — так и скажи; не выдумывай цепочку
|
|
||||||
из текстовой близости.
|
|
||||||
|
|
||||||
## Failure modes
|
|
||||||
|
|
||||||
- Страница удалена/не найдена → graph тул вернёт ошибку. Проверь `wiki_get` —
|
|
||||||
возьми свежий id.
|
|
||||||
- Разреженный граф → `stats` показывает ~0 edges. Не форсируй — читай.
|
|
||||||
- Нет MCP-тулов mappa в сессии → граф недоступен; читай вручную, отметь
|
|
||||||
пользователю, что mappa MCP не подключён.
|
|
||||||
|
|
||||||
## Side effects
|
|
||||||
|
|
||||||
None. Read-only (карв-аут лиза, решение 19): без лиза, без записи, без сети
|
|
||||||
кроме сервиса.
|
|
||||||
|
|
||||||
## What NOT to do
|
|
||||||
|
|
||||||
- Не отвечай на реляционный вопрос чтением одной страницы — это тот самый
|
|
||||||
0%-recall провал, ради которого скил существует.
|
|
||||||
- Не тащи всю вики в контекст, чтобы «проследить» связи руками — сервис делает
|
|
||||||
это за ноль токенов.
|
|
||||||
- Не зови graph на контентные вопросы ("что такое X") — это чтение, не граф.
|
|
||||||
- Не передавай слаги/пути в graph-тулы — только internal id, и только свежие
|
|
||||||
(удалённая сущность → ошибка).
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
# using-wiki
|
|
||||||
|
|
||||||
Runtime policy for an LLM Wiki built on the
|
|
||||||
[Karpathy LLM Wiki pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f).
|
|
||||||
Knowledge is **compiled once and kept current** across three layers, via
|
|
||||||
three named operations, with strict file formats that keep the wiki
|
|
||||||
parseable and grep-friendly.
|
|
||||||
|
|
||||||
`using-wiki` governs *usage* of an existing `.wiki/`. Initial creation and
|
|
||||||
**Канал — mappa** (решение 14/15): вики = сущности `type=wiki` в сервисе
|
|
||||||
(см. SKILL.md v2.0.0). Файловый `.wiki/` — легаси; `setup-wiki` умер.
|
|
||||||
|
|
||||||
> Renamed from `wiki-maintainer` at v1.0.0.
|
|
||||||
|
|
||||||
## When it triggers
|
|
||||||
|
|
||||||
- User says: "use project wiki", "query the wiki", "ingest this", or the
|
|
||||||
Russian equivalents ("обнови вики", "проверь вики", "запроси вики",
|
|
||||||
"заингесть").
|
|
||||||
- Any time the agent modifies a file under `.wiki/` — the workflow and
|
|
||||||
formats below are mandatory.
|
|
||||||
- If `.wiki/` is missing or non-canonical, this skill delegates to
|
|
||||||
вики читается из mappa (`wiki_get`); ничего настраивать не нужно.
|
|
||||||
|
|
||||||
## Three layers (do not blur)
|
|
||||||
|
|
||||||
1. **Raw sources** — `.wiki/raw/` (or external paths registered in
|
|
||||||
`raw/README.md`). **Immutable.** Read, never edit. The only exception is
|
|
||||||
appending a `> Status` blockquote when the user explicitly asks for a
|
|
||||||
status audit.
|
|
||||||
2. **Wiki** — everything else under `.wiki/`. Agent-owned. Entity / concept /
|
|
||||||
package / source summary pages.
|
|
||||||
3. **Schema** — `.wiki/CLAUDE.md`. Project-specific conventions (what
|
|
||||||
entities, what packages, naming). Always read it first; it overrides this
|
|
||||||
skill on conflict.
|
|
||||||
|
|
||||||
## Three operations
|
|
||||||
|
|
||||||
### Ingest
|
|
||||||
|
|
||||||
«заингесть X» — pull a raw source into the wiki.
|
|
||||||
|
|
||||||
1. Read the raw source fully.
|
|
||||||
2. Extract: entities, concepts, packages, cross-cutting patterns.
|
|
||||||
3. Create `sources/<slug>.md` (one summary page per source, ~50–150 lines).
|
|
||||||
4. For each affected entity / concept / package page: update if exists,
|
|
||||||
create if not. Flag contradictions explicitly with
|
|
||||||
`> **Противоречие:** источник A говорит X, источник B — Y`.
|
|
||||||
**Never silently overwrite.**
|
|
||||||
5. Update `index.md`.
|
|
||||||
6. Append one line to `log.md`.
|
|
||||||
7. Report: what was created, updated, contradicted.
|
|
||||||
|
|
||||||
One ingest may touch 10–15 pages. That's normal — that's why an LLM does it.
|
|
||||||
|
|
||||||
### Query
|
|
||||||
|
|
||||||
A question answered from the wiki.
|
|
||||||
|
|
||||||
1. Read `index.md` first, drill into relevant pages.
|
|
||||||
2. Answer with citations as markdown links.
|
|
||||||
3. **Compound the wiki.** If the answer is a real synthesis, ask the user:
|
|
||||||
"Сохранить как страницу wiki?" Good queries become durable pages under
|
|
||||||
`concepts/` or `analyses/`.
|
|
||||||
4. Append one line to `log.md`.
|
|
||||||
|
|
||||||
### Lint
|
|
||||||
|
|
||||||
«проверь wiki» — health check.
|
|
||||||
|
|
||||||
Scan for:
|
|
||||||
|
|
||||||
- Contradictions between pages.
|
|
||||||
- Orphans (pages with no inbound links).
|
|
||||||
- Stale claims (raw source updated after the summary's `ingested:` date —
|
|
||||||
check via `git log -p`).
|
|
||||||
- Concepts mentioned in prose but missing their own page.
|
|
||||||
- Empty / TODO sections.
|
|
||||||
|
|
||||||
Report as a punch list. Don't delete anything automatically. Append one
|
|
||||||
line to `log.md` with the findings.
|
|
||||||
|
|
||||||
## File formats (mandatory)
|
|
||||||
|
|
||||||
### Page frontmatter
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
title: Человекочитаемое имя
|
|
||||||
type: entity | concept | package | source | contradiction | open-question | overview
|
|
||||||
tags: [short, tokens]
|
|
||||||
sources: [../sources/foo.md, ../sources/bar.md]
|
|
||||||
updated: 2026-04-21
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Source pages also carry `ingested: YYYY-MM-DD` and `raw_path: ../raw/...`.
|
|
||||||
Contradiction pages also carry `status: open | resolved | accepted-divergence` and `affects: [../entities/x.md, ../concepts/y.md]`.
|
|
||||||
Open-question pages also carry `status: open | answered | obsolete` and `touches: [../entities/x.md, ../sources/z.md]`.
|
|
||||||
|
|
||||||
### File naming
|
|
||||||
|
|
||||||
- `kebab-case.md`, **Latin only**. Transliterate Cyrillic / non-Latin in
|
|
||||||
filenames; keep the original title in H1 + frontmatter.
|
|
||||||
- `entities/<name>.md`, `concepts/<name>.md`, `packages/<name>.md`
|
|
||||||
(no `@org/` prefix), `sources/<slug>.md`, `contradictions/<slug>.md`,
|
|
||||||
`open-questions/<slug>.md`.
|
|
||||||
|
|
||||||
### `log.md` — append-only, grep-parseable
|
|
||||||
|
|
||||||
Every entry must start with:
|
|
||||||
|
|
||||||
```
|
|
||||||
## [YYYY-MM-DD] <operation> | <short description>
|
|
||||||
```
|
|
||||||
|
|
||||||
Operations: `ingest`, `query`, `lint`, `refactor`, `decision`, `init`.
|
|
||||||
|
|
||||||
Parse with: `grep "^## \[" .wiki/log.md | tail -20`.
|
|
||||||
|
|
||||||
### `index.md`
|
|
||||||
|
|
||||||
Catalog, not narrative. One line per page: `- [Title](path) — hook.`
|
|
||||||
Sections by type. Update on every ingest.
|
|
||||||
|
|
||||||
### Cross-references
|
|
||||||
|
|
||||||
- Wiki → wiki: relative markdown links — `[Name](../entities/x.md)`.
|
|
||||||
- Wiki → code: relative path from repo root — `[foo.js](../../packages/api/foo.js)`.
|
|
||||||
- Wiki → raw: `../raw/<file>`.
|
|
||||||
- URL-encode spaces (`%20`) and Cyrillic when needed.
|
|
||||||
|
|
||||||
## Quick reference
|
|
||||||
|
|
||||||
| Situation | Files touched |
|
|
||||||
|---|---|
|
|
||||||
| Ingest one doc | `sources/<slug>.md` (new) + 3–15 entity/concept/package pages + `index.md` + `log.md` |
|
|
||||||
| Query | (read only) + optionally a new wiki page + `log.md` |
|
|
||||||
| Lint | (read only) + `log.md` |
|
|
||||||
| Новая вики проекта | первый ingest создаёт CLAUDE/index/log через wiki_create |
|
|
||||||
|
|
||||||
## Common mistakes
|
|
||||||
|
|
||||||
- **Editing `raw/`.** Don't. Only allowed change: status blockquote on
|
|
||||||
explicit request.
|
|
||||||
- **Dumping raw content into `sources/`.** Summaries are summaries. Link to
|
|
||||||
raw, don't copy.
|
|
||||||
- **Silent overwrites on contradictions.** Flag them with a `> **Противоречие:**`
|
|
||||||
block.
|
|
||||||
- **Narrative `log.md`.** "Today I added…" is wrong. Use
|
|
||||||
`## [YYYY-MM-DD] ingest | <what>`.
|
|
||||||
- **Non-ASCII filenames.** Breaks greppability and cross-platform. Transliterate.
|
|
||||||
- **Forgetting `index.md`.** Pages not listed there are invisible to future
|
|
||||||
queries.
|
|
||||||
- **Improvising layout when canon files are missing.** Hand off to
|
|
||||||
(setup-wiki умер: канал — mappa, страницы создаются wiki_create).
|
|
||||||
|
|
||||||
## When NOT to use
|
|
||||||
|
|
||||||
- The project has CLAUDE.md / AGENTS.md docs but no `.wiki/` — that's regular
|
|
||||||
documentation, not an LLM Wiki.
|
|
||||||
- The user wants a single-file README or ADR — this skill is for persistent,
|
|
||||||
interlinked knowledge bases.
|
|
||||||
- One-off questions about code — read files directly, no wiki workflow needed.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
From the repo root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash scripts/install.sh using-wiki
|
|
||||||
```
|
|
||||||
|
|
||||||
Works on Windows under git-bash, Linux, macOS.
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
- mappa — сервис-хост вики (`wiki.get`/`wiki.create`/`wiki.update`);
|
|
||||||
canon migration.
|
|
||||||
- [`project-bootstrap`](../project-bootstrap/) — invokes mappa-режим для
|
|
||||||
new projects.
|
|
||||||
- Karpathy's LLM Wiki gist:
|
|
||||||
<https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f>
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
---
|
|
||||||
name: using-wiki
|
|
||||||
author: ours
|
|
||||||
version: 2.2.0
|
|
||||||
description: >
|
|
||||||
Policy skill for working with the project wiki in Mappa (Karpathy LLM Wiki
|
|
||||||
pattern, channel = mappa-сущности, решения 14/15 спеки mappa). Use when the
|
|
||||||
user asks to ingest a document, answer from the wiki, lint/health-check it, or
|
|
||||||
says «use project wiki», «обнови вики», «проверь вики», «запроси вики»,
|
|
||||||
«заингесть», «query the wiki». Also use when modifying any wiki page — the
|
|
||||||
workflow and formats below are mandatory, and project-specific conventions live
|
|
||||||
in the `AGENTS` wiki-сущности проекта (legacy — `CLAUDE`-указатель). Wiki =
|
|
||||||
сущности `type=wiki` в сервисе
|
|
||||||
(чтение — карв-аут лиза; запись — под лизом проекта, решение 19). Файлового
|
|
||||||
`.wiki/` больше нет; `setup-wiki` умер (нечего настраивать).
|
|
||||||
---
|
|
||||||
|
|
||||||
# using-wiki
|
|
||||||
|
|
||||||
> Policy for maintaining an LLM Wiki (Karpathy pattern:
|
|
||||||
> https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) whose pages
|
|
||||||
> live in **Mappa** as `type=wiki` сущности (решение 14/15), not in files.
|
|
||||||
> Knowledge is **compiled once and kept current**: three named operations
|
|
||||||
> (ingest / query / lint), strict page formats that keep the wiki parseable and
|
|
||||||
> grep-friendly, and a cross-linked graph ([[refs]] → рёбра, решение 4).
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
Wiki проекта = сущности в сервисе Mappa (HTTP-ядро, MCP-адаптер `mcp__mappa__*`).
|
|
||||||
Слаг страницы = путь от корня вики без расширения (`index`, `log`, `AGENTS`,
|
|
||||||
`CLAUDE`, `concepts/foo`, `entities/bar`, `packages/baz`, `sources/doc`, `overview`).
|
|
||||||
Body = frontmatter + markdown как есть (content-модель сохраняется, решение 2).
|
|
||||||
|
|
||||||
Проектная вики (scope=project) читается/пишется с параметром проекта;
|
|
||||||
общая вики (scope=shared) — без проекта. Чей именно вики трогаем, определяет
|
|
||||||
контекст: `wiki.get(project, slug)` — проектная, `wiki.get(slug)` — shared.
|
|
||||||
|
|
||||||
Файловый `.wiki/` в репозиториях — легаси: источник истины — сервис.
|
|
||||||
Если вики проекта пуста (нет сущностей) — **ничего настраивать не надо**
|
|
||||||
(setup-wiki умер): первый ingest сам создаёт `AGENTS` (+ `CLAUDE`-указатель);
|
|
||||||
оп-лог вести не нужно — сервис пишет его в таблицу `logs` автоматически
|
|
||||||
(решение 12, ратификация 2026-08-24).
|
|
||||||
|
|
||||||
## MCP-поверхность
|
|
||||||
|
|
||||||
| Операция | Тул | Примечание |
|
|
||||||
|---|---|---|
|
|
||||||
| Чтение страницы | `mcp__mappa__wiki_get(project?, slug)` | чтение — карв-аут лиза (решение 19) |
|
|
||||||
| Поиск страниц | `mcp__mappa__entity_search(q, type='wiki', project?, scope?, limit)` | ILIKE по body/title |
|
|
||||||
| Захват лиза для записи | `mcp__mappa__task_claim_next(project, owner)` | → `token` (лиз проекта, решение 19); таска может отсутствовать |
|
|
||||||
| Продление лиза | `mcp__mappa__task_heartbeat(project, claim_token)` | долгие ingest-циклы |
|
|
||||||
| Создать страницу | `mcp__mappa__wiki_create(project, slug, body, claim_token)` | под лизом |
|
|
||||||
| Обновить страницу | `mcp__mappa__wiki_update(project, id, title?, body?, claim_token)` | под лизом; id — internal (см. ниже) |
|
|
||||||
|
|
||||||
**Запись всегда под лизом.** Мутации wiki гейтятся лизом проекта: без
|
|
||||||
валидного `claim_token` — 422 busy. Лиз экспирится по TTL (дефолт 600s);
|
|
||||||
закрыть вручную нечем (кроме `admin_release_lease` для залипших) — пиши,
|
|
||||||
затем отпусти (не держи лиз на время чтения/размышлений).
|
|
||||||
|
|
||||||
**Рефы и id (#1037/#1028).** Публичная поверхность несёт per-type реф первым полем:
|
|
||||||
`ref: "wiki:3"` (полное имя типа + номер, решение 20, конвенция #1028), `num`
|
|
||||||
следом, глобальный `id` — internal (последним полем). Для `wiki.update` нужен
|
|
||||||
internal `id` — бери его из ответа `wiki_get`/`entity_search`. В тексте страниц
|
|
||||||
ссылайся викилинками по слагу (`[[concepts/foo]]`, решение 4) или per-type
|
|
||||||
рефами полными именами (`[[inbox:N]]`/`[[task:N]]`). В прозе — слаг/имя первым,
|
|
||||||
реф как якорь: «спека `concepts/session-live-ingest` (wiki:2604)».
|
|
||||||
|
|
||||||
## Три слоя (не смешивать)
|
|
||||||
|
|
||||||
1. **Raw-источники** — `sources/<slug>` страницы. Иммутабельны: читай, не
|
|
||||||
редактируй (единственное исключение — блок-цитата `> Status` по явной
|
|
||||||
просьбе пользователя).
|
|
||||||
2. **Вики** — все остальные страницы (entities/concepts/packages/…).
|
|
||||||
3. **Схема** — сущности `AGENTS` (канон, slug `AGENTS`) + `CLAUDE` (legacy-
|
|
||||||
указатель «Canon is AGENTS»). Конвенции проекта. Читай `AGENTS` первой; она
|
|
||||||
перекрывает этот скил при конфликте.
|
|
||||||
|
|
||||||
## Первый шаг любой операции
|
|
||||||
|
|
||||||
1. `mcp__mappa__wiki_get(project, 'AGENTS')` — если есть, читай (канон; если
|
|
||||||
нет — `wiki_get(project, 'CLAUDE')`, легаси-указатель).
|
|
||||||
2. `mcp__mappa__wiki_get(project, 'index')` — каталог, найди нужные страницы.
|
|
||||||
3. Только потом действуй.
|
|
||||||
|
|
||||||
Если `AGENTS`/`CLAUDE` нет — вики либо новая, либо неухоженная: не
|
|
||||||
импровизируй структуру, создай `AGENTS` (+ `CLAUDE`-указатель) при первом
|
|
||||||
ingest (см. ниже). Каталог — через `entity_search` (решение 1); `index`-страница
|
|
||||||
опциональна (для ориентации).
|
|
||||||
|
|
||||||
## Три операции
|
|
||||||
|
|
||||||
### Ingest — «заингесть X»
|
|
||||||
|
|
||||||
1. Прочитай источник полностью.
|
|
||||||
2. Извлеки: entities, concepts, packages, кросс-резы.
|
|
||||||
3. Создай `sources/<slug>` — одну страницу-резюме на источник (~50–150 строк;
|
|
||||||
ссылку на raw клади в frontmatter `raw_path` + `ingested:`).
|
|
||||||
4. Для каждой затронутой страницы:
|
|
||||||
- есть → обнови (`wiki_update(project, id, body, claim_token)`). **Противоречия
|
|
||||||
помечай явно** блоком `> **Противоречие:** источник A говорит X, источник B — Y`.
|
|
||||||
Не затирай молча.
|
|
||||||
- нет → создай (`wiki_create`).
|
|
||||||
5. Обнови `index` (каталог: одна строка на страницу) — опционально; каталог
|
|
||||||
по умолчанию — `entity_search` (решение 1).
|
|
||||||
6. Отчитайся пользователю: что создано, что обновлено, какие противоречия.
|
|
||||||
Первый ingest новой вики: создай `AGENTS` (канон) + `CLAUDE` (указатель).
|
|
||||||
|
|
||||||
**Оп-лог — автоматический.** Каждая write-операция уже пишется сервисом в
|
|
||||||
таблицу `logs` (component=тип сущности, message=slug+operation; смотреть —
|
|
||||||
`mcp__mappa__admin_logs`). Ручную `log`-страницу НЕ веди — это дубль,
|
|
||||||
аудит-след живёт в сервисе (решение 12, ратификация 2026-08-24).
|
|
||||||
|
|
||||||
**Один ingest может затронуть 10–15 страниц. Это нормально — для того LLM и нужны.**
|
|
||||||
|
|
||||||
Порядок записи: сначала лиз (`task_claim_next`), затем все wiki-мутации одним
|
|
||||||
циклом (не бери лиз на чтение), затем отпусти (лиз живёт TTL — просто закончи
|
|
||||||
писать; heartbeat только если цикл реально долгий).
|
|
||||||
|
|
||||||
### Query — вопрос по вики
|
|
||||||
|
|
||||||
1. Читай `index` сначала, затем углубляйся в страницы (`wiki_get` по слагу).
|
|
||||||
2. Отвечай с цитатами-викилинками: `[[concepts/foo]]` (рёбра создаются при
|
|
||||||
записи, решение 4).
|
|
||||||
3. **Компаундируй вики.** Если ответ — реальный синтез (сравнение, анализ,
|
|
||||||
новая связь) — спроси пользователя: «Сохранить как страницу wiki?» Хорошие
|
|
||||||
вопросы становятся страницами в `concepts/`.
|
|
||||||
|
|
||||||
Оп-лог в query — автоматический (logs-таблица); строку вручную не дописывай.
|
|
||||||
|
|
||||||
### Lint — «проверь вики»
|
|
||||||
|
|
||||||
Ищи:
|
|
||||||
- **Противоречия** между страницами.
|
|
||||||
- **Сирот** — страницы без входящих ссылок: `mcp__mappa__graph_backlinks(id)`
|
|
||||||
(id из `wiki_get`) → нет входящих рёбер = сирота (подробнее — using-wiki-graph).
|
|
||||||
- **Stale-claims** — `updated_at` страницы старше источника, который она резюмирует.
|
|
||||||
- **Потерянные сущности** — понятия из текста без своей страницы
|
|
||||||
(`entity_search` по имени → пусто).
|
|
||||||
- **Пустые/TODO-секции.**
|
|
||||||
|
|
||||||
Отчёт — панч-лист. Ничего не удаляй автоматически.
|
|
||||||
Оп-лог в lint — автоматический (logs-таблица); строку вручную не дописывай.
|
|
||||||
|
|
||||||
## Форматы страниц (ОБЯЗАТЕЛЬНО)
|
|
||||||
|
|
||||||
### Frontmatter
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
title: Человекочитаемое имя
|
|
||||||
type: entity | concept | package | source | contradiction | open-question | overview
|
|
||||||
tags: [short, tokens]
|
|
||||||
sources: [concepts/mappa.md]
|
|
||||||
updated: 2026-08-24
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Страницы `sources/` дополнительно несут `ingested: YYYY-MM-DD` и `raw_path: …`.
|
|
||||||
`contradictions/` — `status: open | resolved | accepted-divergence` и `affects:`.
|
|
||||||
`open-questions/` — `status: open | answered | obsolete` и `touches:`.
|
|
||||||
|
|
||||||
### Слаги
|
|
||||||
|
|
||||||
- `kebab-case`, **только латиница**. Кириллицу/др. скрипты транслитерируй
|
|
||||||
(`план переписывания` → `ozon-client-rewrite`). Оригинальный title — в H1 и frontmatter.
|
|
||||||
- `entities/<name>`, `concepts/<name>`, `packages/<name>`, `sources/<slug>`,
|
|
||||||
`contradictions/<slug>`, `open-questions/<slug>`.
|
|
||||||
|
|
||||||
### Оп-лог — таблица `logs`, не страница
|
|
||||||
|
|
||||||
File-based `log.md` мёртв (решение 12/15, ратификация 2026-08-24). Сервис пишет
|
|
||||||
оп-лог сам при каждой write-операции: `mcp__mappa__admin_logs` (фильтры
|
|
||||||
level/since/component/entity, retention 14d). Ручную `log`-страницу не заводи,
|
|
||||||
не дописывай, не парси.
|
|
||||||
|
|
||||||
### `index` — каталог через поиск
|
|
||||||
|
|
||||||
Каталог = `entity_search(q, type='wiki', project)` (решение 1). `index`-страница
|
|
||||||
— опциональная опора для ориентации: одна строка на страницу
|
|
||||||
`- [Title](concepts/foo.md) — hook.`, секции по типам. Обновляй только если
|
|
||||||
страница уже существует; не плоди каталог-дубли.
|
|
||||||
|
|
||||||
## Quick reference
|
|
||||||
|
|
||||||
| Ситуация | Что трогаем |
|
|
||||||
|---|---|
|
|
||||||
| Ingest одного документа | `sources/<slug>` (новая) + 3–15 entities/concepts/packages (+ опционально `index`) |
|
|
||||||
| Query | (чтение) + возможно новая страница |
|
|
||||||
| Lint | (чтение) |
|
|
||||||
| Новая вики проекта | первый ingest создаёт `AGENTS` + `CLAUDE`-указатель; оп-лог — автоматический |
|
|
||||||
|
|
||||||
## Частые ошибки
|
|
||||||
|
|
||||||
- **Правка `sources/`.** Нельзя. Только статус-блок по явной просьбе.
|
|
||||||
- **Дамп сырья в `sources/`.** Резюме — это резюме. Ссылайся на raw, не копируй.
|
|
||||||
- **Молчаливые перезаписи.** Новый источник противоречит странице — пометь
|
|
||||||
блоком `> **Противоречие:**`; не затирай.
|
|
||||||
- **Нарративный оп-лог.** Не веди его руками: сервис пишет logs сам (admin.logs).
|
|
||||||
«Сегодня я добавил…» — даже вручную писать не надо.
|
|
||||||
- **Не-ASCII слаги.** Ломают grep и кросс-платформенность. Транслитерируй.
|
|
||||||
- **Забытый `index`.** Страницы без записи в каталоге невидимы для будущих query
|
|
||||||
(если index-страница ведётся; дефолтный каталог — entity_search).
|
|
||||||
- **Пропущенные противоречия в lint.** Ценность вики — в вскрытых напряжениях,
|
|
||||||
а не в ложном консенсусе.
|
|
||||||
- **Запись без лиза.** Wiki-мутации без `claim_token` → 422 busy; не пытайся
|
|
||||||
писать «напрямую».
|
|
||||||
- **Держать лиз на чтение/раздумья.** Лиз — на время записи. Чтение — карв-аут.
|
|
||||||
|
|
||||||
## Когда НЕ использовать этот скил
|
|
||||||
|
|
||||||
- Проект без вики в mappa (нет сущностей `type=wiki`) — обычная документация,
|
|
||||||
не LLM Wiki.
|
|
||||||
- Пользователь хочет однофайловый README/ADR — скил для персистентной
|
|
||||||
связной базы знаний.
|
|
||||||
- Разовые вопросы по коду — обычное чтение файлов, не вики-воркфлоу.
|
|
||||||
- Реляционные/структурные вопросы о вики (связи, сироты, пути) — это
|
|
||||||
**using-wiki-graph** (`mcp__mappa__graph_*`).
|
|
||||||
@@ -1,432 +0,0 @@
|
|||||||
---
|
|
||||||
name: workshop-promote-brainstorm
|
|
||||||
author: ours
|
|
||||||
version: 1.1.0
|
|
||||||
description: >
|
|
||||||
Finalize a matured brainstorm buffer on the boss's desk
|
|
||||||
(~/projects/.workshop/.brainstorm/): ask routing (workshop-meta → local
|
|
||||||
.wiki/concepts/, domain → target project wiki via knowledge_ingest, skill →
|
|
||||||
claude-skills skeleton), extract action-items into target .tasks, create
|
|
||||||
pointers + review umbrella for impl tasks, archive the buffer.
|
|
||||||
Location-agnostic: fires from ANY folder; all paths resolve to
|
|
||||||
~/projects/.workshop/ regardless of CWD. Triggers (user): «промоутни
|
|
||||||
брейнсторм», «finalize <topic>», «выкати в вики», «promote <topic>».
|
|
||||||
---
|
|
||||||
|
|
||||||
# workshop-promote-brainstorm
|
|
||||||
|
|
||||||
Финализирует созревший брейнсторм-буфер на столе босса (`~/projects/.workshop/`). Три ветки маршрутизации:
|
|
||||||
|
|
||||||
> **Location-agnostic.** Скил триггерится из любой папки — босс-штормы
|
|
||||||
> происходят где угодно, запись живёт на столе. Все относительные пути ниже
|
|
||||||
> (`.brainstorm/`, `.archive/`, `.wiki/`, `index.md`) разрешаются относительно
|
|
||||||
> `~/projects/.workshop/` **независимо от CWD**; git-команды явно указывают
|
|
||||||
> `-C ~/projects/.workshop`.
|
|
||||||
|
|
||||||
- **workshop-meta** → локальный `.wiki/concepts/` (методология самой зоны).
|
|
||||||
- **domain** → глобал через `mcp__projects-meta__knowledge_ingest` в `~/projects/<proj>/.wiki/`.
|
|
||||||
- **skill** → `~/projects/claude-skills/skills/<name>/SKILL.md` (только шапка + пустой каркас тела, локальный коммит без push/install/build-hermes).
|
|
||||||
|
|
||||||
Буфер уезжает в `.archive/`. Action-items уходят тасками в target-проект. **Всегда, при любом маршруте, в воркшоп-вики остаётся summary-страница.**
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
- «промоутни брейнсторм», «finalize <topic>», «выкати в вики», «promote <topic>».
|
|
||||||
- Пользователь явно ссылается на `.workshop/.brainstorm/<topic>.md` как на готовый к промоушену.
|
|
||||||
|
|
||||||
## Inputs
|
|
||||||
|
|
||||||
- Путь `.brainstorm/<topic>.md` или просто `<topic>`.
|
|
||||||
- Для skill-ветки дополнительно: `<name>` нового скила (если не указан — спросить, предложить производное от topic).
|
|
||||||
|
|
||||||
## Decision flow
|
|
||||||
|
|
||||||
```
|
|
||||||
.brainstorm/<topic>.md
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
read + summarize (1–2 paragraphs)
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
ask: workshop-meta or domain or skill?
|
|
||||||
│ │ │
|
|
||||||
│ ▼ ▼
|
|
||||||
│ ask: target proj ask: <name> + check
|
|
||||||
│ │ ~/projects/claude-skills/
|
|
||||||
│ ▼ skills/<name>/ NOT exists
|
|
||||||
│ knowledge_ingest │
|
|
||||||
│ │ ▼
|
|
||||||
│ │ dialog: description (trigger contract)
|
|
||||||
│ │ │
|
|
||||||
│ │ ▼
|
|
||||||
│ │ preview + confirm
|
|
||||||
│ │ │
|
|
||||||
│ │ ▼
|
|
||||||
▼ │ mkdir + Write SKILL.md
|
|
||||||
write to │ (header + empty 6-section skeleton)
|
|
||||||
.wiki/concepts │ │
|
|
||||||
│ │ ▼
|
|
||||||
│ │ git add + commit in claude-skills/
|
|
||||||
│ │ (local, no push, no install.sh, no build-hermes)
|
|
||||||
│ │ │
|
|
||||||
└──────────────┴──────────────┘
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
parse action-items + (for skill: prepend 3 baselines)
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
for each: mcp__projects-meta__tasks_create
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
if domain && N≥1: tasks_create [<topic>-review] (blocked-by impl)
|
|
||||||
if skill: tasks_create [<name>-review] (blocked-by impl, behavioral smoke-test)
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
Write .wiki/concepts/<topic>.md ← ВСЕГДА, любой маршрут
|
|
||||||
(summary: решения, куда промочено, задачи, ссылки)
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
git -C ~/projects/.workshop mv .brainstorm/<topic>.md .archive/<date>-<topic>.md
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
append to .wiki/log.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
1. **Прочитать `.brainstorm/<topic>.md`.** Показать summary (≤2 абзаца).
|
|
||||||
|
|
||||||
2. **Спросить тип:**
|
|
||||||
- **workshop-meta** — методология самой workshop-зоны: ретро дистилляции, паттерны, апгрейды скилов зоны.
|
|
||||||
- **domain** — доменное содержимое для какого-то целевого проекта.
|
|
||||||
- **skill** — методология общего назначения, оформляется как скил в `~/projects/claude-skills/`.
|
|
||||||
|
|
||||||
3. **Если domain:**
|
|
||||||
- Спросить целевой проект (имя папки в `~/projects/`).
|
|
||||||
- Валидация: вызвать `mcp__projects-meta__meta_status`, убедиться что проект известен; иначе — abort с сообщением «зарегистрируй проект через setup-projects-meta».
|
|
||||||
|
|
||||||
4. **Если skill:**
|
|
||||||
- Спросить `<name>` нового скила (если не указан) — валидный slug (`[a-z0-9-]+`).
|
|
||||||
- Валидация: `~/projects/claude-skills/skills/<name>/` НЕ должна существовать. Если существует — **abort** с сообщением «скил `<name>` уже существует, обновляйся обычным маршрутом в `claude-skills/`, этот скил не для апдейтов».
|
|
||||||
- Валидация: `~/projects/claude-skills/` сам репозиторий существует. Если нет — abort с сообщением «клонируй claude-skills/ через update-claude-skills или вручную».
|
|
||||||
|
|
||||||
5. **Парсинг action-items:**
|
|
||||||
- regex по строкам вида `- [ ] ...`, `- [ ]`, секции после `## Следующие шаги`/`## TODO`/`## Next steps`/`## Action items`.
|
|
||||||
- Показать список, дать редактировать/удалять/добавлять.
|
|
||||||
- Если 0 action-items — продолжить, не блокировать.
|
|
||||||
|
|
||||||
6. **Промоушен контента:**
|
|
||||||
|
|
||||||
- **workshop-meta:** `Write` → `.wiki/concepts/<topic>.md` с frontmatter:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
date: <YYYY-MM-DD>
|
|
||||||
source: .brainstorm/<topic>.md
|
|
||||||
status: promoted
|
|
||||||
type: workshop-meta
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Тело — содержимое буфера (можно слегка причесать заголовки, секции типа TODO убрать — они уже сепарированы в action-items).
|
|
||||||
|
|
||||||
- **domain:** `mcp__projects-meta__knowledge_ingest` с параметрами:
|
|
||||||
- `project: <target>`
|
|
||||||
- `path: concepts/<topic>.md` (внутри target wiki)
|
|
||||||
- `content: <тело буфера с frontmatter>`
|
|
||||||
|
|
||||||
Если `knowledge_ingest` падает → abort до tasks_create и до `git mv`. Сообщить пользователю.
|
|
||||||
|
|
||||||
- **skill:** двухпроходной.
|
|
||||||
|
|
||||||
**Проход первый (этот скил):**
|
|
||||||
|
|
||||||
1. **Диалог по `description`** — поведенческий контракт активации скила. Показать пользователю summary буфера и спросить:
|
|
||||||
- На каких триггер-фразах скил должен активироваться? (минимум 2-3, лучше — пары русский/английский)
|
|
||||||
- Что скил делает в одном предложении?
|
|
||||||
- Когда скил **не должен** активироваться (антипаттерны)?
|
|
||||||
|
|
||||||
Из ответов собрать `description` строкой ~200-400 символов в стиле существующих скилов (см. `~/projects/claude-skills/skills/*/SKILL.md` для примеров).
|
|
||||||
|
|
||||||
2. **Preview + confirm** (обязательно):
|
|
||||||
```
|
|
||||||
Писать в: ~/projects/claude-skills/skills/<name>/SKILL.md
|
|
||||||
Frontmatter: name=<name>, version=0.1.0, description=<...>
|
|
||||||
Body: пустой каркас с заголовками
|
|
||||||
When to use / Inputs / Steps / Failure modes / Side effects / What NOT to do
|
|
||||||
Коммит: feat(skills): add <name> v0.1.0 (promoted from .workshop/.brainstorm/<topic>.md)
|
|
||||||
Без: install.sh, push, build-hermes (это в созданных тасках)
|
|
||||||
ОК?
|
|
||||||
```
|
|
||||||
|
|
||||||
3. После confirm:
|
|
||||||
- `mkdir -p ~/projects/claude-skills/skills/<name>/`
|
|
||||||
- `Write` файла `~/projects/claude-skills/skills/<name>/SKILL.md`:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
name: <name>
|
|
||||||
version: 0.1.0
|
|
||||||
description: <вписанный пользователем триггер-контракт>
|
|
||||||
---
|
|
||||||
|
|
||||||
# <name>
|
|
||||||
|
|
||||||
<одно-два предложения что скил делает — из диалога>
|
|
||||||
|
|
||||||
## When to use
|
|
||||||
|
|
||||||
<пусто, дописывается во втором проходе>
|
|
||||||
|
|
||||||
## Inputs
|
|
||||||
|
|
||||||
<пусто>
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
<пусто>
|
|
||||||
|
|
||||||
## Failure modes
|
|
||||||
|
|
||||||
<пусто>
|
|
||||||
|
|
||||||
## Side effects
|
|
||||||
|
|
||||||
<пусто>
|
|
||||||
|
|
||||||
## What NOT to do
|
|
||||||
|
|
||||||
<пусто>
|
|
||||||
```
|
|
||||||
|
|
||||||
- В `~/projects/claude-skills/`: `git -C ~/projects/claude-skills add skills/<name>/SKILL.md && git -C ~/projects/claude-skills commit -m "feat(skills): add <name> v0.1.0 (promoted from ~/projects/.workshop/.brainstorm/<topic>.md)"`.
|
|
||||||
- **STOP.** Не запускать `install.sh`. Не делать `git push`. Не править `hermes/mapping.yaml`. Это всё уйдёт тасками на шаге 7.
|
|
||||||
|
|
||||||
**Проход второй** — пользователь явно зовёт «доведём `<name>`» в этой же или следующей сессии. Источник лежит в `.archive/<date>-<topic>.md`, тело каркаса дописывается глазами. Вне scope этого скила.
|
|
||||||
|
|
||||||
7. **Создание тасок:**
|
|
||||||
|
|
||||||
- **domain (mandatory pre-impl) — `[<topic>-pointers]`:** **первой** создать таску, заполняющую `.wiki/CLAUDE.md` Domain conventions у target-проекта пойнтерами на спецификацию. Без неё импл-таски будут подняты со stub'ом в Domain conventions, и следующий агент попадёт в дыру: dense `where_stopped` one-liner + пустой stub = угадывание порогов / таксономий / pipeline-этапов. Параметры:
|
|
||||||
|
|
||||||
- `target_project: <target>`
|
|
||||||
- `slug: <topic>-pointers`
|
|
||||||
- `status: ready`
|
|
||||||
- `description:` шаблон ниже
|
|
||||||
- `next_action:` готовый блок текста для копирования в `.wiki/CLAUDE.md` (шаблон ниже)
|
|
||||||
|
|
||||||
Description-шаблон:
|
|
||||||
|
|
||||||
```
|
|
||||||
Bootstrap-pointers для design <topic>. Pre-fills target's `.wiki/CLAUDE.md`
|
|
||||||
Domain conventions ссылками на спецификацию. Дизайн не лежит в этом репо —
|
|
||||||
только pointer-stub. Без этой таски следующий агент попадёт в дыру:
|
|
||||||
where_stopped one-liner + пустой Domain conventions stub = угадывание
|
|
||||||
порогов / таксономий / pipeline-этапов вместо чтения готовых решений.
|
|
||||||
|
|
||||||
**Кто делает:** любой следующий агент в этом проекте. Это первая по
|
|
||||||
приоритету таска промоушена — все остальные импл-таски ссылаются на
|
|
||||||
pointers через .wiki/CLAUDE.md.
|
|
||||||
```
|
|
||||||
|
|
||||||
Next-action шаблон (pre-filled, копировать дословно — подменив `<topic>` и `<YYYY-MM-DD>`):
|
|
||||||
|
|
||||||
```
|
|
||||||
В `.wiki/CLAUDE.md` секции "Domain conventions" вставить блок (или заменить
|
|
||||||
дефолтный setup-wiki stub):
|
|
||||||
|
|
||||||
### Mandatory: read design context before implementation
|
|
||||||
|
|
||||||
Before picking up any task in `.tasks/`, load the full design context. It
|
|
||||||
does **not** live in this repo — only pointers do. Sources, in order:
|
|
||||||
|
|
||||||
1. **Global wiki design (canonical):** `mcp__projects-meta__knowledge_get`
|
|
||||||
с `slug = "concepts/<topic>"`. Architecture decisions, contracts, scope.
|
|
||||||
2. **Brainstorm process trace (rationale):**
|
|
||||||
`~/projects/.workshop/.archive/<YYYY-MM-DD>-<topic>.md`.
|
|
||||||
Why each decision was made, what was rejected and why, anti-patterns.
|
|
||||||
3. **Local `overview.md`** — thin summary of (1), used as quick orientation
|
|
||||||
only — never as the source of truth.
|
|
||||||
|
|
||||||
Do **not** invent thresholds, taxonomies, container topology, or pipeline
|
|
||||||
stages from task `where_stopped` lines alone — those are pointers, not
|
|
||||||
specifications.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Закоммитить: `wiki(claude): add design-context pointers for <topic>`.
|
|
||||||
```
|
|
||||||
|
|
||||||
Конкретные значения, которые промоутер должен подставить **заранее** в
|
|
||||||
текст next_action перед `tasks_create`:
|
|
||||||
|
|
||||||
- `<topic>` — тема промоушена (тот же slug, что используется в `concepts/<topic>.md` и в `.archive/<YYYY-MM-DD>-<topic>.md`).
|
|
||||||
- `<YYYY-MM-DD>` — сегодняшняя дата (та же, что в шаге 9 архивации).
|
|
||||||
|
|
||||||
Если `tasks_create` для `<topic>-pointers` упала → **abort** до content-тасок и до review. Без pointers оставшиеся таски бесполезны: импл-агент будет угадывать. Сообщить пользователю, буфер оставить на месте.
|
|
||||||
|
|
||||||
- **workshop-meta / domain (content):** для каждого action-item:
|
|
||||||
- `mcp__projects-meta__tasks_create` с `project: <target>` (для domain) или с `project: <inferred>` (для workshop-meta — спросить пользователя если неоднозначно).
|
|
||||||
- Title — первая строка action-item; description — остальное.
|
|
||||||
|
|
||||||
- **skill:** **всегда** добавляются три baseline-таски в `project: claude-skills`:
|
|
||||||
- `[<name>-install]` — запустить `install.sh` в `~/projects/claude-skills/`, проверить что скил активируется в новой сессии, сделать `/reload-plugins`.
|
|
||||||
- `[<name>-hermes-mapping]` — добавить запись в `~/projects/claude-skills/hermes/mapping.yaml`. Режим: `auto` если скил чисто стилевой / response-style, `pending` если скил трогает инструменты или окружение (требует отдельного аудита).
|
|
||||||
- `[<name>-test-trigger]` — прогнать триггер-фразы из `description` на тестовом буфере: убедиться что активируется на своих фразах И не активируется на 2-3 близких чужих (false-positive check).
|
|
||||||
|
|
||||||
Плюс content-таски из самого буфера (если были) — также в `project: claude-skills`, slug-prefix `<name>-`.
|
|
||||||
|
|
||||||
- Если N-я таска упала — продолжить остальные, в конце сообщить какие созданы / какие нет.
|
|
||||||
- Запомнить slug'и созданных импл-тасок для шага 8.
|
|
||||||
|
|
||||||
8. **Review-чекпоинт.** Создаётся всегда для skill-промоушена; для domain-промоушена — только если N≥1 импл-тасок; для workshop-meta или N=0 (domain) — skip с пометкой в логе.
|
|
||||||
|
|
||||||
- **domain (N≥1):**
|
|
||||||
- `mcp__projects-meta__tasks_create`:
|
|
||||||
- `target_project: <target>`
|
|
||||||
- `slug: <topic>-review`
|
|
||||||
- `status: blocked`
|
|
||||||
- `blocker:` `«bootstrap: <topic>-pointers; impl-tasks: <номера #n через запятую>»` — блокеры по номерам (номер = машинный ключ; слаги оставить в скобках для читаемости).
|
|
||||||
- `description:` шаблон ниже.
|
|
||||||
- `next_action:` «Дождаться 🟢 у всех blocker-тасок (включая `<topic>-pointers` — без него pointers в `.wiki/CLAUDE.md` не залиты, и review будет читать stub). Прочитать спецификацию (см. путь в description). Для каждой импл-таски: `git show <commit>`, прогнать тесты в её scope'е, сверить с acceptance criteria. Findings → новые follow-up tasks через `mcp__projects-meta__tasks_create`.»
|
|
||||||
|
|
||||||
Description-шаблон (domain):
|
|
||||||
|
|
||||||
```
|
|
||||||
Code-review checkpoint для брейнсторма <topic> (промоушен <YYYY-MM-DD>).
|
|
||||||
|
|
||||||
**Спецификация:** <путь к промоушенному design-документу — concepts/<topic>.md в target-wiki>.
|
|
||||||
**Pre-impl bootstrap:** `<topic>-pointers` (заполнил `.wiki/CLAUDE.md` Domain conventions — без него review бы читал stub).
|
|
||||||
**Импл-таски (review против их acceptance criteria):** <номера #n из шага 7, слаги в скобках>.
|
|
||||||
|
|
||||||
**Кто делает:** **не имплементер.** Следующая сессия в этом проекте (другая модель / другой день / другой агент) поднимает таску с чистым контекстом. «Я только что это написал» bias = главный риск.
|
|
||||||
|
|
||||||
**Чек-лист ревью:**
|
|
||||||
- Прочитать спецификацию (acceptance criteria каждой импл-таски).
|
|
||||||
- `git log --oneline` shipped-коммитов (по slug или scope в commit-message).
|
|
||||||
- Для каждой импл-таски: прогнать соответствующие тесты, реально проверить что они доходят до своих веток (не coverage-illusion).
|
|
||||||
- Сверить дизайн-decisions со shipped-кодом (signature, params, error-paths, безопасность).
|
|
||||||
- Findings — отдельные follow-up tasks (`<topic>-<gap>-fix` или подобное) через `tasks_create`.
|
|
||||||
|
|
||||||
**Закрытие:** только когда все findings зафайлены ИЛИ ревьюер подтвердил «нет findings» в close-note.
|
|
||||||
```
|
|
||||||
|
|
||||||
- **skill:**
|
|
||||||
- `mcp__projects-meta__tasks_create`:
|
|
||||||
- `target_project: claude-skills`
|
|
||||||
- `slug: <name>-review`
|
|
||||||
- `status: blocked`
|
|
||||||
- `blocker:` `«impl-tasks: <name>-install, <name>-hermes-mapping, <name>-test-trigger[, content-impls если были]»` — номера `#n` из шага 7 (слаги в скобках для читаемости).
|
|
||||||
- `description:` шаблон ниже.
|
|
||||||
- `next_action:` «Дождаться 🟢 у baseline-тасок. Прогнать поведенческий smoke-test (см. чек-лист в description). Findings → follow-up tasks через `tasks_create`.»
|
|
||||||
|
|
||||||
Description-шаблон (skill):
|
|
||||||
|
|
||||||
```
|
|
||||||
Skill-review checkpoint для <name> (промоушен <YYYY-MM-DD>).
|
|
||||||
|
|
||||||
**Источник дизайна:** .workshop/.archive/<YYYY-MM-DD>-<topic>.md.
|
|
||||||
**Импл-таски:** <name>-install, <name>-hermes-mapping, <name>-test-trigger[, content-impls] — номера #n из шага 7.
|
|
||||||
|
|
||||||
**Кто делает:** **не имплементер.** Другая сессия / другой день / другой агент. Identity-not-location: ревьюер работает в любой папке, где есть доступ к файлам (см. `.workshop/.wiki/concepts/workshop-architecture.md` §5.1).
|
|
||||||
|
|
||||||
**Поведенческий smoke-test (это и есть acceptance):**
|
|
||||||
- Скил активируется в чистой сессии на каждой триггер-фразе из `description` (русский И английский варианты).
|
|
||||||
- Скил **не** активируется на 2-3 близких но не своих фразах из соседних доменов (false-positive check).
|
|
||||||
- Каждый шаг секции `Steps` отрабатывает на тестовом буфере без ошибок.
|
|
||||||
- `Failure modes` уводят в abort, не в частичный успех с грязным состоянием.
|
|
||||||
- `What NOT to do` соответствует реальности — нет дыры между правилом и реализацией.
|
|
||||||
|
|
||||||
Findings — обычные follow-up tasks (`<name>-<gap>-fix` или подобное) через `tasks_create` в `claude-skills`.
|
|
||||||
|
|
||||||
**Закрытие:** только когда все findings зафайлены ИЛИ ревьюер подтвердил «нет findings» в close-note.
|
|
||||||
|
|
||||||
**NB по семверу:** `version: 0.1.0` записан промоутером. Дальнейшие инкременты — ответственность владельца `claude-skills/`, **не** этого скила и не ревьюера. Если ревью требует правок — правит владелец, бампит он же.
|
|
||||||
```
|
|
||||||
|
|
||||||
- Если `tasks_create` review-таски упала — сообщить пользователю, **продолжить** к шагу 9 (архивация буфера). Review-таску можно создать вручную позже из `.archive/<date>-<topic>.md`.
|
|
||||||
|
|
||||||
9. **Workshop-wiki summary (обязательно для всех маршрутов):**
|
|
||||||
|
|
||||||
`Write` → `.wiki/concepts/<topic>.md` с frontmatter:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
date: <YYYY-MM-DD>
|
|
||||||
source: .brainstorm/<topic>.md → .archive/<YYYY-MM-DD>-<topic>.md
|
|
||||||
status: promoted
|
|
||||||
type: workshop-meta
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Содержание (≤60 строк):
|
|
||||||
- **Что решили** — ключевые решения раундов (не пересказ, а outcomes).
|
|
||||||
- **Куда промочено** — полный путь: target-wiki / claude-skills / local concepts.
|
|
||||||
- **Задачи** — перечень slug'ов, созданных в шаге 7.
|
|
||||||
- **Ссылки** — архив буфера + связанные концепты в workshop-вики + глобальная вики.
|
|
||||||
|
|
||||||
Для **workshop-meta**: summary — сокращение полного контента (который уже в `.wiki/concepts/<topic>.md` шага 6); если шаг 6 уже записал туда полный файл — шаг 9 его дополняет секцией «Куда промочено / Задачи» или пропускается (не дублировать).
|
|
||||||
|
|
||||||
Затем обновить `index.md` — добавить строку в нужную секцию.
|
|
||||||
|
|
||||||
Если `Write` упал → сообщить, **не блокировать** архивацию (summary менее критична чем content-промоушен).
|
|
||||||
|
|
||||||
10. **Архивация:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git -C ~/projects/.workshop mv .brainstorm/<topic>.md .archive/<YYYY-MM-DD>-<topic>.md
|
|
||||||
```
|
|
||||||
|
|
||||||
**Только** если шаги 6 и 7 прошли (или прошли с допустимым partial — пользователь подтвердил). Иначе — оставить буфер на месте, чтобы можно было ретраиить.
|
|
||||||
|
|
||||||
11. **Лог:** дописать в `.wiki/log.md`:
|
|
||||||
|
|
||||||
```
|
|
||||||
<date> promoted <topic> → <destination> [created N tasks in <proj>]
|
|
||||||
```
|
|
||||||
|
|
||||||
Для skill — `<destination>` = `claude-skills/skills/<name>/SKILL.md (skeleton)`.
|
|
||||||
|
|
||||||
12. **Финальный отчёт пользователю:**
|
|
||||||
- Куда промочено (полный путь).
|
|
||||||
- Какие таски созданы (id, title, проект).
|
|
||||||
- Куда уехал исходник.
|
|
||||||
- **Для skill:** напомнить что нужен второй проход «доведём `<name>`» для дописывания тела каркаса.
|
|
||||||
|
|
||||||
## Failure modes
|
|
||||||
|
|
||||||
- `.brainstorm/<topic>.md` отсутствует → abort.
|
|
||||||
- `mcp__projects-meta` недоступен → abort до записей.
|
|
||||||
- Целевой проект (для domain) не найден в `meta_status` → abort.
|
|
||||||
- `knowledge_ingest` упал → abort до `tasks_create` и `git mv`. Буфер остаётся.
|
|
||||||
- **domain:** `tasks_create` для `[<topic>-pointers]` упал → **abort** до content-тасок и до review-таски. Без pointers оставшиеся таски бесполезны (агент будет угадывать). Сообщить пользователю; буфер оставить на месте для retry.
|
|
||||||
- `tasks_create` упал на N-й content-таске → продолжить остальные. Сообщить partial. **Не делать** `git mv` без подтверждения пользователя.
|
|
||||||
- `tasks_create` упал на review-таске (шаг 8) → не блокировать; перейти к архивации, сообщить пользователю чтобы создал вручную из `.archive/`.
|
|
||||||
- **Skill:** `~/projects/claude-skills/` не существует → abort с сообщением «клонируй через update-claude-skills или вручную».
|
|
||||||
- **Skill:** `~/projects/claude-skills/skills/<name>/` уже существует → abort с сообщением «скил уже существует, обновляйся обычным маршрутом в `claude-skills/`».
|
|
||||||
- **Skill:** пользователь не подтвердил preview перед записью → abort, состояние не меняется.
|
|
||||||
- **Skill:** локальный `git commit` в `claude-skills/` упал (например, не настроен user.email) → файл остаётся, сообщить пользователю что коммит нужно сделать руками; **не** делать `git mv` буфера до подтверждения.
|
|
||||||
|
|
||||||
## Side effects
|
|
||||||
|
|
||||||
- **Всегда (любой маршрут):** создаёт summary-страницу `.wiki/concepts/<topic>.md` в `.workshop/` + добавляет строку в `index.md`.
|
|
||||||
- **workshop-meta:** summary IS контент (шаг 6 записывает полное тело; шаг 9 дополняет секцию «задачи/ссылки» или пропускается если уже полный).
|
|
||||||
- **domain:** создаёт запись в target-wiki через MCP (`mcp__projects-meta__knowledge_ingest`).
|
|
||||||
- **domain:** создаёт также **mandatory pre-impl** таску `[<topic>-pointers]` в target — pre-filled блок текста для `.wiki/CLAUDE.md` Domain conventions (ссылки на global wiki slug + workshop archive trace + local overview.md). Без неё последующий импл-агент попадает в дыру: where_stopped one-liner + пустой Domain conventions stub.
|
|
||||||
- **skill:** создаёт `~/projects/claude-skills/skills/<name>/SKILL.md` — **только шапка + пустой каркас**. Локальный коммит в `claude-skills/`. **Без** установки, push, или build-hermes — это всё в созданных baseline-тасках.
|
|
||||||
- Создаёт N тасок в target `.tasks/` через MCP.
|
|
||||||
- Для domain (N≥1) или skill: создаёт зонтичную review-таску (status=blocked, blocker=impl-slugs; для domain — также включает `<topic>-pointers`) в том же target.
|
|
||||||
- Перемещает `.brainstorm/<topic>.md` → `.archive/<date>-<topic>.md`.
|
|
||||||
- Аппендит строку в `.wiki/log.md`.
|
|
||||||
- **Семвер скилов:** при target=skill промоутер записывает `version: 0.1.0` в шапку. Дальнейшие инкременты — ответственность владельца `claude-skills/`, **не** этого скила. При попытке промоушена в существующий скил — abort (см. Failure modes).
|
|
||||||
|
|
||||||
## What NOT to do
|
|
||||||
|
|
||||||
- Не писать доменное содержимое в локальный `.wiki/concepts/` (правило #1 из `.workshop/CLAUDE.md`). Summary-страница шага 9 — это trace/навигация, не domain-контент.
|
|
||||||
- Не пропускать шаг 9 (workshop-wiki summary) — именно так следующая сессия узнаёт что буфер был и куда ушёл.
|
|
||||||
- Не делать `git mv` буфера до успеха promotion+tasks.
|
|
||||||
- Не удалять буфер вместо `git mv` — теряется история.
|
|
||||||
- **Skill:** не пытаться автоматически переформатировать тело буфера в каркас `Steps`/`Failure modes`/etc. — это поведенческий контракт, не косметика. Каркас остаётся пустым; тело дописывается во втором проходе глазами.
|
|
||||||
- **Skill:** не запускать `install.sh`. Не делать `git push` в `claude-skills/`. Не править `hermes/mapping.yaml`. Не запускать `build-hermes.py`. Это работа baseline-тасок, не промоутера.
|
|
||||||
- **Skill:** не бампить `version` после первой записи (это работа владельца `claude-skills/`).
|
|
||||||
- **Skill:** не промоутить в существующий скил (см. Failure modes — abort).
|
|
||||||
- **Skill:** не пропускать обязательный preview + confirm перед `Write` — действие выходит за пределы мастерской, изменяет соседний репозиторий.
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: writing-skills
|
name: writing-skills
|
||||||
adapted-from: obra/superpowers @ 6.2.0 (MIT) — TDD-for-skills core; ideya 8 self-skill-authoring (workshop record)
|
adapted-from: obra/superpowers @ 6.2.0 (MIT) — TDD-for-skills core; ideya 8 self-skill-authoring (workshop record)
|
||||||
version: 0.1.1
|
version: 0.2.0
|
||||||
description: >
|
description: >
|
||||||
Authoring agent skills TDD-style — RED-GREEN-REFACTOR applied to SKILL.md
|
Authoring agent skills TDD-style — RED-GREEN-REFACTOR applied to SKILL.md
|
||||||
documents. Use when creating a new skill, editing an existing one, or
|
documents. Use when creating a new skill, editing an existing one, or
|
||||||
@@ -89,9 +89,21 @@ content for hypothetical cases.
|
|||||||
### Skill structure (our catalog conventions)
|
### Skill structure (our catalog conventions)
|
||||||
|
|
||||||
```
|
```
|
||||||
skills/<name>/SKILL.md
|
skills/<name>/SKILL.md # общий каталог (catalog, версионируется, ставится install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Куда класть скил — определи ДО написания (три варианта, не путать):**
|
||||||
|
|
||||||
|
| Тип скила | Место | Когда |
|
||||||
|
|---|---|---|
|
||||||
|
| Общий каталог | `~/projects/skills/skills/<name>/SKILL.md` + deploy (lint/build/install) | полезен всем проектам/агентам |
|
||||||
|
| **Проектный (зона проекта)** | `<project>/.agents/skills/<name>/SKILL.md` (pi грузит из cwd; Claude Code: `.claude/skills/`) | привязан к одному проекту/роли (пример: `.admin` ops-скилы, `books/.agents/skills/`) |
|
||||||
|
| ~~Глобальная установка руками~~ | ~~`~/.agents/skills/`~~ | **НЕ сюда** — это установочная копия (перезапишется update-skills), не место разработки |
|
||||||
|
|
||||||
|
Правило: если скил про зону одного проекта (admin, books, …) — проектный путь
|
||||||
|
(`.agents/skills/` в cwd проекта), НЕ общий каталог и НЕ `~/.agents/skills/`.
|
||||||
|
Если скил общий — каталог `skills/` + deploy-цикл. При сомнении — спросить.
|
||||||
|
|
||||||
Frontmatter (YAML):
|
Frontmatter (YAML):
|
||||||
|
|
||||||
- `name` — letters, numbers, hyphens only. Verb-first, active voice:
|
- `name` — letters, numbers, hyphens only. Verb-first, active voice:
|
||||||
@@ -158,6 +170,8 @@ discipline skills.
|
|||||||
- [ ] Description = when to use only, no workflow summary
|
- [ ] Description = when to use only, no workflow summary
|
||||||
- [ ] Frontmatter: name (verb-first, hyphens), description (triggers), version
|
- [ ] Frontmatter: name (verb-first, hyphens), description (triggers), version
|
||||||
(bumped), provenance (author/adapted-from with real pin)
|
(bumped), provenance (author/adapted-from with real pin)
|
||||||
|
- [ ] Placement decided: project skill → `<project>/.agents/skills/` (cwd), NOT
|
||||||
|
`~/.agents/skills/`; catalog skill → `skills/<name>/` + deploy cycle
|
||||||
- [ ] Lint passes (catalog: `scripts/lint-skills.py`), dist rebuilt
|
- [ ] Lint passes (catalog: `scripts/lint-skills.py`), dist rebuilt
|
||||||
(`scripts/build.sh`), installed (`scripts/install.sh <name>`)
|
(`scripts/build.sh`), installed (`scripts/install.sh <name>`)
|
||||||
- [ ] README provenance table updated (catalog)
|
- [ ] README provenance table updated (catalog)
|
||||||
|
|||||||
Reference in New Issue
Block a user