feat(mappa-knowledge): merge using-wiki + using-wiki-graph → mappa-knowledge v1.0.0 (cycle ingest/query/lint + graph layer, guarded failure-mode, old names = trigger synonyms) [skip-tdd: visual]

This commit is contained in:
2026-08-24 22:42:45 +03:00
parent fe8484bb2b
commit b9c13a0aaf
5 changed files with 271 additions and 493 deletions

View File

@@ -17,4 +17,14 @@ Relational/структурные вопросы (связи, backlinks, сир
## 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
- RED-базис: триггер-поверхность унаследована из using-wiki/using-wiki-graph (прошли ревью); дельта = слияние + цикл-фрейминг + guarded failure-mode графа. Полный behavioral smoke — за #1065.
- Побочная lint-находка GREEN-теста: рефы в прозе (не [[викилинки]]) рёбер не дают → спека может быть сиротой, «таска↔спека» в графе теряется. Это известная семантика решения 4 (рёбра только из [[refs]]), не баг скила — отмечено как наблюдение, кандидат в follow-up, если понадобится проставлять [[викилинки]] при создании тасок-промоушена.

View File

@@ -0,0 +1,261 @@
---
name: mappa-knowledge
author: ours
version: 1.0.0
description: >
Цикл работы со знаниями проекта в Mappa (Karpathy LLM Wiki, канал =
mappa-сущности): ingest → query → lint + граф-слой для
реляционных/структурных вопросов. Поглощает using-wiki + using-wiki-graph
(старые имена — триггер-синонимы). Триггеры: «заингесть», «обнови вики»,
«запроси вики», «проверь вики», «use project wiki», «query the wiki»,
«что связывает X и Y», «как связаны», «путь между X и Y», «what connects
X and Y», «что ссылается на X», «backlinks of X», «сироты», «битые ссылки»,
«orphan pages». Wiki = сущности type=wiki (чтение — карв-аут лиза; запись —
под лизом проекта, решение 19). Реляционные вопросы — через graph_* (BFS на
стороне сервиса), guarded failure-mode: одна страница и стоп, без
многохоповых цепочек чтением. Skip для одно-страничных контентных вопросов.
---
# mappa-knowledge
Единый цикл работы со знаниями проекта в **Mappa**: три операции (ingest /
query / lint) + **граф-слой** для реляционных и структурных вопросов. Скилл =
цикл, не тул: знание **компилируется один раз и держится актуальным**
(ingest), к нему обращаются (query), его проверяют (lint), а связи между
сущностями читают через граф (graph_*).
Канал — Mappa (`mcp__mappa__*`), НЕ файлы. Страница — сущность `type=wiki`
(`wiki:N`); чтение — карв-аут лиза, запись — под лизом проекта (решение 19).
Файлового `.wiki/` больше нет; `setup-wiki` умер (нечего настраивать).
## Когда использовать
- Заингестить документ/источник в вики («заингесть X», «обнови вики»).
- Ответить из вики / проверить вики («запроси вики», «проверь вики», lint).
- Реляционный/структурный вопрос («что связывает X и Y», «backlinks», «сироты») — граф-слой.
- Модифицировать любую страницу — форматы ниже обязательны; конвенции проекта
живут в `AGENTS`-сущности (legacy — `CLAUDE`-указатель).
**НЕ для:** разовых вопросов по коду (обычное чтение файлов), однофайловых
README/ADR (не персистентная база знаний), проекта без вики в mappa.
## Три слоя (не смешивать)
1. **Raw-источники**`sources/<slug>` страницы. Иммутабельны: читай, не
редактируй (единственное исключение — блок-цитата `> Status` по явной
просьбе пользователя).
2. **Вики** — остальные страницы (entities/concepts/packages/contradictions/open-questions/overview).
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')` — каталог; найди нужные страницы.
(Каталог по умолчанию — `entity_search`, решение 1; `index` — опора ориентации.)
3. Только потом действуй.
Если `AGENTS`/`CLAUDE` нет — вики либо новая, либо неухоженная: не
импровизируй структуру, первый ingest создаёт `AGENTS` (+ `CLAUDE`-указатель).
## 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`; таска может отсутствовать |
| Продление лиза | `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 |
| Путь между сущностями | `mcp__mappa__graph_path({from, to})` | кратчайшая цепочка, BFS |
| Соседи / исходящие | `mcp__mappa__graph_neighbors({id})` | рёбра узла с резолвом целей |
| Входящие ссылки | `mcp__mappa__graph_backlinks({id})` | кто ссылается на узел |
| Здоровье графа | `mcp__mappa__graph_stats()` | nodes/edges/components |
**Запись всегда под лизом.** Мутации 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/session-live-ingest` (wiki:2604)».
В теле страниц — викилинки по слагу (`[[concepts/foo]]`, решение 4) или
per-type рефы полными именами (`[[task:N]]`/`[[inbox:N]]`).
---
## Цикл: три операции
### Ingest — «заингесть X»
1. Прочитай источник полностью.
2. Извлеки: entities, concepts, packages, кросс-резы.
3. Создай `sources/<slug>` — одну страницу-резюме на источник (~50150 строк;
ссылку на 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 может затронуть 1015 страниц. Это нормально — для того LLM и нужны.**
Порядок записи: сначала лиз (`task_claim_next`), затем все wiki-мутации одним
циклом (не бери лиз на чтение), затем отпусти (лиз живёт TTL — просто закончи
писать; heartbeat только если цикл реально долгий).
### Query — вопрос по вики
1. Читай `index` сначала, затем углубляйся в страницы (`wiki_get` по слагу).
2. Отвечай с цитатами-викилинками: `[[concepts/foo]]` (рёбра создаются при
записи, решение 4).
3. **Компаундируй вики.** Если ответ — реальный синтез (сравнение, анализ,
новая связь) — спроси пользователя: «Сохранить как страницу wiki?» Хорошие
вопросы становятся страницами в `concepts/`.
**Реляционные/структурные вопросы — не читай, а зови граф** (следующая секция):
связи образуют граф, который LLM не обходит надёжно чтением.
### Lint — «проверь вики»
Ищи:
- **Противоречия** между страницами.
- **Сирот** — страницы без входящих ссылок: `graph_backlinks(id)` (id из
`wiki_get`) → нет входящих рёбер = сирота.
- **Stale-claims** — `updated_at` страницы старше источника, который она резюмирует.
- **Потерянные сущности** — понятия из текста без своей страницы
(`entity_search` по имени → пусто).
- **Пустые/TODO-секции.**
Отчёт — панч-лист. Ничего не удаляй автоматически.
---
## Граф-слой (реляционные/структурные вопросы)
**Stop and call the graph.** На реляционный/структурный вопрос о вики или
любых сущностях mappa (таски, письма, сессии) **не отвечай, прочитав одну
страницу** — это 0%-recall провал, ради которого существует граф-слой.
Сервис ходит по рёбрам детерминированно (BFS) и возвращает ответ в
нескольких строках; контекст не засоряется.
Формы вопроса → тул:
| Вопрос | Тул |
|---|---|
| relational — «что связывает X и Y», «путь между», "what connects", "shortest path" | `graph_path({from, to})` |
| neighbourhood — «соседи X», "neighbours of X" | `graph_neighbors({id})` |
| incoming — «кто ссылается на X», «backlinks», "what links to X" | `graph_backlinks({id})` |
| health — «сироты», «битые ссылки», «здоровье вики», "orphan pages" | `graph_stats()` + `graph_backlinks(id)` |
**Адресация: slug → internal id.** Резолвь `id` через `wiki_get`/`entity_search`
(последнее поле ответа; `ref`/`num` — для показа). Ответы graph несут per-type
refs полными именами (`task:N`/`inbox:N`/`wiki:N`, конвенция #1028) — реферируй
по ним, не по id. Пустой `path` = связи реально нет — так и скажи; не выдумывай
цепочку из текстовой близости.
**Precondition — граф реально связан.** Если сомневаешься — сначала
`graph_stats()`: `edges` ≈ 0 ⇒ граф пуст, отвечай чтением. (Слаги без
[[линков]] рёбер не создают; сироты — норма для разреженных вики.)
---
## Форматы страниц (ОБЯЗАТЕЛЬНО)
### 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>` (новая) + 315 entities/concepts/packages (+ опционально `index`) |
| Query | (чтение) + возможно новая страница |
| Query реляционный | graph_* (BFS), не чтение |
| Lint | (чтение) + graph_backlinks/stats для сирот |
| Новая вики проекта | первый ingest создаёт `AGENTS` + `CLAUDE`-указатель; оп-лог — автоматический |
## Частые ошибки
- **Правка `sources/`.** Нельзя. Только статус-блок по явной просьбе.
- **Дамп сырья в `sources/`.** Резюме — это резюме. Ссылайся на raw, не копируй.
- **Молчаливые перезаписи.** Новый источник противоречит странице — пометь
блоком `> **Противоречие:**`; не затирай.
- **Нарративный оп-лог.** Не веди его руками: сервис пишет logs сам (admin.logs).
- **Не-ASCII слаги.** Ломают grep и кросс-платформенность. Транслитерируй.
- **Пропущенные противоречия в lint.** Ценность вики — во вскрытых напряжениях,
а не в ложном консенсусе.
- **Запись без лиза.** Wiki-мутации без `claim_token` → 422 busy.
- **Держать лиз на чтение/раздумья.** Лиз — на время записи. Чтение — карв-аут.
- **Реляционный вопрос чтением одной страницы.** Это тот самый 0%-recall
провал — зови graph_*.
- **Слаги/пути в graph-тулы.** Только internal id, и только свежие (удалённая
сущность → ошибка).
- **Тащить всю вики в контекст**, чтобы «проследить» связи руками — сервис
делает это за ноль токенов.
## Red flags
- Реляционный вопрос → читаешь страницу вместо `graph_*`.
- Правка `sources/` или молчаливая перезапись противоречия.
- Wiki-мутация без лиза (422) или лиз держится на чтение.
- Нарративный оп-лог руками.
---
## Reference
- Поиск по сущностям: `mcp__mappa__entity_search` (FTS, решение 1).
- Оп-лог: `mcp__mappa__admin_logs` (автоматический, решение 12).
- Дерево/зонтики: `mcp__mappa__graph_tree(root, depth?, fields?, limit?)`.
- Задачи: `mappa-task-work`. Почта: `mappa-messaging`. Делегирование: `mappa-delegation`.
- Related: `using-projects-meta` (мост до флипа), `project-discipline`.

View File

@@ -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, и только свежие
(удалённая сущность → ошибка).

View File

@@ -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, ~50150 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 1015 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) + 315 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>

View File

@@ -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>` — одну страницу-резюме на источник (~50150 строк;
ссылку на 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 может затронуть 1015 страниц. Это нормально — для того 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>` (новая) + 315 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_*`).