chore(1328): дедуп mappa-скилов из skills/skills + dist — канон теперь в mappa
- удалены 8 mappa-* + report-mappa-issue из skills/skills (источник — mappa/skills/) - удалены соответствующие dist/mappa-*.skill архивы - skills/skills остаётся только для общих скилов - чужие WIP (update-skills, using-markitdown dist) не тронуты
This commit is contained in:
BIN
dist/mappa-brainstorm-promote.skill
vendored
BIN
dist/mappa-brainstorm-promote.skill
vendored
Binary file not shown.
BIN
dist/mappa-closing-ritual.skill
vendored
BIN
dist/mappa-closing-ritual.skill
vendored
Binary file not shown.
BIN
dist/mappa-delegation.skill
vendored
BIN
dist/mappa-delegation.skill
vendored
Binary file not shown.
BIN
dist/mappa-knowledge.skill
vendored
BIN
dist/mappa-knowledge.skill
vendored
Binary file not shown.
BIN
dist/mappa-messaging.skill
vendored
BIN
dist/mappa-messaging.skill
vendored
Binary file not shown.
BIN
dist/mappa-session-orient.skill
vendored
BIN
dist/mappa-session-orient.skill
vendored
Binary file not shown.
BIN
dist/mappa-task-work.skill
vendored
BIN
dist/mappa-task-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.
@@ -1,322 +0,0 @@
|
||||
---
|
||||
name: mappa-brainstorm-promote
|
||||
author: ours
|
||||
version: 1.10.0
|
||||
description: >
|
||||
Finalize a brainstorm buffer (mappa type=brainstorm, status=buffer): two
|
||||
paths. (1) Promote a matured buffer — read → target → brainstorm_promote
|
||||
(atomic buffer → wiki-page + archive, decision 7) → action-items as tasks
|
||||
(task_create, bodies carry [[brainstorm:N]]) → review umbrella → covering
|
||||
letter → final entry. (2) Close an already-completed buffer (work done, no
|
||||
wiki needed) — verify linked tasks done → final entry + status=archive.
|
||||
Buffer done ⇔ all action-items created AND all tasks done (incl.
|
||||
review-umbrella) — wiki concepts/buffer-completion-criteria. General mappa
|
||||
mechanism. Old name — trigger-synonym: workshop-promote-brainstorm.
|
||||
Triggers (bilingual): «промоутни брейнсторм», «выкати в вики», "promote
|
||||
the brainstorm", "finalize <topic>", "publish to wiki"; «закрой буфер»,
|
||||
«архивируй буфер», "close the buffer", "archive the buffer".
|
||||
---
|
||||
|
||||
# mappa-brainstorm-promote
|
||||
|
||||
Finalizing a matured brainstorm buffer that lives **as a mappa entity of type
|
||||
`brainstorm`** (status=buffer). This is a general mappa mechanism — exactly
|
||||
like `task.create` or `wiki.create`: the buffer exists in mappa, the skill
|
||||
takes it to the end (promote the content into the wiki + action-items as
|
||||
tasks). No workshop specifics: the skill triggers from any folder, works with
|
||||
brainstorm entities of any project.
|
||||
|
||||
The procedure is linear (from reading the buffer to promotion and tasks), not
|
||||
a loop: it's launched explicitly on the final buffer and takes it to the end.
|
||||
In the forkflow it sits between work (`mappa-task-work`) and finish
|
||||
(`mappa-closing-ritual`).
|
||||
|
||||
**Completion criteria** (wiki `concepts/buffer-completion-criteria`, .workshop):
|
||||
a buffer is done ⇔ (all action-items are created as tasks) ∧ (all created
|
||||
tasks are done, including the review-umbrella). Two entry paths to `archive`:
|
||||
|
||||
- **Promote** (steps 5–9): a maturing buffer whose content must land in a
|
||||
wiki — `brainstorm_promote` (wiki page + archive atomically).
|
||||
- **Close** (step 5b): an already-completed buffer — work done long ago
|
||||
(tasks done / resolved / legacy-promoted in the file era), no wiki page
|
||||
needed. Verify the chain — in the graph for same-project links, via
|
||||
direct `task_get` for cross-project tasks — write the final entry,
|
||||
`brainstorm_update(status='archive')`. This is how done-but-not-closed
|
||||
buffers are swept (case: entity-uuid brainstorm:109, tasks 1067/1068/1093
|
||||
done, buffer still `buffer` with zero edges — audit 2026-08-25).
|
||||
|
||||
**Content promotion — always via `mcp__mappa__brainstorm_promote`:**
|
||||
atomically creates a wiki page (slug from the buffer, body preserved) in the
|
||||
project from the call and moves the buffer to `archive` (number/slug stable,
|
||||
decision 20; parent_of edges, `brainstorm.promoted` event). No file channels.
|
||||
Action-items go as tasks to the target project via `mcp__mappa__task_create`
|
||||
(carve-out without a lease, #1054; sequentially, not batched).
|
||||
|
||||
## When to use
|
||||
|
||||
- «промоутни брейнсторм», «выкати в вики», "promote the brainstorm",
|
||||
"finalize <topic>", "publish to wiki".
|
||||
- The user references a brainstorm entity (brainstorm:N) or a buffer topic
|
||||
that matured and is ready for promotion.
|
||||
|
||||
## Inputs
|
||||
|
||||
- Brainstorm ref `brainstorm:N` or `<topic>` (buffer slug/topic) + project (if
|
||||
the buffer is not in the current project — ask).
|
||||
- For the skill branch additionally: `<name>` of the new skill (if not
|
||||
specified — ask, propose a derivation from the topic).
|
||||
|
||||
## Decision flow
|
||||
|
||||
```
|
||||
brainstorm entity in mappa (type=brainstorm, status=buffer)
|
||||
│
|
||||
▼
|
||||
find + read (entity_search type=brainstorm → entity_get full body)
|
||||
│
|
||||
▼
|
||||
ask: target project (where to promote)
|
||||
│
|
||||
├── close (no promotion): work already done, no wiki page needed
|
||||
│ → step 5b (graph check + final entry + status=archive)
|
||||
│
|
||||
├── ordinary project → brainstorm_promote(project=<target>)
|
||||
│ → wiki page (spec) in the target wiki
|
||||
│
|
||||
└── skill → dialog: description (trigger contract)
|
||||
→ preview + confirm
|
||||
→ mkdir + Write SKILL.md (skeleton) in ~/projects/skills/
|
||||
→ git add + commit (local, no push/install)
|
||||
│
|
||||
▼
|
||||
parse action-items from the buffer body
|
||||
│
|
||||
▼
|
||||
for each: mcp__mappa__task_create (SEQUENTIALLY, not batched)
|
||||
│
|
||||
▼
|
||||
review-umbrella: mcp__mappa__task_create (blocked, blocker=impl#)
|
||||
│
|
||||
▼
|
||||
covering letter: mcp__mappa__inbox_send (mappa-delegation canon)
|
||||
│
|
||||
▼
|
||||
final report (wiki:NNNN — spec, brainstorm:N — archive, tasks)
|
||||
```
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Find the buffer in mappa.** `mcp__mappa__entity_search(type='brainstorm',
|
||||
project=<project>, q=<topic>)` → in the results brainstorm:N (ref). Read the
|
||||
full buffer: `mcp__mappa__entity_get(key)` — key = uuid, full ref
|
||||
`brainstorm:N`, or bare num (канон адресации task:1221: голое число = num;
|
||||
этап A задеплоен) — body = running record (frontmatter + rounds).
|
||||
Адресация буфера — по num/ref/uuid, internal id наружу не используем
|
||||
(выпилится в этапе B, task:1221).
|
||||
|
||||
If the buffer is not in mappa — create a brainstorm entity via
|
||||
`mcp__mappa__brainstorm_create` (or HTTP `POST /entities` type=brainstorm,
|
||||
contract decision 7/#1054). Don't invent file buffers.
|
||||
|
||||
2. **Show the buffer summary (≤2 paragraphs).**
|
||||
|
||||
3. **Ask the target project** — where to promote the content. Default — the
|
||||
project where the buffer lives (brainstorms are run where the topic is
|
||||
relevant). Verify the project exists in mappa:
|
||||
`mcp__mappa__entity_search` type=project (or `mcp__mappa__entity_search`
|
||||
with q=<project name>). If not — abort with a message.
|
||||
|
||||
4. **If target = skill (the user wants it as a skill):**
|
||||
- Ask `<name>` of the new skill (if not specified) — a valid slug
|
||||
(`[a-z0-9-]+`).
|
||||
- Validation (order matters): first check that `~/projects/skills/` itself
|
||||
is a repository. If not — **abort** with the message "clone skills via
|
||||
update-skills or manually".
|
||||
- Then: `~/projects/skills/skills/<name>/` must NOT exist. If it exists —
|
||||
**abort** with the message "skill `<name>` already exists, update through
|
||||
the normal route in `~/projects/skills/`, this skill is not for updates".
|
||||
- Two-pass skeleton: dialog on `description` (activation trigger contract:
|
||||
minimum 2-3 phrases, Russian/English pairs; what it does; antipatterns) →
|
||||
preview + confirm → `Write` of the skeleton (header + 6 empty sections) →
|
||||
local `git commit` in `~/projects/skills/`. **Without** install.sh, push,
|
||||
build-hermes — those are in the baseline tasks of step 7. The body of the
|
||||
skeleton is written in a second pass by eye (outside this skill's scope).
|
||||
|
||||
5. **Content promotion (always via `brainstorm_promote`, decision 7):**
|
||||
|
||||
`mcp__mappa__brainstorm_promote(project=<target>, brainstorm_id=<num | ref brainstorm:N | uuid>)`
|
||||
|
||||
- Atomically: buffer → wiki page (slug from the buffer, body preserved,
|
||||
parent_of buffer→wiki edges and refs→buffer) + buffer → `archive` +
|
||||
significant `brainstorm.promoted` event.
|
||||
- **Frontmatter-summary (wiki:2661):** make sure the buffer body has
|
||||
`summary:` as one line in the frontmatter — `wiki.search` cards read it.
|
||||
If missing — append via `mcp__mappa__brainstorm_update` (PATCH
|
||||
/brainstorm/:id, title/body/status, optimistic version+409; id = num |
|
||||
ref | uuid) before the promotion.
|
||||
- Re-promoting an archived buffer → error (one-shot, idempotent via
|
||||
status). Cross-check `brainstorm_id` (num/ref) from step 1.
|
||||
- If `brainstorm_promote` failed (version conflict, 409) → retry with the
|
||||
fresh num/ref; on a stable failure — abort before creating tasks.
|
||||
|
||||
5b. **Closing an already-completed buffer (no promotion).** When the work is
|
||||
already done and no wiki page is needed (legacy-promoted, resolved by the
|
||||
human, tasks all done, or the decision was reversed):
|
||||
|
||||
- Verify the chain: `mcp__mappa__graph_neighbors`/`graph_backlinks` on
|
||||
the buffer for same-project links (edges resolve in the owner's project
|
||||
scope, finding #1014); for cross-project tasks (workshop → target, the
|
||||
normal case) resolve the refs from the body/final entry via direct
|
||||
`mcp__mappa__task_get(task:N)` — every linked task must be status=done
|
||||
(or the buffer is closed by content: «решено»/«отменено»).
|
||||
If tasks are done but nothing is written — the chain was never recorded;
|
||||
the final entry below fixes it (backward text refs).
|
||||
- Append the final entry to the body via `mcp__mappa__brainstorm_update`
|
||||
(body, expected version; 409 → re-GET → retry):
|
||||
«Закрытие (дата) — цепочка завершена: [[task:N]]… done / решено /
|
||||
промоутнуто (легаси). Критерий: [[concepts/buffer-completion-criteria]]».
|
||||
The `[[task:N]]` and `[[wiki:…]]` links create the closing edges on
|
||||
write (decision 4).
|
||||
- Set `status='archive'` in the same `brainstorm_update`. Buffer archived
|
||||
without a wiki page — the knowledge is already where it belongs or is
|
||||
historical (review reports, legacy plans).
|
||||
- Report: `brainstorm:N` → archive, with the reason.
|
||||
|
||||
6. **Action-items parsing:** regex over lines like `- [ ] ...` in the buffer
|
||||
body, sections after `## Следующие шаги`/`## TODO`/`## Next steps`/
|
||||
`## Action items`. Show the list, allow editing/removing/adding. If 0
|
||||
action-items — continue, don't block.
|
||||
|
||||
7. **Task creation:**
|
||||
|
||||
> **NB:** create tasks **SEQUENTIALLY**, not batched. One `task_create` →
|
||||
> wait for the response → the next one.
|
||||
|
||||
- **Ordinary target:** for each action-item —
|
||||
`mcp__mappa__task_create(project=<target>, slug=<kebab>, title, description,
|
||||
status='ready')`. Create — carve-out, no lease needed (wiki:2660/#1054).
|
||||
The impl task description references the spec (wiki:NNNN from step 5) and
|
||||
MUST start with the buffer wikilink `[[brainstorm:N]]` — a ref edge is
|
||||
created on write (decision 4) when the buffer is in the same project as
|
||||
the task; cross-project it stays a searchable text ref
|
||||
(`entity_search "brainstorm:N"` finds the task).
|
||||
- **Skill:** three baseline tasks in `project='skills'`:
|
||||
- `[<name>-install]` — run `install.sh` in `~/projects/skills/`,
|
||||
verify activation in a new session.
|
||||
- `[<name>-hermes-mapping]` — a record in
|
||||
`~/projects/skills/hermes/mapping.yaml` (mode `auto` for style ones,
|
||||
`pending` if it touches tools/environment).
|
||||
- `[<name>-test-trigger]` — run the trigger phrases from the description:
|
||||
activates on its own, doesn't activate on 2-3 close foreign ones.
|
||||
Plus content tasks from the buffer (if any) — also in `project='skills'`,
|
||||
slug-prefix `<name>-`.
|
||||
- If the N-th task failed — continue the rest, report at the end which were
|
||||
created / which weren't. Remember the slugs for the review-umbrella.
|
||||
|
||||
8. **Review-umbrella (for a target with impl tasks, and for skill — always):**
|
||||
|
||||
`mcp__mappa__task_create(project=<target>, slug=<topic>-review,
|
||||
status='blocked', blocker=<impl task numbers separated by commas>, description=<checklist>)`
|
||||
|
||||
- **Who does it:** not the implementer. The next session in this project (a
|
||||
different model / different day / different agent) with a clean context.
|
||||
The "I just wrote this" bias is the main risk.
|
||||
- Checklist: read the spec (wiki:NNNN from step 5), `git log` of the
|
||||
shipped commits, for each impl task run the tests and cross-check with
|
||||
acceptance criteria, findings → follow-up tasks via `task_create`.
|
||||
- Closing: all findings filed OR the reviewer confirmed "no findings" in
|
||||
the close-note.
|
||||
- If the review task failed — report, **continue** to step 9 (the promotion
|
||||
is already done, the buffer is in archive).
|
||||
|
||||
8b. **Final entry in the buffer (closing the chain).** After tasks are
|
||||
created, append to the buffer body via `mcp__mappa__brainstorm_update`
|
||||
(body + expected version; 409 → re-GET → retry): «Промоут → wiki:NNNN ·
|
||||
таски [[task:N]]… · review-зонт [[task:M]]». This writes the backward
|
||||
refs — the completion record per `concepts/buffer-completion-criteria`
|
||||
(cross-project: text refs, verified by `task_get`; same-project: edges).
|
||||
If the body PATCH on an archived entity is rejected — report to the user
|
||||
(the chain stays visible through the tasks' [[brainstorm:N]] forward refs).
|
||||
|
||||
9. **Covering letter to the target's inbox (mappa-delegation canon).** A task
|
||||
on the board doesn't ping a live session, a letter = ping + context:
|
||||
|
||||
`mcp__mappa__inbox_send(project=<target>, from=<your folder>, subject='Promotion
|
||||
<topic>: tasks <#N…>', body=<list + wiki:NNNN spec>)`
|
||||
|
||||
10. **Final report to the user:**
|
||||
- Where it was promoted: `wiki:NNNN` (spec in the target wiki).
|
||||
- Archive: `brainstorm:N` (status=archive, number stable).
|
||||
- Which tasks were created (ref, title, project).
|
||||
- **For skill:** remind about the second pass "let's flesh out `<name>`".
|
||||
|
||||
## Failure modes
|
||||
|
||||
- Buffer not found in mappa (no brainstorm entity) → abort, report: create via
|
||||
`brainstorm_create` (step 1) or HTTP POST /entities.
|
||||
- `entity_search`/`entity_get` failed (API error, not an empty result) → abort
|
||||
with the error text; don't create a buffer by guess.
|
||||
- Target project doesn't exist in mappa → abort before promotion.
|
||||
- `brainstorm_promote` failed (409 version / stable refusal) → retry with the
|
||||
fresh num/ref; on a repeated failure — abort before creating tasks. The
|
||||
buffer stays in buffer — retried later.
|
||||
- Buffer already `archive` (repeated call) → abort: promotion is one-shot,
|
||||
idempotence via status (decision 7).
|
||||
- Closing (step 5b): buffer still has open linked tasks → abort, don't close;
|
||||
report which tasks are open. Buffer is a living storm → abort (close only
|
||||
completed or reversed buffers).
|
||||
- Closing: `brainstorm_update` 409 (version) → re-GET → retry; repeated
|
||||
failure → report, buffer stays in `buffer`.
|
||||
- `task_create` failed on the N-th content task → continue the rest, report
|
||||
partial. The promotion is already done — the buffer is not rolled back.
|
||||
- `task_create` review-umbrella failed → don't block, report to the user
|
||||
(create manually from step 8).
|
||||
- `inbox_send` (covering letter) failed → promotion and tasks are not rolled
|
||||
back; report to the user, the letter can be sent later (the promotion is
|
||||
already visible in the graph/inbox of the target).
|
||||
- **Skill:** `~/projects/skills/` doesn't exist → abort.
|
||||
- **Skill:** `~/projects/skills/skills/<name>/` already exists → abort.
|
||||
- **Skill:** user didn't confirm the preview → abort, state unchanged.
|
||||
- **Skill:** local `git commit` in `~/projects/skills/` failed → the file
|
||||
stays, report that the commit needs to be done by hand; the buffer promotion
|
||||
is not blocked.
|
||||
|
||||
## Side effects
|
||||
|
||||
- **Always:** `brainstorm_promote` — atomically wiki page in the target +
|
||||
buffer → `archive` + parent_of edges (wiki→buffer, refs→buffer) +
|
||||
`brainstorm.promoted` event.
|
||||
- **Closing (5b):** `brainstorm_update` — final entry with `[[task:N]]`/
|
||||
`[[wiki:…]]` refs + status → `archive`; closing edges on write.
|
||||
- **Ordinary target:** spec page in the target project's wiki (with
|
||||
frontmatter-summary, wiki:2661) + impl tasks + review-umbrella + covering letter.
|
||||
- **Skill:** skeleton `~/projects/skills/skills/<name>/SKILL.md` (only header +
|
||||
empty 6-section skeleton) + local commit in `~/projects/skills/`.
|
||||
**Without** install.sh, push, build-hermes — those are in the baseline tasks.
|
||||
- Creates N tasks in the target via `mcp__mappa__task_create` (carve-out).
|
||||
- Creates a review-umbrella task (status=blocked, blocker=impl#).
|
||||
- Sends a covering letter to the target's inbox.
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **Don't use file channels** — the buffer lives in a mappa brainstorm entity,
|
||||
no `.brainstorm/`/`.archive/` records.
|
||||
- **Don't use `mcp__projects-meta__tasks_create` / `knowledge_ingest` /
|
||||
`knowledge_promote`** — file channels are removed. Tasks —
|
||||
`mcp__mappa__task_create`, wiki — `brainstorm_promote` (content) +
|
||||
`wiki_create`/`wiki_update` (extra pages).
|
||||
- Don't `git mv` the buffer into the archive — the promotion archives it itself.
|
||||
- Don't delete the buffer instead of promoting — the graph history is lost
|
||||
(parent_of, refs).
|
||||
- Don't close a living buffer (5b) — closing is only for completed/reversed
|
||||
work; verify linked tasks via the graph first.
|
||||
- Don't close without the final entry — the backward refs are the chain.
|
||||
- Don't invent wiki pages when closing (5b) — closing ≠ promotion.
|
||||
- Don't batch `task_create` (race; incident 2026-08-24: 6/7 failed) — only
|
||||
sequentially.
|
||||
- Don't forget the covering letter — a task on the board doesn't ping a live session.
|
||||
- **Skill:** don't automatically reformat the buffer body into the skeleton —
|
||||
the body is written in a second pass by eye.
|
||||
- **Skill:** don't run `install.sh`, don't push, don't edit
|
||||
`hermes/mapping.yaml` — those are baseline tasks.
|
||||
- **Skill:** don't promote into an existing skill (abort).
|
||||
@@ -1,152 +0,0 @@
|
||||
---
|
||||
name: mappa-closing-ritual
|
||||
author: ours
|
||||
version: 1.3.0
|
||||
description: >
|
||||
Finish phase of the forkflow: handoff write (mcp__mappa__handoff_write,
|
||||
version h:N) + PROPOSE wiki-ingest + PROPOSE task closes. Mutations — only
|
||||
after user confirmation. Ad-hoc: mode=light — an explicit question "Write
|
||||
handoff?" at the end of the session (NOT an automatic sweep), the decision
|
||||
is the human's. Old name — trigger-synonym: session-handoff (write part).
|
||||
Reading at start — mappa-session-orient. Triggers (bilingual): «завершаем
|
||||
сессию», «сворачиваемся», «закругляемся», "wrap up session", "end session",
|
||||
"we're done for now". Anti-triggers (task-zone, not session-end):
|
||||
«закрываем эту таску», «pause», «отбой», «разбегаемся».
|
||||
---
|
||||
|
||||
# mappa-closing-ritual
|
||||
|
||||
Finish phase of the agent cycle: **write handoff → propose wiki-ingest →
|
||||
propose task closes**. Start ≠ finish: reading the handoff at start —
|
||||
`mappa-session-orient`; here — the write path with procedure and confirmation.
|
||||
|
||||
Channel — the **Mappa handoff entity** (`mcp__mappa__handoff_write`, type
|
||||
`h:`, per-project): fields `session_id`/`date`/`status`/`summary`/
|
||||
`open_treks[]`/`ask_user[]`/`guards[]`/`recent_commits[]`. Each write = a **new
|
||||
version** (append-only, versioned history). The file-based
|
||||
`.tasks/NEXT_SESSION.md` no longer exists.
|
||||
|
||||
## When to use
|
||||
|
||||
- Session-end phrases: «завершаем сессию», «сворачиваемся», «закругляемся»,
|
||||
"wrap up session", "end session", "we're done for now".
|
||||
- Ad-hoc session without a track/task at the end: **mode=light** — an explicit
|
||||
question "Write handoff?" (not an automatic sweep), the human decides.
|
||||
- The project's AGENTS.md contains the trigger line
|
||||
`session handoff: read on start, write on end`.
|
||||
|
||||
**Skip (task-zone, not session-end):** «закрываем эту таску» (task close →
|
||||
`mappa-task-work`), «pause», «приостанови» (task-pause), «отбой», «разбегаемся»
|
||||
(too broad), "let me finish one task first, then we'll talk" (partial finish).
|
||||
On ambiguity — **ASK**: "are we closing the session or a task?"
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Scope check
|
||||
|
||||
This is the current project (cwd). No global mutations, no other projects.
|
||||
|
||||
### 2. Mid-task capture
|
||||
|
||||
If there is a 🔴 active task of the project (mappa board / `.tasks/`) — capture
|
||||
into summary:
|
||||
```
|
||||
left mid-task: <slug>
|
||||
where_stopped: <one line>
|
||||
```
|
||||
No board — write the handoff without the mid-task section, don't block.
|
||||
|
||||
### 3. Compose content (handoff fields)
|
||||
|
||||
- `session_id` — `<ISO date>` or session identifier;
|
||||
- `status` — `active` (work continues) / `paused` (frozen) / `done` (finished);
|
||||
- `summary` — the link: where we stopped, mid-task, key decisions;
|
||||
- `open_treks` — array of open tracks (readiness + entry-point);
|
||||
- `ask_user` — pending decisions / expected resolutions;
|
||||
- `guards` — "don't do" (preemptive guards);
|
||||
- `recent_commits` — 3–5 latest commits (`<slug>: <subject>`).
|
||||
|
||||
Forward-looking, not a timeline: handoff = a link of new things specifically
|
||||
for the next turn, not an overview of the whole project. The mappa board / wiki
|
||||
remain authoritative for their own scope — don't duplicate them in the handoff.
|
||||
|
||||
### 4. Append
|
||||
|
||||
`mcp__mappa__handoff_write(project=<name>, session_id, status, summary, open_treks?, ask_user?, guards?, recent_commits?)` — the service creates a new `h:N` version (previous ones remain; reading the latest — `entity_search(type='handoff', project, limit=1)`). Pass array fields as `[]` when empty (the next agent sees: empty, not forgotten). Written without a lease (like inbox).
|
||||
|
||||
> **Confirm gate:** handoff write is a mutation. In mode=light (ad-hoc) and on
|
||||
> ambiguity — first an explicit question "Write handoff?", only after "yes" —
|
||||
> write.
|
||||
|
||||
### 5. Propose wiki-ingest (don't write!)
|
||||
|
||||
If durable knowledge appeared during the session — **PROPOSE** the ingest
|
||||
(`mappa-knowledge`: mappa wiki create — carve-out, update — version+409,
|
||||
wiki:2660), listing the candidates. Don't write anything without confirmation.
|
||||
|
||||
### 6. Propose task-board closes (don't close!)
|
||||
|
||||
If there are tasks that look closed — **PROPOSE** the closes
|
||||
(`mappa-task-work`: task_close with version+409, wiki:2660). Respect ralph-loop:
|
||||
verifier tasks close only via the verifier (attempt/harness-record).
|
||||
|
||||
### 7. Proposal format — one block
|
||||
|
||||
```
|
||||
Closing ritual:
|
||||
(a) ingest X into the wiki?
|
||||
(b) close Y?
|
||||
(c) nothing.
|
||||
```
|
||||
Wait for the answer. Refusal = skip (don't insist, don't repeat in this session).
|
||||
|
||||
---
|
||||
|
||||
## mode=light (ad-hoc sessions)
|
||||
|
||||
Ad-hoc session (no task/track, but artifacts may be born): the trace in mappa
|
||||
is always written (service contract — session live-ingest), but
|
||||
**structuring happens only on an explicit question**: at the end of the
|
||||
session ask "Write handoff?" (the human decides). NOT an automatic sweep:
|
||||
without "yes" — write nothing, the trace stays in mappa as is.
|
||||
|
||||
## Failure modes
|
||||
|
||||
- **Secret detected.** Content matches secret patterns (`AKIA...`, `sk-...`,
|
||||
`ghp_...`, `ssh-rsa`, `BEGIN PRIVATE KEY`, `password=`/`token=`) → **abort
|
||||
write**. Tell the user with the suspicious line indicated.
|
||||
- **Ambiguous phrase** → ASK "are we closing the session or a task?", don't guess.
|
||||
- **Mid-task without a board** → handoff without the mid-task section, don't block.
|
||||
- **User refused the ritual proposals** → skip, don't insist.
|
||||
- **Project not in mappa** → silent exit (first session).
|
||||
|
||||
## Side effects
|
||||
|
||||
- Writes the project's handoff entity (append-only, versioned history). No
|
||||
files, no git commits for the handoff.
|
||||
- The ritual **proposes** wiki-ingest and task closes — but does NOT write
|
||||
them without "yes".
|
||||
- No global mutations, no other projects.
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **No auto-execute** — every mutation (handoff write / wiki-ingest / task
|
||||
close) only after an explicit "yes" from the user.
|
||||
- **Don't run the ritual on a substantive commit.** Only a session-end phrase
|
||||
(or an explicit user request).
|
||||
- **Don't sweep automatically in ad-hoc** — mode=light: an explicit question
|
||||
"Write handoff?", the human decides.
|
||||
- **Don't write secrets** into the handoff. Secret-pattern match → abort.
|
||||
- **Don't write a handoff on every commit** — only at the finish.
|
||||
- **Don't duplicate the board / wiki** — handoff = forward-looking link.
|
||||
- **No cross-project** — per-project scope.
|
||||
- **Don't treat the handoff as authoritative** on the reader's side — it's the
|
||||
previous session's recommendation, not a directive; the user can override.
|
||||
|
||||
## Reference
|
||||
|
||||
- Reading the handoff at start: `mappa-session-orient`.
|
||||
- Task closes: `mappa-task-work` (pre-close coverage, notify letter).
|
||||
- Wiki-ingest: `mappa-knowledge`.
|
||||
- Letters: `mappa-messaging`. Delegation: `mappa-delegation`.
|
||||
- Session live-ingest (the trace in mappa is always written): `concepts/session-live-ingest` (wiki:2604).
|
||||
@@ -1,277 +0,0 @@
|
||||
---
|
||||
name: mappa-delegation
|
||||
author: ours
|
||||
version: 1.4.0
|
||||
description: >
|
||||
The cycle of delegating a task to another agent/project: pre-flight gate →
|
||||
body template → dry-run preview → confirm → covering letter to the
|
||||
recipient's inbox → paired review task for impl. Every cross-project
|
||||
delegation is a pair: tasks_create + letter (event: created) — a task on the
|
||||
board does not ping a live session. Old name — trigger-synonym:
|
||||
delegate-task. Triggers (bilingual): «делегировать таску», «создать задачу
|
||||
на агента», «поставить задачу агенту», «tasks_create для», "delegate task",
|
||||
"create a task for an agent", "assign a task to an agent". NOT applicable:
|
||||
self-assigned tasks on your own board («создать задачу себе» →
|
||||
mappa-task-work), doing work yourself, workshop-internal tasks.
|
||||
---
|
||||
|
||||
# mappa-delegation
|
||||
|
||||
Unified **cycle of assigning tasks to agents**: from the pre-flight gate to
|
||||
the covering letter to the recipient. Guarantees that every delegated task
|
||||
carries: mandatory skills (imperative invoke), pre-flight permissions,
|
||||
steering-loop fields (notify/weight), a paired review task for impl — and that
|
||||
the recipient actually learns about the task (letter, not just the board).
|
||||
|
||||
## When to use
|
||||
|
||||
Before every `tasks_create` call for another project or agent.
|
||||
|
||||
**Activates:** «делегировать таску», «создать задачу на агента», «поставить задачу агенту», «tasks_create для», "delegate task", "create a task for an agent".
|
||||
|
||||
**Not applicable:**
|
||||
- Work you do yourself in the current session.
|
||||
- Self-assigned tasks on your own board («создать задачу себе», "task for myself") → `mappa-task-work`, not delegation. Disambiguator: «на агента»/«агенту»/«в проект X» = delegation; «себе»/"myself" = your own board.
|
||||
- Workshop-internal tasks (`.workshop/.tasks/` — workshop-meta, not delegation).
|
||||
- `tasks_create` with `target=agenda` (cross-project agenda — not delegation to an agent).
|
||||
|
||||
## Inputs
|
||||
|
||||
- `target_project` — qualified `<owner>/<repo>` (required)
|
||||
- `slug` — kebab-case latin
|
||||
- Short task description (goal + acceptance criteria)
|
||||
- `weight` — `cheap-ok | needs-claude | needs-human`
|
||||
- `notify` — commissioning project slug (who gets the inbox letter on close/park)
|
||||
|
||||
The task number is assigned by the server (`tasks_create` from the
|
||||
agenda/task-counter) — the assigner neither invents nor reserves it. The
|
||||
returned `#n` from preview/confirm is the task's machine key: blockers,
|
||||
letters, and the decision trail reference it.
|
||||
|
||||
> **Contract (interactive, wiki:2660).** `task_create` — **carve-out without a
|
||||
> lease** (create-without-lease as a principle); update/close — version+409
|
||||
> (409 → re-GET → retry). file channel — sha-CAS via Gitea. No claim/TTL —
|
||||
> "take a task" = conditional update by version (poller outside mappa).
|
||||
|
||||
## Steps (the cycle)
|
||||
|
||||
### 1. Pre-flight gate (6 questions to the user)
|
||||
|
||||
Ask **before** composing the task body:
|
||||
|
||||
0. **Critical infrastructure?** — the task changes: poller/agent-runner, MCP
|
||||
servers (projects-meta, interns), claim/close/heartbeat mechanics, deploy
|
||||
infra (traefik, docker, systemd), CI/CD pipelines, git hooks.
|
||||
- If **yes** → force `weight: needs-human`, no discussion. Explain to the
|
||||
user why.
|
||||
- If **no** → continue.
|
||||
1. **Interns — allowed?** (yes/no, per task)
|
||||
2. **Auto-push — allowed?** (yes/no, per task)
|
||||
3. **Contextual skills beyond defaults?** — propose per task content (e.g.
|
||||
`claude-api` for Anthropic SDK work, `frontend-design` for UI,
|
||||
`using-interns` if interns are allowed); the user approves.
|
||||
4. **notify — who gets the completion/block report?** (project slug; usually
|
||||
`.workshop` or `OpeItcLoc03/workshop`)
|
||||
5. **Session-break after this task?** — is a session break needed after it
|
||||
closes (domain-switch, milestone, heavy infra)?
|
||||
- If **yes** → set `session_break` in the task body (see template): `true`
|
||||
or a string-hint with the next track's name. `mappa-task-work` will stop
|
||||
after close and propose ending the session, without claiming the next task.
|
||||
- If **no** → don't add the field (default — the agent continues the cycle).
|
||||
|
||||
### 2. Compose the task body per template
|
||||
|
||||
Sections strictly in order:
|
||||
|
||||
```
|
||||
<Goal — one or two sentences. Acceptance criteria if any.>
|
||||
**Spec:** <path to the design solution or .brainstorm/…> — mandatory for tasks
|
||||
from design/decision: the impl reads the design, doesn't guess
|
||||
|
||||
## Mandatory skills — invoke before starting work
|
||||
|
||||
- invoke `tdd-criteria` — before writing code
|
||||
- invoke `mappa-task-work` — for task status management
|
||||
- invoke `project-discipline` — commit/push discipline
|
||||
- invoke `mappa-knowledge` after closing — ingest .wiki/concepts/<slug>.md
|
||||
[if cross-project: - invoke `using-projects-meta` — cross-project tasks/wiki]
|
||||
[contextual skills from step 1.3]
|
||||
|
||||
**TDD:** yes | no — <reason>
|
||||
**Permissions:** interns: yes/no | auto-push: yes/no
|
||||
**weight:** cheap-ok | needs-claude | needs-human
|
||||
**notify:** <commissioning-project-slug>
|
||||
[**allow_upgrade:** true/false]
|
||||
[**session_break:** true | "<next track / hint>"] # optional — mappa-task-work stops after close, doesn't claim the next task
|
||||
```
|
||||
|
||||
**When to set `session_break`** (optional; by default DON'T set it — it marks
|
||||
a real boundary, not a default). Three cases:
|
||||
|
||||
1. **Domain / repo switch** — the task finishes one track before moving to an
|
||||
unrelated one.
|
||||
2. **Milestone task** — the last in a group of sub-tasks of one feature.
|
||||
3. **Heavy infra task** — shared checkout, migrations, deploy — where it's
|
||||
reasonable to stop and check the state.
|
||||
|
||||
Value: `true` (next track = "see STATUS.md") or a string-hint with the next
|
||||
track's name. Consumer — `mappa-task-work`: after close it prints
|
||||
`🔚 SESSION BOUNDARY …` and stops, without claiming the next task. Design:
|
||||
`.wiki/concepts/delegate-task-session-break.md`.
|
||||
|
||||
**Staged breakdown:** if the solution splits into stages (1 → 1b → 3), create
|
||||
each stage as a separate task with `status: blocked` + `blocker:
|
||||
<predecessor numbers> (#n1, #n2 — numbers, not slugs; the number = machine
|
||||
key)`. The board shows the order, the poller won't take dependent work early.
|
||||
Create tasks in one repo sequentially, not in parallel (otherwise sha-lock
|
||||
conflict — see Failure modes).
|
||||
|
||||
**Why `invoke` and not a trigger phrase:** AGENTS.md is unreliable (drifts
|
||||
under compression, weak models ignore it). The task body is read actively —
|
||||
the imperative `invoke` is a direct command, not passive matching.
|
||||
|
||||
### 3. Dry-run preview
|
||||
|
||||
`tasks_create(confirm=false)` — show the user the preview before the real commit.
|
||||
|
||||
### 4. Confirmation and creation
|
||||
|
||||
After the user's OK: `tasks_create(confirm=true)`.
|
||||
|
||||
### 5. Covering letter — mandatory for cross-project delegation
|
||||
|
||||
After creation, **every cross-project delegation** is duplicated by a letter to
|
||||
the recipient's inbox (canon — `mappa-messaging`: Mappa channel, address from
|
||||
the address book `~/projects/.wiki/concepts/projects-address-book.md`):
|
||||
|
||||
```
|
||||
mcp__mappa__inbox_send(
|
||||
project: <recipient address>, # folder name, from the address book
|
||||
from: <your folder>,
|
||||
subject: "[event: created] #n slug",
|
||||
body: "1-2 lines — what the task is, why, slug; «sort it out and take it»"
|
||||
)
|
||||
```
|
||||
|
||||
(«sort it out and take it» — intentionally bilingual placeholder: the covering
|
||||
letter body may be written in the recipient's language (Russian for
|
||||
Russian-speaking projects, English otherwise). Not a trigger phrase.)
|
||||
```
|
||||
|
||||
(update/close mutations — version-based (409 → retry); letter delivery —
|
||||
carve-out, requires no lease.)
|
||||
|
||||
Reason: a task on the board **does not ping the recipient's live session**.
|
||||
The poller will pick it up by `Weight`/`Notify`, but a live interactive
|
||||
session learns only through the inbox monitor — i.e. through the letter. The
|
||||
rule "task + letter, not just task" — is the general case (step 7 is its
|
||||
particular case for downstream tasks).
|
||||
|
||||
Skip: self-assigned tasks on your own board; `target=agenda` (shared board,
|
||||
no concrete recipient — steering-loop via `Notify`).
|
||||
|
||||
### 6. Paired review task (impl tasks only)
|
||||
|
||||
If the task is implementation — create the paired `<slug>-review`
|
||||
(status=blocked, blocker=`#n` — the impl task number). Skip for: pointer
|
||||
tasks, ops tasks, research tasks, any non-impl.
|
||||
|
||||
**Deploy gate (operator rule 2026-08-26):** if the task requires deploy — its
|
||||
target is `.admin` (secrets/runbooks are service-use, other agents must NOT
|
||||
look into them), not the app repo. Deploy is possible ONLY after: impl close →
|
||||
paired review done → all follow-up tasks closed. Admin gets the task + a
|
||||
covering letter.
|
||||
|
||||
**Notifying affected projects (operator rule 2026-08-26):** every delegation /
|
||||
promotion notifies the project agents — the covering letter goes to ALL
|
||||
affected projects, except yourself (self-copy doesn't count as notifying
|
||||
others). Task on a board doesn't ping a live session; the letter is the ping.
|
||||
|
||||
**`weight` of the review task — inherit from the impl task, but never below
|
||||
`needs-claude`** (set explicitly at `tasks_create`):
|
||||
|
||||
- impl `needs-human` → review `needs-human` (a critical-infra change cannot
|
||||
be reviewed by a weak tier — the review inherits the impl's strictness).
|
||||
- impl `needs-claude` → review `needs-claude`.
|
||||
- impl `cheap-ok` → review `needs-claude` (floor: review is
|
||||
discipline-critical, see What NOT to do — don't drop to cheap-ok).
|
||||
|
||||
Without an explicit `weight` the poller won't route the review task (the
|
||||
reconciler skips it) — so always set it, even when impl and review are at the
|
||||
same tier.
|
||||
|
||||
### 7. Downstream task for a LIVE session → require task + inbox letter
|
||||
|
||||
If the task body **instructs the agent to create a downstream task itself** for
|
||||
another project where a **live interactive session** is working (e.g. the
|
||||
programmer sets a deploy task for the admin) — in the spec **explicitly require
|
||||
BOTH `tasks_create` AND the inbox letter** to that project
|
||||
(`mcp__mappa__inbox_send(project=<target>, from=<yours>, subject="[event: created] #n slug", ...)`).
|
||||
|
||||
Reason: a task on the board does **NOT** ping the live session. The poller
|
||||
will pick it up by `Weight`/`Notify`, but a live interactive session learns
|
||||
only through the inbox monitor / Stop-hook — i.e. through the letter. A spec
|
||||
that requires only `tasks_create` leaves the downstream task hanging unnoticed,
|
||||
and someone finishes the ping by hand.
|
||||
|
||||
Rule: poller-driven target → `Weight`/`Notify` mandatory; live session → inbox
|
||||
letter mandatory; **not sure poller or live — require BOTH.** Apply the same
|
||||
rule when you ping a peer yourself: task + letter, not just task.
|
||||
|
||||
## Failure modes
|
||||
|
||||
- **User refuses the pre-flight** → abort, don't create the task.
|
||||
- **User rejects the dry-run preview** → abort.
|
||||
- **notify not specified** → re-ask, don't skip silently. Without notify the
|
||||
steering-loop doesn't close.
|
||||
- **weight not specified** → re-ask. Without weight the poller doesn't know who
|
||||
to give the task to.
|
||||
- **tasks_create failed** → distinguish: **PushRejected** (sha-lock conflict —
|
||||
the repo moved between preview and confirm; happens on parallel creation into
|
||||
one repo) → **retry**: repeat the confirm — the server re-reads the actual
|
||||
base_sha. Other errors → tell the user, don't retry without an explicit request.
|
||||
|
||||
## Side effects
|
||||
|
||||
- Creates a task in the target project via `tasks_create` (file channel —
|
||||
Gitea commit; service channel — mappa entity, create = carve-out without a
|
||||
lease wiki:2660).
|
||||
- Optionally creates the paired review task (status=blocked).
|
||||
- Covering letter to the recipient's inbox (cross-project delegation).
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- Don't skip the pre-flight gate — even if everything seems obvious.
|
||||
- Don't use passive trigger phrases instead of `invoke` — "tdd-criteria" in
|
||||
text is weaker than "invoke `tdd-criteria`".
|
||||
- Don't skip `notify` — without it the boss won't learn about completion.
|
||||
- Don't skip `weight` — without it fleet routing is blind.
|
||||
- Don't create a review task for pointer/ops/research tasks — impl only.
|
||||
- Don't create a review task without `weight` — the reconciler/poller will
|
||||
skip it. Inherit from impl, floor `needs-claude` (see Step 6).
|
||||
- Don't assign `weight: cheap-ok` where discipline is critical (review,
|
||||
security, schema migration) — weak models may ignore invoke instructions.
|
||||
- Don't assign `weight: needs-claude` or `cheap-ok` to tasks changing critical
|
||||
infrastructure (poller, MCP servers, deploy, CI/CD) — only `needs-human`.
|
||||
- Don't set `session_break` routinely on every task — it marks a real
|
||||
boundary (domain-switch / milestone / heavy infra), not a default; otherwise
|
||||
`mappa-task-work` breaks the session after every close.
|
||||
- **Don't create tasks from design/decision without a `**Spec:**` reference**
|
||||
— the impl agent guesses thresholds/scope instead of reading the design.
|
||||
- **Don't create several tasks in one repo in parallel** — sha-lock conflicts
|
||||
(PushRejected); serialize the confirms.
|
||||
- **Don't delegate a cross-project task without the covering letter** to the
|
||||
recipient's inbox (step 5, Mappa `inbox_send`). `tasks_create` into a foreign
|
||||
board doesn't ping the live session — a task without a letter stays unnoticed
|
||||
until the poller/hand.
|
||||
- **Don't instruct the agent to create a downstream task for a live session
|
||||
without the paired inbox letter** (see Step 7). `tasks_create` into a foreign
|
||||
board doesn't ping the live session — the spec must require BOTH the task
|
||||
and the letter, otherwise the downstream task hangs unnoticed.
|
||||
|
||||
## Reference
|
||||
|
||||
- Letters: `mappa-messaging` (inbox_send canon, address book).
|
||||
- Tasks/board: `mappa-task-work`.
|
||||
- Knowledge: `mappa-knowledge` (wiki after closing).
|
||||
- Promotion: `mappa-brainstorm-promote` (review-umbrella through it too).
|
||||
@@ -1,279 +0,0 @@
|
||||
---
|
||||
name: mappa-knowledge
|
||||
author: ours
|
||||
version: 1.5.3
|
||||
description: >
|
||||
The cycle of working with a project's knowledge in Mappa (Karpathy LLM Wiki,
|
||||
channel = mappa entities): ingest → query → lint + a graph layer for
|
||||
relational/structural questions. Absorbs using-wiki + using-wiki-graph (old
|
||||
names — trigger-synonyms). Triggers (bilingual): «заингесть», «обнови вики»,
|
||||
«запроси вики», «проверь вики», "use project wiki", "query the wiki",
|
||||
«что связывает X и Y», «как связаны», «путь между X и Y», "what connects
|
||||
X and Y", «что ссылается на X», «backlinks of X», «сироты», «битые ссылки»,
|
||||
"orphan pages". Wiki = entities type=wiki (read — carve-out; create —
|
||||
carve-out, update — version+409; contract wiki:2660). Relational questions —
|
||||
via graph_* (BFS server-side), guarded failure-mode: one page and stop,
|
||||
no multi-hop chains by reading. Skip for single-page content questions.
|
||||
---
|
||||
|
||||
# mappa-knowledge
|
||||
|
||||
The single cycle of working with a project's knowledge in **Mappa**: three
|
||||
operations (ingest / query / lint) + a **graph layer** for relational and
|
||||
structural questions. The skill is a cycle, not a tool: knowledge is
|
||||
**compiled once and kept current** (ingest), queried (query), checked (lint),
|
||||
and the links between entities are read through the graph (graph_*).
|
||||
|
||||
Channel — Mappa (`mcp__mappa__*`), NOT files. A page is an entity `type=wiki`
|
||||
(`wiki:N`); read — carve-out; **create — carve-out without a lease; update —
|
||||
optimistic concurrency (version+409 → retry)** (contract wiki:2660, v0.12.0).
|
||||
The file-based `.wiki/` no longer exists; `setup-wiki` is dead (nothing to set up).
|
||||
|
||||
## When to use
|
||||
|
||||
- Ingest a document/source into the wiki («заингесть X», «обнови вики»).
|
||||
- Answer from the wiki / check the wiki («запроси вики», «проверь вики», lint).
|
||||
- Relational/structural question («что связывает X и Y», «backlinks», «сироты») — the graph layer.
|
||||
- Modify any page — formats below are mandatory; project conventions live in
|
||||
the `AGENTS` entity (legacy — `CLAUDE` pointer).
|
||||
|
||||
**NOT for:** one-off code questions (normal file reading), single-file
|
||||
README/ADR (not a persistent knowledge base), a project without a wiki in mappa.
|
||||
|
||||
## Three layers (don't mix)
|
||||
|
||||
1. **Raw sources** — `summaries/<slug>` pages. Immutable: read, don't edit
|
||||
(the only exception — the `> Status` blockquote on an explicit user request).
|
||||
2. **Wiki** — the other pages (entities/concepts/packages/contradictions/open-questions/overview).
|
||||
3. **Schema** — the `AGENTS` entity (canon, slug `AGENTS`) + `CLAUDE` (legacy
|
||||
pointer "Canon is AGENTS"). Read `AGENTS` first; it overrides this skill on
|
||||
conflict.
|
||||
|
||||
## First step of any operation
|
||||
|
||||
1. `mcp__mappa__wiki_get(project, 'AGENTS')` — if present, read it (canon; if
|
||||
not — `wiki_get(project, 'CLAUDE')`, the legacy pointer).
|
||||
2. `mcp__mappa__wiki_get(project, 'index')` — the catalog; find the needed
|
||||
pages. (Default catalog — `entity_search`, decision 1; `index` is an
|
||||
orientation aid.)
|
||||
3. Only then act.
|
||||
|
||||
If `AGENTS`/`CLAUDE` is missing — the wiki is either new or unmaintained:
|
||||
don't improvise the structure, the first ingest creates `AGENTS`
|
||||
(+ `CLAUDE` pointer).
|
||||
|
||||
## MCP surface
|
||||
|
||||
| Operation | Tool | Note |
|
||||
|---|---|---|
|
||||
| Read a page | `mcp__mappa__wiki_get(project?, slug)` | read — carve-out |
|
||||
| Search pages | `mcp__mappa__entity_search(q, type='wiki', project?, scope?, limit)` | ILIKE over body/title (full bodies) |
|
||||
| Card search | `mcp__mappa__wiki.search(q, scope?, project?, projects?, limit?)` | cards {ref, project, slug, title, summary, snippet, related} — without bodies (wiki:2661) |
|
||||
| Create a page | `mcp__mappa__wiki_create(project, slug, body)` | **carve-out without a lease** |
|
||||
| Update a page | `mcp__mappa__wiki_update(project, id, title?, body?, version)` | id = num \| ref wiki:N \| uuid (канон task:1221); **version-based**: conflict → 409 → retry with the fresh version from wiki_get |
|
||||
| Path between entities | `mcp__mappa__graph_path({from, to})` | shortest chain, BFS |
|
||||
| Neighbors / outgoing | `mcp__mappa__graph_neighbors({id})` | node edges with target resolution |
|
||||
| Incoming links | `mcp__mappa__graph_backlinks({id})` | who references the node |
|
||||
| Graph health | `mcp__mappa__graph_stats()` | nodes/edges/components |
|
||||
|
||||
**Writing — carve-out (create) / version-based (update), no lease (interactive
|
||||
contract, wiki:2660).** `wiki_create` requires no claim_token; `wiki_update`
|
||||
takes the expected `version` (fresh from `wiki_get`) — conflict → 409 →
|
||||
re-GET → retry.
|
||||
|
||||
**Frontmatter-summary (wiki:2661, card search).** On create/update/promote
|
||||
write `summary:` — ONE essence line in the page frontmatter (`---\ntitle: …\nsummary: one line\n---`). The `wiki.search` cards read it (without summary the
|
||||
card is poorer — snippet fallback only). Don't insert duplicate info into the
|
||||
body: the summary is compiled once, in the frontmatter.
|
||||
|
||||
**Refs and ids (#1037/#1028, канон task:1221).** The public surface carries the per-type ref by
|
||||
full name as the first field: `ref: "wiki:3"` (decision 20, convention #1028),
|
||||
`num` next, the global `id` — internal (last). `wiki_update` takes the
|
||||
`num` | `ref wiki:N` | uuid (этап A task:1221 задеплоен: голое число = num;
|
||||
internal id наружу не используем — выпилится в этапе B). In prose —
|
||||
slug/name first, ref as anchor: "the spec `concepts/session-live-ingest`
|
||||
(wiki:2604)". In page bodies — wikilinks by slug (`[[concepts/foo]]`,
|
||||
decision 4) or per-type refs by full names (`[[task:N]]`/`[[inbox:N]]`).
|
||||
|
||||
---
|
||||
|
||||
## The cycle: three operations
|
||||
|
||||
### Ingest — «заингесть X»
|
||||
|
||||
1. Read the source completely.
|
||||
2. Extract: entities, concepts, packages, cross-results.
|
||||
3. Create `summaries/<slug>` — one summary page per source (~50–150 lines;
|
||||
put the raw link in frontmatter `raw_path` + `ingested:`).
|
||||
4. For every affected page:
|
||||
- exists → update (`wiki_update(project, id, body, version)` — version
|
||||
fresh from `wiki_get`; 409 → re-GET → retry). **Mark contradictions
|
||||
explicitly** with a `> **Contradiction:** source A says X, source B — Y`
|
||||
block. Don't overwrite silently.
|
||||
- missing → create (`wiki_create`, carve-out).
|
||||
5. Update `index` (catalog: one line per page) — optional; the default catalog
|
||||
is `entity_search` (decision 1).
|
||||
6. Report to the user: what was created, what updated, which contradictions.
|
||||
First ingest of a new wiki: create `AGENTS` (canon) + `CLAUDE` (pointer).
|
||||
|
||||
**Op-log — automatic.** Every write operation is already logged by the service
|
||||
into the `logs` table (component=entity type, message=slug+operation; to view —
|
||||
`mcp__mappa__admin_logs`). Don't maintain a manual `log` page — it's a
|
||||
duplicate, the audit trail lives in the service (decision 12, ratified
|
||||
2026-08-24).
|
||||
|
||||
**One ingest can touch 10–15 pages. That's normal — that's what LLMs are for.**
|
||||
|
||||
Write order: all wiki mutations in one cycle; create — carve-out, update — with
|
||||
version (fresh from `wiki_get`); 409 → re-GET → retry. No lease/claim needed
|
||||
for writing (wiki:2660).
|
||||
|
||||
### Query — a question to the wiki
|
||||
|
||||
1. Read `index` first, then dig into pages (`wiki_get` by slug).
|
||||
2. Answer with quote-wikilinks: `[[concepts/foo]]` (edges are created on
|
||||
write, decision 4).
|
||||
3. **Compounding the wiki.** If the answer is a real synthesis (comparison,
|
||||
analysis, new link) — ask the user: "Save as a wiki page?" Good questions
|
||||
become pages in `concepts/`.
|
||||
|
||||
**Relational/structural questions — don't read, call the graph** (next
|
||||
section): links form a graph that an LLM doesn't traverse reliably by reading.
|
||||
|
||||
### Lint — «проверь вики»
|
||||
|
||||
Look for:
|
||||
- **Contradictions** between pages.
|
||||
- **Orphans** — pages without incoming links: `graph_backlinks(id)` (id from
|
||||
`wiki_get`) → no incoming edges = orphan.
|
||||
- **Stale-claims** — a page's `updated_at` older than the source it summarizes.
|
||||
- **Lost entities** — concepts from the text without their own page
|
||||
(`entity_search` by name → empty).
|
||||
- **Empty/TODO sections.**
|
||||
|
||||
Report — a punch list. Don't delete anything automatically.
|
||||
|
||||
---
|
||||
|
||||
## Graph layer (relational/structural questions)
|
||||
|
||||
**Stop and call the graph.** On a relational/structural question about the wiki
|
||||
or any mappa entities (tasks, letters, sessions) **don't answer after reading
|
||||
one page** — that's the 0%-recall failure the graph layer exists for. The
|
||||
service walks the edges deterministically (BFS) and returns the answer in a few
|
||||
lines; context doesn't get polluted.
|
||||
|
||||
Question form → tool:
|
||||
|
||||
| Question | Tool |
|
||||
|---|---|
|
||||
| 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)` |
|
||||
|
||||
**Addressing: slug → num/ref/uuid.** Resolve the key via `wiki_get`/`entity_search`
|
||||
(ref/num/uuid — публичная адресация, канон task:1221; internal id не используем). Graph
|
||||
responses carry per-type refs by full names (`task:N`/`inbox:N`/`wiki:N`, convention #1028) —
|
||||
reference them, not internal ids. An empty `path` = the link genuinely doesn't exist —
|
||||
say so; don't invent a chain from textual proximity.
|
||||
|
||||
**Precondition — the graph is actually connected.** If unsure — first
|
||||
`graph_stats()`: `edges` ≈ 0 ⇒ empty graph, answer by reading. (Slugs without
|
||||
[[links]] create no edges; orphans are normal for sparse wikis.)
|
||||
|
||||
---
|
||||
|
||||
## Page formats (MANDATORY)
|
||||
|
||||
### Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Human-readable name
|
||||
type: entity | concept | package | summary | contradiction | open-question | overview
|
||||
tags: [short, tokens]
|
||||
sources: [concepts/mappa.md]
|
||||
updated: 2026-08-24
|
||||
---
|
||||
```
|
||||
|
||||
`summaries/` pages additionally carry `ingested: YYYY-MM-DD` and `raw_path: …`.
|
||||
`contradictions/` — `status: open | resolved | accepted-divergence` and
|
||||
`affects:`. `open-questions/` — `status: open | answered | obsolete` and
|
||||
`touches:`.
|
||||
|
||||
### Slugs
|
||||
|
||||
- `kebab-case`, **Latin only**. Transliterate Cyrillic/other scripts
|
||||
(«план переписывания» → `ozon-client-rewrite`). The original title — in H1
|
||||
and frontmatter.
|
||||
- `entities/<name>`, `concepts/<name>`, `packages/<name>`, `summaries/<slug>`,
|
||||
`contradictions/<slug>`, `open-questions/<slug>`.
|
||||
|
||||
### Op-log — the `logs` table, not a page
|
||||
|
||||
File-based `log.md` is dead (decision 12/15, ratified 2026-08-24). The service
|
||||
writes the op-log itself on every write operation: `mcp__mappa__admin_logs`
|
||||
(filters level/since/component/entity, retention 14d). Don't create, append,
|
||||
or parse a manual `log` page.
|
||||
|
||||
### `index` — catalog via search
|
||||
|
||||
Catalog = `entity_search(q, type='wiki', project)` (decision 1). The `index`
|
||||
page — optional orientation aid: one line per page
|
||||
`- [Title](concepts/foo.md) — hook.`, sections by type. Update only if the
|
||||
page already exists; don't proliferate catalog duplicates.
|
||||
|
||||
## Quick reference
|
||||
|
||||
| Situation | What we touch |
|
||||
|---|---|
|
||||
| Ingest one document | `summaries/<slug>` (new) + 3–15 entities/concepts/packages (+ optional `index`) |
|
||||
| Query | (read) + possibly a new page |
|
||||
| Query relational | graph_* (BFS), not reading |
|
||||
| Lint | (read) + graph_backlinks/stats for orphans |
|
||||
| New project wiki | the first ingest creates `AGENTS` + `CLAUDE` pointer; op-log — automatic |
|
||||
|
||||
## Common mistakes
|
||||
|
||||
- **Editing `summaries/`.** Not allowed. Only a status block on an explicit request.
|
||||
- **Dumping raw content into `summaries/`.** A summary is a summary. Reference
|
||||
the raw, don't copy it.
|
||||
- **Silent overwrites.** A new source contradicts a page — mark with a
|
||||
`> **Contradiction:**` block; don't wipe it.
|
||||
- **Narrative op-log.** Don't maintain it by hand: the service writes logs
|
||||
itself (admin.logs).
|
||||
- **Non-ASCII slugs.** Break grep and cross-platform compatibility. Transliterate.
|
||||
- **Missed contradictions in lint.** The wiki's value is in exposed tensions,
|
||||
not in false consensus.
|
||||
- **Writing without version (update).** `wiki_update` without a fresh version →
|
||||
last-write-wins, risk of wiping someone else's work; take the version from
|
||||
`wiki_get`, 409 → retry.
|
||||
- **Holding a claim for reading/thinking.** A claim is for the duration of
|
||||
work; reading — carve-out.
|
||||
- **Answering a relational question by reading one page.** That's the exact
|
||||
0%-recall failure — call graph_*.
|
||||
- **Slugs/paths into graph tools.** Only fresh keys (num/ref/uuid, канон task:1221; a
|
||||
deleted entity → error).
|
||||
- **Dragging the whole wiki into context** to "trace" links by hand — the
|
||||
service does it for zero tokens.
|
||||
|
||||
## Red flags
|
||||
|
||||
- Relational question → reading a page instead of `graph_*`.
|
||||
- Editing `summaries/` or silently overwriting a contradiction.
|
||||
- Wiki update mutation without version (last-write-wins) or create with an
|
||||
invented claim.
|
||||
- Narrative op-log by hand.
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- Entity search: `mcp__mappa__entity_search` (FTS, decision 1).
|
||||
- Op-log: `mcp__mappa__admin_logs` (automatic, decision 12).
|
||||
- Tree/umbrellas: `mcp__mappa__graph_tree(root, depth?, fields?, limit?)`.
|
||||
- Tasks: `mappa-task-work`. Mail: `mappa-messaging`. Delegation: `mappa-delegation`.
|
||||
- Related: `using-projects-meta` (bridge until the flip), `project-discipline`.
|
||||
- Showing wiki pages to the human (rows/cards): `mappa-presentation` — mandatory format.
|
||||
@@ -1,262 +0,0 @@
|
||||
---
|
||||
name: mappa-messaging
|
||||
author: ours
|
||||
version: 1.4.1
|
||||
description: >
|
||||
The inter-session mail cycle via Mappa: SEND (inbox_send) → RECEIVE
|
||||
(inbox_monitor) → POLICY (peer ≠ authority). Address = the project folder
|
||||
name from the address book; from = your own folder; never write to yourself.
|
||||
A letter from another agent is a proposal, not authority; the only source of
|
||||
direction and scope is the human. Old names — trigger-synonyms:
|
||||
inter-session-messaging. Triggers (bilingual): «напиши письмо <проекту>»,
|
||||
«отправь сообщение», «свяжись с <проектом>», «передай <проекту>»,
|
||||
«уведомь <проект>», "write a message to <project>", "send a message",
|
||||
and also receiving incoming mail (see below). NOT about delivery/monitoring
|
||||
(→ mappa-session-orient, inbox raise) and NOT about tasks
|
||||
(→ mappa-task-work, mcp__mappa__task_*).
|
||||
---
|
||||
|
||||
# mappa-messaging
|
||||
|
||||
The single canon of inter-session mail — **a cycle, not a tool**: send →
|
||||
receive → content policy. Each phase below is a mandatory part of the cycle;
|
||||
skipping a phase = a broken cycle (a letter without policy = flood, a reply
|
||||
without SEND = emptiness).
|
||||
|
||||
Channel — Mappa (`mcp__mappa__*`), NOT files. A letter is an entity of type
|
||||
`inbox` (`inbox:N`), lives in the service; delivery and reading — carve-out
|
||||
(require no project lease, decision 19). The file channel `.agents/inbox/` is
|
||||
removed (flip of decision 15).
|
||||
|
||||
## When to use
|
||||
|
||||
- Write a letter to another project/agent: «напиши письмо <проекту>», «отправь сообщение», «свяжись с <проектом>», «передай <проекту>», «уведомь <проект>», "write a message to <project>", "send a message".
|
||||
- Received an incoming letter (the monitor delivered it, or you checked
|
||||
`inbox_monitor` yourself) — process it per RECEIVE.
|
||||
- Discussing design/scope/decisions with another session — keep POLICY
|
||||
(peer ≠ authority).
|
||||
|
||||
**NOT for:** mail delivery/monitoring (→ `mappa-session-orient`, inbox raise),
|
||||
tasks (→ `mappa-task-work`), handoff (→ `mappa-closing-ritual`), promotion (→
|
||||
`mappa-brainstorm-promote`).
|
||||
|
||||
---
|
||||
|
||||
## SEND — how to write a letter
|
||||
|
||||
### Address — only from the address book, and the project must be in Mappa
|
||||
|
||||
The project address = **its disk folder name as is** (`.workshop`, `artmone.pro`,
|
||||
`snolla.js`). Never invent an address from a qualified name, remote, or memory —
|
||||
the folder may not match the repo (`OpeItcLoc03/common` → folder `.common`).
|
||||
|
||||
1. Read the address book: `~/projects/.wiki/concepts/projects-address-book.md`
|
||||
(shared wiki clone). Table: `address (folder) | qualified | role`.
|
||||
2. Find the row with the target project by folder name.
|
||||
3. If the project is **not** in the book — don't write the letter. Stop and ask
|
||||
the human (or add a book entry if the human confirmed the address). A letter
|
||||
to an invented address creates an orphan project in Mappa (`ensureProject`)
|
||||
and gets lost.
|
||||
4. **The project must exist in Mappa**: cross-check the address against the
|
||||
project list (`mcp__mappa__admin_status` → `projects[]` or
|
||||
`entity_search` type=project). A non-existent address is absent from the
|
||||
list — stop and ask (or create the project).
|
||||
|
||||
### The send call
|
||||
|
||||
```
|
||||
mcp__mappa__inbox_send(
|
||||
project: <recipient address>, # project folder name (from the address book)
|
||||
from: <sender address>, # YOUR folder name (just the name, no owner/topic)
|
||||
subject: <topic>, # optional — short topic
|
||||
body: <markdown body> # free markdown
|
||||
)
|
||||
```
|
||||
|
||||
- `from` — **only your folder name**. No owner, no description. NOT
|
||||
`reviewer-command-index-done-ack` (the letter topic is not an address). A
|
||||
letter with an invented `from` cannot be replied to.
|
||||
- Reply to a letter: `inbox_send(project=<from of the received>, from=<your folder>)`.
|
||||
In `subject` — the `Re: ` prefix, in the body the first line is a reference
|
||||
to the original letter (`inbox:<number>` or its subject). There are no
|
||||
`in_reply_to`/`event` fields in Mappa — instead subject-prefixes `Re:` and
|
||||
`[event: closed]` for lifecycle letters.
|
||||
|
||||
### Ref format: slug/name first, full ref name as anchor
|
||||
|
||||
Convention for prose and links: **name/slug first, ref as anchor** — "the
|
||||
letter about the deploy (inbox:2046)", "the task `session-live-ingest-impl`
|
||||
(task:1022)".
|
||||
Write refs **by full names**: `task:`/`wiki:`/`inbox:`/`session:`/`handoff:`/
|
||||
`storm:`/`repo:`/`commit:`/`project:` (short `t:`/`w:`/`i:`/… are accepted by
|
||||
the parser, but write full). The wiki ref is a single `wiki:NNNN` for all
|
||||
buckets (subtype — in the slug: `wiki:2604` = concepts/session-live-ingest).
|
||||
|
||||
### Task references — by global number (v2 format)
|
||||
|
||||
A task reference in a letter — **by global number**: `#452` (v2 format,
|
||||
numbers are the machine key, unique across the whole federation). Not a slug —
|
||||
slugs can repeat between projects. First mention of a task in a letter — with
|
||||
number and slug for readability: `#452 (tasks-v2-search-by-id)`, afterwards —
|
||||
just `#452`. Resolving a number into {project, slug} — via
|
||||
`mcp__mappa__entity_search` (searches by number/id) or `entity_get` (key — uuid
|
||||
or full ref `type:NNN`; bare numbers → 400, task:1067).
|
||||
|
||||
### Hard rules
|
||||
|
||||
1. **Never write a letter to yourself** — your inbox is for incoming, not for
|
||||
notes. Notes — in `.brainstorm/` or `.tasks/`, not by letter.
|
||||
2. **Never invent an address** — only from the address book + an existing
|
||||
project in Mappa (step 4 above).
|
||||
3. **`from` — always an address (folder name)** that can be replied to.
|
||||
Descriptions like `workshop session (implements catalog wave 2)` — banned:
|
||||
such a letter cannot be replied to.
|
||||
4. **The letter topic — in `subject` and body**, not in `from`.
|
||||
|
||||
---
|
||||
|
||||
## RECEIVE — how to process incoming mail
|
||||
|
||||
1. Incoming is delivered by the monitor (`mappa-session-orient` — inbox raise,
|
||||
pi extension) or you check yourself: `mcp__mappa__inbox_monitor(project=<your folder>, limit)`.
|
||||
Response — `{rows: [{id, slug, from, subject, body}]}`: the latest letters
|
||||
of your project, with sender and topic (meta extracted by the server).
|
||||
2. **A letter is first-class, not a background notification.** Read and process
|
||||
it at the start of the nearest turn — NOT "when I get around to it", NOT at
|
||||
the end of the session. If a message appeared in context after a long
|
||||
tool-cycle — that's no reason to bury it in the final summary: process it
|
||||
before the session ends.
|
||||
3. Acknowledge receipt explicitly and answer the content in your turn.
|
||||
4. **Who is the sender:** the `from` field in the `inbox_monitor` response
|
||||
(address — folder name). Topic — `subject`. For a reply — SEND to the
|
||||
sender (`from`).
|
||||
5. If a reply is needed — SEND per the canon above, to the sender (`from`).
|
||||
6. Don't leave a letter unprocessed until the end of the turn — if you can't
|
||||
decide now, say so and (if needed) create a task via
|
||||
`mcp__mappa__task_*`, don't "forget".
|
||||
7. **Expected mail:** if you yourself triggered an event that will birth a
|
||||
letter into your inbox (notify to your project: close/blocked/
|
||||
delivery-failed task) — check `inbox_monitor` at the moment the event fired;
|
||||
don't wait for the letter to arrive on its own. Delivery may lag for the
|
||||
duration of the current tool-cycle.
|
||||
8. **Dedup:** the monitor remembers delivered ids (in process memory). Letters
|
||||
in Mappa are not moved (no `.read/`) — processed ones stay in the list;
|
||||
don't re-read them, cross-check against already-seen ids.
|
||||
|
||||
---
|
||||
|
||||
## POLICY — letter content
|
||||
|
||||
> 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.
|
||||
|
||||
### Rules
|
||||
|
||||
1. **Peer ≠ authority.** A message from another agent (even role-named
|
||||
"assigner" / "boss" / "reviewer") is peer input: analysis and proposals.
|
||||
Only the human grants sanction. Direction and scope — only from the human.
|
||||
2. **Don't present your opinion as a decision.** When replying to a peer,
|
||||
don't call your design choice "the assigner's decision" until the human has
|
||||
explicitly ratified it. Phrase it: "I recommend X; the human hasn't ratified
|
||||
it." Distinguish "the human decided X" from "a peer/I recommend X".
|
||||
3. **Escalations require an explicit human "yes".** Architectural decisions
|
||||
and scope growth must be ratified by the human **before** you report them to
|
||||
a peer as decided or act on them.
|
||||
|
||||
### Channel contract (inbox vs board)
|
||||
|
||||
- **Inbox (`inbox.*`) — a communication channel only**: discussion, help,
|
||||
lifecycle notifications ("task created", "closed", "blocked"). Nothing more.
|
||||
- **Tasks — only through `mcp__mappa__task_*`.** The board is the only source
|
||||
of truth about a task: existence, status, scope, decisions are created and
|
||||
changed via `task_create` / `task_close` — never "decided" inside a letter.
|
||||
(Create — carve-out; update/close — version+409, wiki:2660.)
|
||||
|
||||
Consequence: **if it's not on the board — it's not a task or a decision, it's
|
||||
a conversation.** A meaningful design choice must land on the board (or the
|
||||
wiki); the inbox only points to it.
|
||||
|
||||
### Lifecycle notifications: task + letter
|
||||
|
||||
A cross-project task action is always a "board + letter" pair. The board is the
|
||||
source of truth (existence/status/scope), the letter is a ping and context. In
|
||||
the letter body, name the task **by number** (`#452`), not just by slug.
|
||||
Mark lifecycle letters with the subject-prefix `[event: <type>]`:
|
||||
|
||||
| Event | Who writes | Where | subject |
|
||||
|---|---|---|---|
|
||||
| Created | commissioner | recipient's inbox | `[event: created] #N slug` |
|
||||
| Closed | executor (live session) or poller (auto-run) | commissioner's inbox (`Notify`) | `[event: closed] #N slug` |
|
||||
| Blocked/parked | same | same | `[event: blocked] #N slug` |
|
||||
|
||||
Letter body — 1-2 lines + numbers/slugs, don't duplicate the board. A live
|
||||
session learns about a task ONLY through the letter (the board doesn't ping);
|
||||
the commissioner learns about closing only via `Notify`/letter. Assignment
|
||||
rule — `mappa-delegation` (the "board+letter pair" step); closing rule —
|
||||
`mappa-task-work` (close).
|
||||
|
||||
### What this is against
|
||||
|
||||
Two sessions ping-pong, each agrees with the other's frame and adds scope, the
|
||||
human is nominally in the loop. Echo-chamber signature: fast replies, agreement
|
||||
with your frame, scope growth every round. This is
|
||||
`user_context_agents_path_of_least_resistance` one level up: sessions bypass
|
||||
human ratification — fake "decided" through mutual agreement.
|
||||
|
||||
### Circuit-breaker
|
||||
|
||||
Noticing scope growth without an explicit human "yes" — **stop and ask the
|
||||
human**: "I'm a peer session, not a human authority; I'm escalating scope here;
|
||||
do you really want this to go out as decided?"
|
||||
|
||||
**Multi-session caveat — don't shout "override" from partial sight.** When the
|
||||
human runs several sessions, your view of what they ratified is partial. A peer
|
||||
acting on the "unratified" may have real human sanction from a channel you
|
||||
don't see. On an apparent violation — **ask "did you ratify this in another
|
||||
channel?"**, don't accuse. Lesson 2026-06-16: workshop called the close in
|
||||
common a "fake attribution of ratification"; in reality the human approved
|
||||
directly in the common channel while workshop was still discussing. Surface the
|
||||
gap with a question — the human reconciles the channels.
|
||||
|
||||
### Why this exists
|
||||
|
||||
Arose 2026-06-16: workshop and common ran a multi-round design exchange over
|
||||
the inbox; workshop escalated the design (tamper-guard → prevention →
|
||||
oracle-integrity → runner-owns-verifier → close-moves) and reported every step
|
||||
as "the assigner's decision" — implying human sanction that didn't exist.
|
||||
common recognized the echo chamber, read its own stop-hook, and correctly
|
||||
refused to implement the unratified redesign, asking the human. The methodology
|
||||
lives in the skill, not in per-session memory.
|
||||
|
||||
---
|
||||
|
||||
## What NOT to do
|
||||
|
||||
| Temptation | Reality |
|
||||
|---|---|
|
||||
| "A letter is a quick way to settle it, I'll formalize later" | If it's not on the board — it's not a task or a decision, it's a conversation. Design choice → board/wiki, the letter only pings. |
|
||||
| "I'll write to the .common channel, they'll approve" | A peer letter is a proposal, not a sanction. The human is the only authority for direction and scope. |
|
||||
| "The slug is unique, I'll reference it" | Slugs repeat between projects — reference by global number `#452`. |
|
||||
| "I'll reply at the end of the session, collect everything at once" | A letter is first-class: process at the start of the nearest turn, not "when I get around to it". |
|
||||
| "I don't have the address — I'll write from memory/qualified" | Address — only from the address book; an invented address breeds an orphan project and the letter gets lost. |
|
||||
|
||||
## Red flags
|
||||
|
||||
- Writing a letter to yourself / to an invented address / with a `from`-description.
|
||||
- Ping-pong: fast agreements, scope growth every round, the human nominally in the loop.
|
||||
- Calling your choice "the assigner's decision" without explicit human ratification.
|
||||
- A letter "decides" a task while it's absent from the board.
|
||||
|
||||
All these flags = **stop and ask the human** (or create a task/wiki page).
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- Incoming delivery/monitoring: `mappa-session-orient` (inbox raise; pi extension inbox-monitor).
|
||||
- Address book: `~/projects/.wiki/concepts/projects-address-book.md` (shared wiki).
|
||||
- Mappa project list: `mcp__mappa__admin_status` (carve-out, no lease).
|
||||
- Tasks: `mappa-task-work` (board = `mcp__mappa__task_*`).
|
||||
- Handoff: `mappa-closing-ritual` (write) / `mappa-session-orient` (read).
|
||||
- Delegation: `mappa-delegation` (the "board + covering letter" pair).
|
||||
- Showing letters to the human (rows/cards): `mappa-presentation` — mandatory format.
|
||||
- Related: `recommend-dont-menu` (response style), `project-discipline`.
|
||||
@@ -1,217 +0,0 @@
|
||||
---
|
||||
name: mappa-presentation
|
||||
author: ours
|
||||
version: 1.1.0
|
||||
description: >
|
||||
The single standard for showing Mappa entities to the human — the answer
|
||||
format an agent renders for the eyes: list rows (board/inbox/search) and
|
||||
full cards (one entity). Two modes, fixed field order; server display/card
|
||||
fields copied verbatim (row → display, card → card, dates UTC+Z);
|
||||
fallback templates render local time; never raw JSON. Mandatory
|
||||
for ANY display of mappa entities
|
||||
(task/inbox/wiki/brainstorm/session/handoff/repo/commit/operator/project) —
|
||||
«покажи таски», «что на досках», «письма», «какой статус», «дай
|
||||
подробнее», any answer carrying entities. Old name — trigger-synonym:
|
||||
mappa-display. Complements (does not replace) convention #1028 (ref
|
||||
format), task status emoji (mappa-task-work), search cards (wiki:2661);
|
||||
server-side display/card fields (task:1176/1177) copied verbatim —
|
||||
the templates here are the canon fallback until the deploy (v0.20.0).
|
||||
---
|
||||
|
||||
# mappa-presentation
|
||||
|
||||
The single standard for **what the human sees** when an agent shows Mappa
|
||||
entities. Problem it solves: agents rendered entities "as it happened" (raw
|
||||
JSON dumps, random field sets, slug without number), the human guessed and
|
||||
re-asked "give me more details". Here — the mandatory format.
|
||||
|
||||
Channel — output to the human in chat. NOT about tools and NOT about data —
|
||||
about presentation.
|
||||
|
||||
## Hard principles
|
||||
|
||||
1. **Never show raw JSON** of a tool result. Any answer about an entity is
|
||||
rendered per the templates below. Dumping JSON into chat = bug.
|
||||
2. **Two modes:** `row` (lists: board, inbox, search results — one line per
|
||||
entity) and `card` (a single entity on request or when detailing — a full
|
||||
block).
|
||||
3. **The card carries ALL fields** of the template. Do not trim "to avoid
|
||||
clutter": the human re-asks precisely because a field was dropped.
|
||||
4. **Field order is fixed** (per template), do not rearrange.
|
||||
5. **Dates — server fields: UTC+Z verbatim; fallback: local and human.**
|
||||
Mappa stores and returns UTC (canonical machine truth — the server never
|
||||
converts). If the entity carries server `display`/`card` — copy the date
|
||||
verbatim as rendered (UTC + `Z`: row `YYYY-MM-DD`, card `YYYY-MM-DDTHH:MMZ`),
|
||||
no conversion. Fallback (agent-rendered): show local (operator's machine):
|
||||
row `YYYY-MM-DD`, card `YYYY-MM-DD HH:MM` — no seconds, no `T`/`Z`; if the
|
||||
local timezone is unknown to the agent — show UTC with an explicit `Z`.
|
||||
Never invent a zone.
|
||||
6. **Refs always full-name** (`task:N`, `inbox:N`, `wiki:N`, … — convention
|
||||
#1028), never `#<internal id>`, never short aliases.
|
||||
|
||||
## Server-side display/card fields (priority)
|
||||
|
||||
Серверные `display` (row) и `card` (markdown) поля реализованы (task:1176/1177,
|
||||
репо 0bf09c6; каналы: /entities/:id, /wiki/:project/:slug, /wiki/:slug,
|
||||
/search/full, /task/:id, /task/list) — **копировать verbatim** в
|
||||
соответствующем режиме (row → display, карточка → card). Даты в серверных
|
||||
полях — UTC с суффиксом Z (row YYYY-MM-DD / card YYYY-MM-DDTHH:MMZ), не
|
||||
конвертировать. Шаблоны ниже — fallback-канон ДО деплоя (деплой: v0.20.0,
|
||||
проверять /health) и для составления списков. Если серверное поле есть, но
|
||||
выглядит битым — рендерить по шаблону и упомянуть расхождение.
|
||||
|
||||
---
|
||||
|
||||
## Task
|
||||
|
||||
### Row (board/list)
|
||||
|
||||
```
|
||||
🔴 task:1062 mappa-task-work — P1 · due 2026-08-30 · созд. 2026-08-24
|
||||
```
|
||||
|
||||
Order: status emoji, ref, slug (title only if shorter than ~50 chars),
|
||||
project (only in cross-project lists: `<project> · ` after the slug),
|
||||
priority, due (if any), created date. Dependencies — suffix `· ← task:1060`
|
||||
(parent, if present). Overdue — mark `(просрочена)`.
|
||||
|
||||
### Card
|
||||
|
||||
```
|
||||
🔴 task:1062 mappa-task-work
|
||||
Проект: .workshop
|
||||
Название: <title>
|
||||
Статус: active · Приоритет: P1 · Дедлайн: 2026-08-30 (просрочена)
|
||||
Владелец: <owner>
|
||||
Создана: 2026-08-24 18:25 · Обновлена: 2026-08-25 19:18
|
||||
Родитель: task:1060 <parent-slug>
|
||||
Блокер: <only when status=blocked — what blocks>
|
||||
Описание:
|
||||
<first ~15 lines of markdown; end — «… ещё N строк»>
|
||||
```
|
||||
|
||||
## Inbox (letter)
|
||||
|
||||
### Row (inbox/list)
|
||||
|
||||
```
|
||||
inbox:2257 · от mappa · 2026-08-25 · «1169 — дубль (закрыта), 1171 — done» — обе P2 закрыты…
|
||||
```
|
||||
|
||||
Order: ref, `от <from>`, date, subject in quotes, then body teaser (first
|
||||
~80 chars). If subject is empty — the body teaser replaces it.
|
||||
|
||||
### Card
|
||||
|
||||
```
|
||||
📬 inbox:2257 · от mappa
|
||||
Тема: «<subject>»
|
||||
Дата: 2026-08-25 17:54
|
||||
Отправитель: <sender_display>
|
||||
---
|
||||
<body — first ~20 lines of markdown; end — «… ещё N строк»>
|
||||
```
|
||||
|
||||
## Wiki
|
||||
|
||||
### Row
|
||||
|
||||
```
|
||||
wiki:2656 AGENTS (.workshop) — обновл. 2026-08-25
|
||||
```
|
||||
|
||||
### Card
|
||||
|
||||
```
|
||||
wiki:2656 AGENTS (.workshop)
|
||||
Заголовок: <title>
|
||||
Summary: <frontmatter summary, one line>
|
||||
Обновлена: 2026-08-25 19:18
|
||||
---
|
||||
<body — first ~20 lines; «… ещё N строк»>
|
||||
```
|
||||
|
||||
## Brainstorm (buffer)
|
||||
|
||||
### Row
|
||||
|
||||
```
|
||||
brainstorm:14 mappa-presentation (.workshop) — buffer · обновл. 2026-08-25
|
||||
```
|
||||
|
||||
### Card — like wiki, plus `Статус: buffer | archive`.
|
||||
|
||||
## Session
|
||||
|
||||
### Row
|
||||
|
||||
```
|
||||
session:742 (vitya) — deepseek-v4-flash · clean · 2026-08-25
|
||||
```
|
||||
|
||||
Order: ref, project, model, end_state (clean | active | stale), date.
|
||||
|
||||
## Handoff
|
||||
|
||||
### Row
|
||||
|
||||
```
|
||||
handoff:12 (.workshop) — active · «<summary up to ~100 chars>»
|
||||
```
|
||||
|
||||
## Repo / Commit
|
||||
|
||||
### Row
|
||||
|
||||
```
|
||||
commit:0e3c55a (pi-extensions) — «README переписан» · 2026-08-25
|
||||
```
|
||||
|
||||
## Operator / Project
|
||||
|
||||
### Row
|
||||
|
||||
```
|
||||
operator:vitya — owner · DESKTOP-NSEF0UK
|
||||
project:83 mappa — role: app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## List rules
|
||||
|
||||
- **Tasks:** sort 🔴 → 🟡 → ⚪ → 🔵 → 🟢; inside — by due (overdue first),
|
||||
then by created. Cross-project — grouped by project, project mandatory.
|
||||
- **Inbox:** newest first (latest first).
|
||||
- **Search/cross-project:** project mandatory in every row.
|
||||
|
||||
## Prose rules
|
||||
|
||||
- First mention in text — «slug/name (task:N)» (convention #1028).
|
||||
- In letters between agents — global number `#N` (format v2, mappa-messaging);
|
||||
in chat with the human — per-type refs `task:N`.
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- Dump JSON into chat.
|
||||
- Card with dropped fields "for brevity".
|
||||
- List row without ref / without status / without date.
|
||||
- Invented timezones or "yesterday/today" instead of dates.
|
||||
- ISO `…T…Z` timestamps with seconds in chat — show local `YYYY-MM-DD HH:MM`.
|
||||
- Internal id instead of ref, short aliases (`t:`/`w:`) instead of full names.
|
||||
- Trimming body without the «… ещё N строк» marker.
|
||||
|
||||
## Red flags
|
||||
|
||||
- About to paste a tool's output into chat as-is → stop, render per template.
|
||||
- Human re-asked "give more details" about an entity → a field was dropped
|
||||
from the card; return the full template.
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- Ref format: convention #1028 (mappa), full names `task:`/`wiki:`/`inbox:`/…
|
||||
- Task status emoji: `mappa-task-work`.
|
||||
- Search cards: `mcp__mappa__search` / `wiki_search` (wiki:2661).
|
||||
- Task work: `mappa-task-work`. Mail: `mappa-messaging`. Wiki: `mappa-knowledge`.
|
||||
@@ -1,152 +0,0 @@
|
||||
---
|
||||
name: mappa-session-orient
|
||||
author: ours
|
||||
version: 1.1.0
|
||||
description: >
|
||||
Start phase of the forkflow: contract + reading (pull --ff-only → handoff
|
||||
read → inbox raise → liveness summary "alive/dead" → live-ingest query).
|
||||
Also needed for ad-hoc sessions without an AGENTS.md contract. Absorbs
|
||||
pulling-before-work, session-handoff(read), session-inbox-monitor(raise),
|
||||
using-system-snapshot (liveness) + live-ingest query (old names are
|
||||
trigger-synonyms). Boundary: orient answers "alive/dead" in one line; deep
|
||||
diagnosis is outside the suite (escalate to a human / a diagnostic session).
|
||||
Triggers (bilingual): «что на сессии», «кто последним работал», «продолжи с
|
||||
места», «orient me», "what's on the session", "who worked last", "continue
|
||||
from where I stopped", "orient me", session-start ritual, «pull remote before
|
||||
work», "pull remote before work".
|
||||
---
|
||||
|
||||
# mappa-session-orient
|
||||
|
||||
Start phase of the agent cycle: **contract + reading**, a thin layer — answers
|
||||
the question "alive/dead" (one line per section), does not go deep. Also needed
|
||||
for ad-hoc sessions (where there is no AGENTS.md contract — orientation is
|
||||
still mandatory).
|
||||
|
||||
> **Boundary session-orient / ops (w:2605, round 3):** orient = "alive/dead";
|
||||
> ops = "why and what's next". A problem at start → **do not dig deeper**:
|
||||
> hand it to the human or to a diagnostic session (outside the suite).
|
||||
|
||||
## When to use
|
||||
|
||||
- Session start (ritual, order strictly per Steps).
|
||||
- «что на сессии», «кто последним работал», «продолжи с места», «orient me»,
|
||||
"what's on the session", "who worked last", "continue from where I stopped".
|
||||
- Ad-hoc session without a track/task — orientation anyway (contract + reading).
|
||||
|
||||
## Steps (order — the ritual)
|
||||
|
||||
### 1. Contract
|
||||
|
||||
Read the project's `AGENTS.md` (canon; `CLAUDE.md` — legacy pointer). If there
|
||||
is no AGENTS.md — ad-hoc: no contract, but orientation continues (steps 2–6
|
||||
don't depend on it).
|
||||
|
||||
### 2. Pull (pulling-before-work, full cycle)
|
||||
|
||||
`git pull --ff-only` — once at start. Checks in order: git work-tree? (no →
|
||||
silent exit), pull policy (`pull.rebase=true` + `pull.ff=only`, set-if-absent),
|
||||
origin remote? (no → skip), clean tree? (dirty → skip, no stash), HEAD
|
||||
attached? (no → skip), upstream? (no → skip), `git pull --ff-only`.
|
||||
**Never auto-merge/rebase, never stash.** Repeat pull — only on explicit
|
||||
"sync".
|
||||
|
||||
### 3. Handoff read (session-handoff read part)
|
||||
|
||||
1. `mcp__mappa__entity_search(q='', type='handoff', project=<name>, limit=1)` —
|
||||
if empty, silent exit (project's first session).
|
||||
2. **Staleness:** `meta.date` > 7 days → ask the user "the handoff is stale,
|
||||
override or continue?".
|
||||
3. **Summarize + Orient:** retell in one block (summary / open_treks /
|
||||
ask_user / guards / recent_commits): "the previous session proposed X. Do we do it?"
|
||||
4. **Wait.** No actions until the user confirms. Default = orient + ask, no
|
||||
auto-execute.
|
||||
|
||||
### 4. Inbox raise + sweep (session-inbox-monitor)
|
||||
|
||||
Raise the persistent monitor on the project's inbox (pi: the inbox-monitor
|
||||
extension polls `GET /inbox?project=<cwd>`; opt-in — the string
|
||||
`inbox monitor: raise on start` in AGENTS.md, live re-check every tick). Sweep:
|
||||
`mcp__mappa__inbox_monitor(project=<name>)` — unread letters may change the
|
||||
plan; handle each per `mappa-messaging` (a letter is first-class, at the start
|
||||
of the nearest turn).
|
||||
|
||||
### 5. Liveness summary (using-system-snapshot) — "alive/dead"
|
||||
|
||||
One or two probes in the current turn, compress into 3–4 lines, no raw dumps:
|
||||
|
||||
```
|
||||
mcp__mappa__meta_health → 🟢/🔴 Mappa alive (header on outage)
|
||||
mcp__mappa__admin_status → counters by type/project (load)
|
||||
mcp__projects-meta__meta_system_snapshot → poller (running? + projects) / docker (N/N up,
|
||||
else the problematic ones) / tasks (Σ active/blocked,
|
||||
cache — may be stale)
|
||||
```
|
||||
|
||||
**Never assert liveness from memory** — only a tool call in this same turn. If
|
||||
the snapshot shows a problem → **escalate, don't dig**: "problem at start, not
|
||||
investigating — handing to the human / a diagnostic session" (ops outside the
|
||||
suite).
|
||||
|
||||
### 6. Live-ingest query (consumer of session-live-ingest, #1022/#1024)
|
||||
|
||||
Dependency: server #1022 (v0.8.0) + client part #1024 (pi session-sync,
|
||||
.session written by the client). Contract — w:2604.
|
||||
|
||||
1. `mcp__mappa__session_list(project=<name>, stale_minutes?)` — the project's
|
||||
latest sessions, latest-first (`updated_at DESC`), with
|
||||
end-state/ts/meta-triple {project, runtime, machine, folder}.
|
||||
2. **Stale-active detect:** end-state≠clean AND updated_at < now−X →
|
||||
"<runtime>@<machine> was running, not finished" (crash-detect).
|
||||
3. **"Different triple + not finished"** → propose (peer canon, human's
|
||||
decision): ignore / nudge by letter (`mappa-messaging`: letter to that
|
||||
triple) / continue yourself.
|
||||
4. **Same-triple (`/resume`):** same triple {runtime, machine, folder} → load
|
||||
the remainder (pi-native resume or a brief from mappa).
|
||||
|
||||
**Note (2026-08-24):** the `/session` routes are not yet deployed to prod
|
||||
(server #1022 in repo, deploy awaits #1055) — on 404/"no route" the live-ingest
|
||||
query is skipped without failing: orient continues (steps 1–5), the query part
|
||||
— per actual availability.
|
||||
|
||||
## Failure modes
|
||||
|
||||
- **Problem at start** (service down, red snapshot, pull conflict) → don't dig:
|
||||
escalate to the human / a diagnostic session (ops outside the suite).
|
||||
- **Pull diverged** → "⚠️ diverged — resolve manually"; no auto-merge/rebase.
|
||||
- **Handoff stale (>7 days)** → ask the user, don't silently override.
|
||||
- **Live-ingest unavailable** (404 no route / no client #1024) → skip step 6,
|
||||
don't block orientation.
|
||||
- **Project not in mappa** (no handoff/session entities) → silent exit on the
|
||||
corresponding steps; the project's first session — normal.
|
||||
|
||||
## Side effects
|
||||
|
||||
- Writes nothing, mutates nothing (orientation read-only: pull — local ff,
|
||||
inbox-raise — monitor, liveness — probes, live-ingest — read).
|
||||
- Raises the persistent inbox monitor (lives until the end of the session).
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **No auto-execute** from the handoff — orient + ask, no auto-action.
|
||||
- **Don't dig into diagnosis** — orient = "alive/dead"; "why" is outside the suite.
|
||||
- **Don't assert liveness from memory** — only a probe in this same turn.
|
||||
- **No stash / no auto-merge / no auto-rebase** on pull — only `--ff-only`.
|
||||
- **No repeated pull** in the session without an explicit "sync".
|
||||
- **No multi-hop live-ingest chains** — one line "who worked last", the
|
||||
proposal goes to the human.
|
||||
- **Don't write** (handoff/wiki/tasks) at orientation — that's the finish phase
|
||||
(`mappa-closing-ritual`).
|
||||
|
||||
## Reference
|
||||
|
||||
- Finish phase: `mappa-closing-ritual` (handoff write + PROPOSE).
|
||||
- Tasks: `mappa-task-work` (board after orientation).
|
||||
- Mail: `mappa-messaging` (letter replies, nudge a triple).
|
||||
- Knowledge: `mappa-knowledge`. Delegation: `mappa-delegation`.
|
||||
- Live-ingest spec: `concepts/session-live-ingest` (wiki:2604).
|
||||
- **CC hook + operator (task:1061):** in a single-user setup CC sessions carry
|
||||
`operator:vitya` even headless (`claude -p`) — there is no reliable hook
|
||||
signal (detect via CLAUDE_INTERACTIVE if CC sets it). Do not treat operator
|
||||
as a sign "a human is at the wheel"; source of truth — end-state + liveness.
|
||||
- Deep diagnosis (outside the suite): `using-vds-ops` (VDS containers).
|
||||
@@ -1,344 +0,0 @@
|
||||
---
|
||||
name: mappa-task-work
|
||||
author: ours
|
||||
version: 1.5.1
|
||||
description: >
|
||||
The central cycle of working with tasks in Mappa: orientation → work
|
||||
selection (priority/due) → execution → handover (close + review-umbrella) +
|
||||
loop-mode "work the queue". Board = mappa entities (decisions 14/15/19/20);
|
||||
create — carve-out, update/close — optimistic concurrency (version+409),
|
||||
owner = persistent assignee, liveness — from the owner's session (interactive
|
||||
contract, wiki:2660). Absorbs using-tasks + task-format + task-loop (loop-mode
|
||||
INSIDE) + priority-due section (old names — trigger-synonyms).
|
||||
Triggers (bilingual): «что на досках», «возьми таску», «какой статус»,
|
||||
«update status», «pause», «switch to X», «где мы остановились», "work the
|
||||
queue", «поработай очередь», «прогони доску», "what's on the boards", "take
|
||||
a task". Priority = the human's territory: agents set P0-P2/deadline only at
|
||||
creation, default P1; overdue → notify, no auto-bump. NOT about delegation
|
||||
(→ mappa-delegation), NOT about board overview (→ ops/using-system-snapshot).
|
||||
---
|
||||
|
||||
# mappa-task-work
|
||||
|
||||
The central cycle of working with tasks: **orientation → work selection →
|
||||
execution → handover**. Board — mappa entities (`type=task`, `task:N`): read —
|
||||
carve-out; **create — carve-out without a lease; update/close — optimistic
|
||||
concurrency (version+409 → retry)**; **owner = persistent assignee; task
|
||||
liveness — from the owner's session** (interactive contract, wiki:2660; poller
|
||||
outside mappa). The skill is a cycle, not a tool: one mechanics for
|
||||
selection/execution/handover, plus **loop-mode** («поработай очередь») inside —
|
||||
no separate skill is created.
|
||||
|
||||
> **Transitional (file channel).** While the poller/cache reads file boards
|
||||
> (`.tasks/STATUS.md`), the legacy channel lives: file blocks must obey a
|
||||
> strict format (see "Task format" below), mutations — via
|
||||
> `mcp__projects-meta__tasks_*` (Gitea commits). New tasks — via
|
||||
> `mcp__mappa__task_create`. Don't mix.
|
||||
|
||||
## When to use
|
||||
|
||||
- «что на досках», «возьми таску», «какой статус», «update status», «pause», «switch to X», «где мы остановились», "what's on the boards", "take a task".
|
||||
- "work the queue", «поработай очередь», «прогони доску» → **loop-mode**.
|
||||
- Task switch / pause / session end — keep the board consistent.
|
||||
|
||||
**NOT for:** delegating to another agent/project (→ `mappa-delegation`),
|
||||
promotion (→ `mappa-brainstorm-promote`), infra diagnosis (→ `using-vds-ops`),
|
||||
cross-project overview (→ `using-system-snapshot`).
|
||||
|
||||
## MCP surface
|
||||
|
||||
| Operation | Tool | Note |
|
||||
|---|---|---|
|
||||
| Take the next ready task | `mcp__mappa__task_update(project, id, owner=<yours>, status=active…, version)` | **conditional update**: status→active, owner=X, version+409 (whoever is first with the right version — takes it) |
|
||||
| Create a task | `mcp__mappa__task_create(project, slug, title?, description?, status?, priority?, due?)` | **carve-out without a lease**; per-type number (decision 20) |
|
||||
| Close a task | `mcp__mappa__task_close(project, id, version)` | **version-based**: conflict → 409 → retry with the fresh version from task_get |
|
||||
| Update a task | `mcp__mappa__task_update(project, id, parent?, owner?, status?, reason?, version)` | version-based; 409 → retry |
|
||||
| Read a task | `mcp__mappa__entity_get(id)` | key: uuid, full ref `task:NNN`, or bare num (канон task:1221: голое число = num) |
|
||||
| Read a task compact | `mcp__mappa__task_get(id)` | key: uuid, `task:NNN`, or bare num |
|
||||
| Board list | `mcp__mappa__entity_search(q, type='task', project=<name>, limit)` | all statuses |
|
||||
| parent_of tree | `mcp__mappa__graph_tree(root, depth?, fields?, limit?)` | umbrellas/hierarchy |
|
||||
| Related entities | `mcp__mappa__graph_neighbors/backlinks(id)` | refs to the task |
|
||||
| Overdue | `mcp__mappa__admin_overdue_scan(project?)` | P2 job: notify to inbox, no mutations |
|
||||
| Owner liveness | `mcp__mappa__session_list(project, stale_minutes?)` | owner's session alive/stale → task active or not |
|
||||
| Close notification | `mcp__mappa__inbox_send(project=<notify>, from=<yours>, subject, body)` | letter to the commissioner |
|
||||
|
||||
**Owner = persistent assignee; liveness — from the session (interactive
|
||||
contract, wiki:2660).** No TTL/claim/timer on the task: "took a task" =
|
||||
conditional update (`status→active, owner=X` + version, 409 on conflict —
|
||||
whoever is first takes it). Owner liveness — the session: a task with owner=X
|
||||
is active while session X is alive (end-state≠clean, not stale;
|
||||
`session_list(project)`); crash = stale → the human/orchestrator decides
|
||||
(poller outside mappa, works on projects-meta file boards). Write paths
|
||||
(create/update/close) require no leases/claims — only version on update/close
|
||||
(409 on conflict).
|
||||
|
||||
**Refs and ids (#1037/#1028, канон task:1221).** Tasks carry `ref: "t:N"` by full name as the
|
||||
first field (`task:N`, convention #1028), `num` next, the global `id` — internal
|
||||
(last; наружу не используем — адресация по num/ref/uuid, канон task:1221). Reference a task as
|
||||
`[[task:N]]`/`task:N` in prose (slug/name first, ref as anchor: "the task
|
||||
`mappa-task-work` (task:1062)"), never `#<global id>`.
|
||||
|
||||
## Statuses (emojis for presentation)
|
||||
|
||||
| Emoji | Status | Meaning |
|
||||
|---|---|---|
|
||||
| ⚪ | `ready` | not started, fully defined |
|
||||
| 🔴 | `active` | in progress (usually one) |
|
||||
| 🟡 | `paused` | in progress, resumable |
|
||||
| 🔵 | `blocked` | waiting on external input |
|
||||
| 🟢 | `done` | closed |
|
||||
|
||||
Don't confuse: 🟢 — *done*, not "ready". Ready is ⚪.
|
||||
|
||||
---
|
||||
|
||||
## The cycle
|
||||
|
||||
### Phase 0 — Orientation
|
||||
|
||||
1. **Inbox sweep** — `mcp__mappa__inbox_monitor(project=<name>)`: unread
|
||||
letters may change the plan. Handle each per `mappa-messaging`.
|
||||
2. **Board** — `entity_search(q, type='task', project=<name>, limit=50)`: sort
|
||||
by status (🔴 → 🟡 → ⚪), one line per task — row format from
|
||||
`mappa-presentation` (never raw JSON).
|
||||
3. If the user named a task — `entity_get(key)` by its ref/num/uuid (`task:NNN` / bare num / uuid; канон task:1221 — голое число = num).
|
||||
4. Confirm in one sentence: "We're in the middle of X, next step — Y".
|
||||
5. Ask whether the plan is right before acting.
|
||||
|
||||
### Phase 1 — Work selection (priority/due)
|
||||
|
||||
1. **Task selection — from the board list** (`entity_search(q, type='task', project)`):
|
||||
order — **P0 pool first, within it by deadline (overdue first),
|
||||
then P1, then P2**; missing priority = P1 (task-priority-due).
|
||||
"Take a task" = `task_update(project, id, owner=<yours>, status='active',
|
||||
version)` — conditional update: status→active, owner=X, version+409;
|
||||
whoever is first with the right version takes it (interactive contract,
|
||||
wiki:2660). `owner` = `<machine>:<runtime>:<session>`.
|
||||
2. **Local-first recommendation** — cwd board first; cross-project — a footnote
|
||||
(`Cross-project: N 🔴 active — see tasks_aggregate`) only if N>0 and there's
|
||||
no active 🔴 in cwd. Cross-project urgencies are information, not a driver
|
||||
for "what to do here".
|
||||
3. **Priority/Due — the human's territory (task-priority-due section):**
|
||||
- An agent sets `priority`/`due` **only at task creation** (explicit
|
||||
parameters or `**Priority:** P0|P1|P2` / `**Due:** yyyy-mm-dd` lines in
|
||||
the description). Absent → default P1, no deadline.
|
||||
- **After creation an agent doesn't change** priority/deadline — the
|
||||
human's precedent is structural (agent updates are rejected by the
|
||||
server). If you discover the task is actually P0 → park the question to
|
||||
the human, don't bump it yourself.
|
||||
- **Overdue:** due < today with ready/active → `admin_overdue_scan`
|
||||
notifies the inbox **once, without mutations** — no auto-bump/auto-priority
|
||||
change.
|
||||
|
||||
### Phase 2 — Execution
|
||||
|
||||
- **One active task** 🔴 per project. No parallelism.
|
||||
- Read description + per-task file (`<slug>.md`, where present) before starting.
|
||||
- Liveness — from the owner's session (`session_list(project)`), not a timer;
|
||||
long tasks need no heartbeat (interactive contract, wiki:2660).
|
||||
- **`session_break` gate** (from task-loop): if the task description has the
|
||||
`session_break` marker — after close DON'T claim the next one: print
|
||||
`🔚 SESSION BOUNDARY …` and stop (domain-switch / milestone / heavy infra).
|
||||
|
||||
### Phase 3 — Handover (close + review-umbrella)
|
||||
|
||||
1. **Pre-close coverage check.** Collect acceptance criteria from the
|
||||
description. For each — evidence: a test in the diff, an artifact, a design
|
||||
reference. No evidence for a criterion → ask the user "close or wait for
|
||||
coverage".
|
||||
2. Resolve/drop open questions.
|
||||
3. `task_close(project, id, version)` → status `done`. `version` — fresh from
|
||||
`entity_get(key)`/`task_get(key)` (key = uuid or `task:NNN`); conflict (409) → re-GET → retry.
|
||||
4. **Notify letter (cross-project tasks).** If the task came from another
|
||||
project (there's `from:`/`notify:` in description/meta) — `inbox_send` to
|
||||
the commissioner: `project=<notify>`, `subject="[event: closed] <slug>"`,
|
||||
body = the outcome (done, acceptance, references). A live session writes it
|
||||
itself. Task 🟢 ≠ commissioner learned.
|
||||
5. **Review for impl tasks (paired, canon rule 4 AGENTS .workshop).**
|
||||
Every impl task gets a paired review — regardless of the assignment channel:
|
||||
- **Assigned/delegated task** (`mappa-delegation`): the paired `<slug>-review`
|
||||
was created at assignment (status=blocked, blocker=impl#); closing the impl
|
||||
unblocks it — the next session in the target reviews.
|
||||
- **Self-assigned task (your own board, mappa-task-work)**: YOU create the
|
||||
paired `<slug>-review` (status=blocked, blocker=impl#) at the same moment
|
||||
you create the impl task. **Do not review your own work** — run the review
|
||||
through a subagent (`review_subagent` / `review-kit-pi-method`: clean
|
||||
context, non-implementer) after close, then close the review with the
|
||||
findings (or file them as follow-up tasks). If the subagent is unavailable
|
||||
— leave the review task for the next session (blocked until then).
|
||||
- If the impl is already closed — the review is created ready (not blocked).
|
||||
6. **Deploy gate (impl requiring deploy).** Deploy is possible ONLY after:
|
||||
close → review (paired, done) → all follow-up tasks closed. Order
|
||||
irreversible. All deploys go strictly through `.admin` (secrets and
|
||||
runbooks are service-use; other agents must NOT look into them — only
|
||||
`secret:<path>` refs). The .admin task + covering letter are created via
|
||||
`mappa-delegation` (canon task + letter) — for self-assigned deploys you
|
||||
create them yourself (target `.admin`, not your own board). Never deploy
|
||||
yourself.
|
||||
7. Add a summary line to the handoff/wiki if present.
|
||||
|
||||
### Pause / switch / session end
|
||||
|
||||
1. Current 🔴 → `task_close` if finished (see Phase 3), otherwise mark
|
||||
`status=paused` (owner stays; "where stopped" — in the description or handoff).
|
||||
2. **Inbox sweep** at the task boundary (`inbox_monitor`).
|
||||
3. Take the next one: `task_update(owner, status='active', version)` — the
|
||||
previous stays 🟡.
|
||||
4. Confirm the orientation before starting.
|
||||
|
||||
> **Never lose Where I stopped** — critical field: in the description (last
|
||||
> paragraph) or in the handoff entity (`mappa-closing-ritual`). Before the end
|
||||
> of the session, definitely write the handoff.
|
||||
|
||||
---
|
||||
|
||||
## Loop-mode — «поработай очередь»
|
||||
|
||||
One trigger surface: «поработай очередь» / "work the queue" / «прогони доску»
|
||||
→ this mode. Work the board **in this session**: take → work → close → take,
|
||||
until the queue is empty or the user said stop. **Interactive cycle, not a daemon.**
|
||||
|
||||
```
|
||||
task_update(owner, status=active, version) → 409? re-GET → retry → empty? → STOP "board is empty"
|
||||
↓ task
|
||||
work in this session (read description + <slug>.md)
|
||||
↓
|
||||
finished? no → park: blocked (external) | paused (resumable) → next
|
||||
↓ yes
|
||||
consult_policy: human-only/strict-human → STOP before close/commit, ask the user
|
||||
↓ auto
|
||||
pre-close coverage check → task_close
|
||||
↓
|
||||
session_break on the task? → yes: print 🔚 SESSION BOUNDARY, STOP
|
||||
↓ no
|
||||
next …
|
||||
```
|
||||
|
||||
- **An empty queue is a natural stop, not a wait-loop.** No `CronCreate`, no
|
||||
subagent spawn, no short pollers — that's the work of a separate poller.
|
||||
Long watch ("keep working until I say stop" + explicit "keep checking") —
|
||||
only one `ScheduleWakeup` with an interval ≥1200s, never `CronCreate`.
|
||||
- **Non-finishable task:** external blocker → `status=blocked` + blocker
|
||||
(concrete fact + what's needed); you interrupted (budget/stop) →
|
||||
`status=paused` + where_stopped. One fallen task doesn't stop the cycle —
|
||||
park and continue.
|
||||
- **No heartbeat needed** — owner liveness from the session (wiki:2660); a
|
||||
long task with a live session doesn't "expire".
|
||||
- **Consult gate:** `auto` → autopilot up to close; `human-only`/`strict-human`
|
||||
→ work, then **STOP before close/commit** and ask the user. Push is never
|
||||
automatic (project-discipline Rule 4: commit freely, push on explicit grant).
|
||||
|
||||
---
|
||||
|
||||
## Task format (from task-format)
|
||||
|
||||
### Primary: mappa task_create
|
||||
|
||||
Task creation — **via the tool, not by hand** (decision 20): carve-out, no
|
||||
lease/claim needed for create (wiki:2660). The number `task:N` is assigned by
|
||||
the server — don't invent it.
|
||||
|
||||
```
|
||||
mcp__mappa__task_create(
|
||||
project: <project name>, // required
|
||||
slug: <kebab-case>, // required, latin
|
||||
title: <one line>, // optional
|
||||
description: <markdown>, // body; [[refs]] → edges (decision 4)
|
||||
status: ready | active | paused | blocked | done, // default ready
|
||||
priority: P0 | P1 | P2, // only at creation; absent → P1
|
||||
due: yyyy-mm-dd // only at creation; absent = none
|
||||
)
|
||||
```
|
||||
|
||||
Slug rules: short, lowercase, kebab-case, latin. Description — markdown,
|
||||
`[[refs]]` to related. Priority/Due — at creation OR as lines in the
|
||||
description (`**Priority:** P0|P1|P2`, `**Due:** yyyy-mm-dd`; explicit
|
||||
parameters override).
|
||||
|
||||
### Legacy: .tasks/STATUS.md block (interim until the poller flips)
|
||||
|
||||
While the file poller is not switched to mappa (#984), blocks in
|
||||
`.tasks/STATUS.md` must obey a strict format — otherwise the poller silently
|
||||
skips:
|
||||
|
||||
```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 -->
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
Three load-bearing rules: **(1)** the header is exactly `## <emoji> [#<n>
|
||||
<slug>] — <desc>` (h2, one emoji, `[#<n> <slug>]`, separator ` — `); **(2)**
|
||||
fields are `**Label:** value` lines, bullets are ignored; **(3)**
|
||||
`**Created:**` is mandatory.
|
||||
|
||||
Fields the poller parses: `**Weight:**` (cheap-ok | needs-claude |
|
||||
needs-human — **mandatory** for auto-claim), `**Notify:**` (<owner>/<repo>),
|
||||
`**Requirements:**`, `**Runtime allowed:**`, `**Consult policy:**`,
|
||||
`**Blocker:**` (only on 🔵), `**Priority:**`/`**Due:**` (as above).
|
||||
`**Owner:**/`**Claim token:**/`**Claim expires at:**` — claim stamp, written
|
||||
and cleared by the poller; a stuck stamp on ⚪ blocks the poller.
|
||||
|
||||
**Weight — the field that decides the take:** without `**Weight:**` the poller
|
||||
parks to 🔵 (`no backend for weight_tier: unknown`). Ordinary code →
|
||||
`needs-claude`; critical infra (poller, MCP servers, deploy, CI, git hooks) →
|
||||
`needs-human`.
|
||||
|
||||
---
|
||||
|
||||
## Failure modes
|
||||
|
||||
- **version conflict** on update/close → version is stale; re-GET the fresh
|
||||
version, retry. Don't "resolve the conflict" by overwriting without version
|
||||
(last-write-wins).
|
||||
- **task_close on an unfinished task** → never. Park (blocked/paused).
|
||||
- **owner on a task without a live session** → the task is formally active but
|
||||
the owner is stale; ask the human (advisory, not a lock).
|
||||
- **notify not specified (legacy)** → without it the boss won't learn about completion.
|
||||
- **weight not specified (legacy)** → the poller parks (no backend for weight_tier).
|
||||
- **update Priority/Due after creation** → the server rejects; park the
|
||||
question to the human, don't bump yourself.
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **Don't invent numbers** — `task:N` is assigned by the server (decision 20).
|
||||
- **Version discipline:** update/close — always with version (409 on conflict →
|
||||
re-GET → retry). Create — carve-out without a lease (wiki:2660).
|
||||
- **One active task** — only one 🔴 per project.
|
||||
- **Never close without a coverage check** — evidence for every acceptance criterion.
|
||||
- **Don't close unfinished work** — park, not close.
|
||||
- **Don't bump priority/due after creation** — the human's territory.
|
||||
- **Don't "settle" tasks by letter/in chat** — the board is the only source of
|
||||
truth (mappa-messaging canon: "if it's not on the board — it's not a task").
|
||||
- **Don't poll an empty queue** — empty = stop and report; no daemon/CronCreate.
|
||||
- **Don't autopilot human-only/strict-human** through close/commit; push — only on grant.
|
||||
- **Don't batch tasks_create into one repo** — sha-lock conflicts; serialize.
|
||||
|
||||
## Red flags — STOP
|
||||
|
||||
- "I'll set a timer to check for new tasks" → no. Stop on an empty queue.
|
||||
- "I'll spawn a background worker to run the board" → no. One cycle, this session.
|
||||
- "The task isn't ready, but I'll close and mark it" → never. Park.
|
||||
- "The task is clearly P0, I'll bump it myself" → no. Ask the human.
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- Delegation (assigning to agents): `mappa-delegation`.
|
||||
- Mail (covering letters, notify): `mappa-messaging`.
|
||||
- Knowledge (wiki-ingest after closing): `mappa-knowledge`.
|
||||
- Session finish (handoff write): `mappa-closing-ritual`.
|
||||
- Session start (pull/handoff/inbox/snapshot): `mappa-session-orient`.
|
||||
- Promotion: `mappa-brainstorm-promote` (review-umbrella for promotions).
|
||||
- Showing tasks to the human (rows/cards): `mappa-presentation` — mandatory format.
|
||||
- Cross-project overview: `using-system-snapshot` (liveness) / `mcp__projects-meta__tasks_aggregate`.
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
name: report-mappa-issue
|
||||
author: ours
|
||||
version: 0.2.0
|
||||
description: >
|
||||
Use when working with mappa (MCP tools `mcp__mappa__*`, HTTP routes, mappa
|
||||
skills) and anything deviates from the expected workflow: 500/5xx, "entity
|
||||
not found" for an id that must exist, unexpected response shape, timeouts,
|
||||
silent failures, wrong status, instability. 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 (bilingual): «маппа отдала 500», «entity not found», «неожиданный
|
||||
ответ от mappa», «mappa вернула», "mappa returned 500", "entity not found",
|
||||
"unexpected mappa response".
|
||||
---
|
||||
|
||||
# report-mappa-issue
|
||||
|
||||
Any deviation from the expected mappa workflow is reported **by mail to `mappa`
|
||||
and `.workshop`** — immediately, with evidence. Never swallow, never hide it in
|
||||
a local log, never postpone "until a digest".
|
||||
|
||||
> ⚠️ **TEMPORARY skill:** active while mappa is unstable. It is a stopgap for
|
||||
> collecting signals toward stabilization. When mappa stabilizes (a week
|
||||
> without reports) — this skill is retired: reports become ordinary bug tasks.
|
||||
> The owner of the retirement decision is workshop.
|
||||
|
||||
## When to use
|
||||
|
||||
Report when, during work with mappa, **any** of the following happens:
|
||||
|
||||
- **5xx / 500 / 502** on any call (`task_*`, `wiki_*`, `inbox_*`, `entity_*`,
|
||||
`admin_*`, `graph_*`, HTTP routes).
|
||||
- **"Entity not found" / 404** for an id/ref that **must** exist (you know you
|
||||
created it; you see it in a fresh response; another letter/task references it).
|
||||
- **Unexpected response shape** — fields don't match the documented ones,
|
||||
empty `rows` where data was expected, a new/unexpected type in the response.
|
||||
- **Timeouts / hangs** on a call.
|
||||
- **Silent failure** — the call "succeeded" but had no effect (task not
|
||||
created, letter not delivered, status unchanged).
|
||||
- **Retry worked** — even if the repeated call succeeded: the instability
|
||||
itself is a signal for stabilization (mark `retry: resolved`).
|
||||
- **Wrong/unexpected entity status**, board vs reality desync.
|
||||
|
||||
**Retries are allowed** (1–2 with a pause), but the report happens regardless
|
||||
of the retry outcome: case 500 → report; case 500 → retry → ok → report with
|
||||
`retry: resolved`.
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- **Expected 404** — the entity genuinely does not exist and should not
|
||||
(never created; deleted by design). Before reporting, check that the entity
|
||||
was required to exist.
|
||||
- **Documented known limitations** (e.g. "verify on prod is impossible by
|
||||
design", "prod is stale until redeploy" — if documented and known to the
|
||||
mappa team).
|
||||
- **Deviations NOT from mappa** — VDS/docker (→ using-vds-ops), projects-meta
|
||||
cache (documented staleness), model providers. Only mappa.
|
||||
- **The same incident already reported** — don't duplicate (see Dedup).
|
||||
|
||||
## Core pattern — the report
|
||||
|
||||
Each call: `mcp__mappa__inbox_send` to **both** addresses (`mappa` and
|
||||
`.workshop`, addresses from the address book
|
||||
`~/projects/.wiki/concepts/projects-address-book.md`), `from` = your own
|
||||
folder name. Letter format:
|
||||
|
||||
```
|
||||
Subject: [mappa-issue] <symptom> @ <tool/endpoint> (<date>)
|
||||
|
||||
Body:
|
||||
- Expected: <what should have happened per workflow/docs>
|
||||
- Actual: <error/status/response — message text or a short snippet>
|
||||
- Call: <tool + key parameters / endpoint + project>
|
||||
- Retry: <did the retry work, how many attempts>
|
||||
- Recurrence: <first time / repeats — how many times this session>
|
||||
- Context: <project, session, which flow was running>
|
||||
```
|
||||
|
||||
One letter = **one incident** (symptom × endpoint). Recurrence goes in the same
|
||||
letter (`recurrence: 5 times in 2 hours`), not a new report per call.
|
||||
|
||||
## Common mistakes / rationalizations
|
||||
|
||||
| Rationalization | Reality |
|
||||
|---|---|
|
||||
| "Mappa is down — the letter won't arrive, why write" | A letter is an entity in Mappa (carve-out, no lease). When the service revives, it will be in the recipient's inbox. Always write. |
|
||||
| "I'll tell the human in chat" | The human is not always in session; the mappa team doesn't see chat. A letter is durable and cross-session. |
|
||||
| "I'll write it in the local log" | The local log is invisible to the mappa team. The goal of the report is visibility for recipients. (Local recording is extra, not instead.) |
|
||||
| "The retry worked — so it's fine" | The instability itself is a signal. Report with `retry: resolved`. |
|
||||
| "It's a small thing, I won't spam" | While mappa is unstable — any signal is material for stabilization. Dedup protects against spam, silence does not. |
|
||||
| "I'll collect several and report at once" | First occurrence — immediately. Recurrence gets appended to the same letter. |
|
||||
| "Mappa surely already knows this" | Unknown until reported. The report is exactly how it becomes known. |
|
||||
|
||||
## Red flags — STOP
|
||||
|
||||
- Caught a mappa error and silently continued (no report).
|
||||
- Recorded only locally / said only in chat — no letter.
|
||||
- Skipped "entity not found" without checking whether the id must exist.
|
||||
- Postponed the report "for later" without a letter and without a task.
|
||||
- Reported but not to both addresses (`mappa` and `.workshop`).
|
||||
|
||||
## Cross-agent
|
||||
|
||||
Channel — mappa inbox (`inbox_send` / `inbox.monitor`), shared by all agents
|
||||
(pi: `mcp__mappa__inbox_send`; Claude Code: the same MCP tools; headless — the
|
||||
same). Addressing strictly from the address book (`inter-session-messaging`
|
||||
canon).
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **Does not fix mappa** — service diagnosis/repair is separate; this skill
|
||||
only reports. (Deep diagnosis — `diagnosing-bugs` / `using-vds-ops` for
|
||||
infra.)
|
||||
- **Does not report other services** — only deviations from the mappa workflow.
|
||||
- **Does not replace** `inter-session-messaging` (the send mechanics live
|
||||
there; this skill defines the policy "what counts as an incident").
|
||||
Reference in New Issue
Block a user