manager · diff
git:20260826.2055336 to git:20260917.75a2929
802 added, 182 removed. Audit A to A.
---
name: manager
description: >-
- Sync session work into GitHub issues, or query track status across repos. Write: find/update issue
- + W-label. Read: "что по <track>". Triggers: "создай issue", "синкни сессию", "manager". Not
- day/week plans (daily-tasks).
+ Use when need to sync session work into GitHub issues OR query status of an
+ existing track across repos. Two modes — write (end-of-session sync: find
+ issues, update body, work-record comment, parent epic + W-label + Project
+ placement, and clean closed tasks from active day/week plans) and read
+ (status lookup across repos with parent/W-label/Project health). Fits the
+ corp-doctor / weekly-planning / weekly-retro operating cycle. Triggers on
+ "/manager", "sync session", "обнови issues", "синкни сессию",
+ "зафиксируй прогресс", "статус задачи", "что по <track>", "есть ли issue по",
+ "track status", "what about <track>".
disable-model-invocation: true
---
- # Manager — двусторонний мост между сессией и GitHub issues
+ # Manager — bidirectional GitHub issues bridge
- ## Железные инварианты — читать первым, повторять перед каждым синком
+ Part of the Personal Corp framework — running a one-person business through AI agents.
- **1-3 обязательны для любого issue, который трогает manager. 4-5 добавляются для активного issue текущей недели. 6-9 действуют в режиме записи и при закрытии.**
+ Bridges session work and GitHub issues in both directions. GitHub issues are the source of truth for tasks; a GitHub Project board is the source of truth for what's active. Manager has two modes:
- 1. **W-label** — текущая неделя, будущая неделя или дата конкретной менторской сессии. Нет в репо — создать.
- 2. **Родительский эпик** — ровно один parent через GitHub Sub-issues API. Всё, что не эпик само, имеет parent. Подробно: [reference/parent-epic-rules.md](reference/parent-epic-rules.md).
- 3. **Трек различается по title + членству в эпике** — track-labels (`x26-bloom`, `ai-native-s2` и т.п.) больше не заводим.
- 4. **Project placement** — активный issue текущей недели стоит на канонической GitHub Project-доске своего слоя и в глобальном недельном Project `ris © corp` / Project `#4`. W-label без Project placement = `Расхождение Project`.
- 5. **Родитель виден в Project** — для активного child одного `parent_issue_url` мало. Видимый parent/root эпик тоже должен быть в нужном Project view с непустой status lane.
- 6. **Комментарий-запись о работе** (режим записи, только при РЕАЛЬНОЙ работе по issue) — GitHub-комментарий в таймлайне: что сделано + ссылки на коммиты. Смена status/label/Project placement его **не заменяет**. Чисто механический re-label или Project-fix — **без** комментария.
- 7. **Дробность задач: никакого чат-журнала** — если по треку появилось больше одного самостоятельного следующего шага или founder говорит, что за ходом тяжело следить, не превращать один issue в длинный журнал. Parent/track issue держит короткий канон: `Status`, `Next issues`, `Decisions`. Исполняемые шаги выносить в отдельные child/sibling issues под тем же эпиком — с W-label, Project placement и понятным критерием готовности.
- 8. **Чек-лист закрытия** — закрывать issue можно, только когда: (а) нерешённые развилки и секция «Открыто» из тела перенесены в отдельный открытый issue; (б) каждый follow-up с датой вписан в `tasks/WNN/<дата>.md` своей даты; (в) параллельные открытые issues того же контура закрыты комментом-указателем «продолжение в #N» либо оставлены открытыми с причиной.
- 9. **Переход «нетронута → In progress» и запись предложений/драфтов в issue** — при создании задача находится в статусе `Backlog` / Untouched (не тронута). Как только по задаче появилось первое предложение, черновик текста, драфт поста, спецификация или решение:
- - Статус задачи (в Project и body) **ОБЯЗАТЕЛЬНО переводится в `In progress`**.
- - Само подготовленное предложение/драфт/спецификация **записывается прямо в тело задачи** (в `## Proposed draft / solution` или `## Updates`), чтобы наработки и варианты не терялись в чате сессии.
+ 1. **Write mode (sync)** — at end of session: read what was done, find existing issues, update with progress + a work-record comment, keep parent / W-label / Project invariants, create new only if nothing matches.
+ 2. **Read mode (query)** — anytime: «what about track X?», «status of Y?» → search across your repos, return condensed state of matching issues with parent epic, labels, Project placement, and last activity.
- **Если родительского эпика нет ни в одном репо** — вынести в предложение founder'у: создать новый или выбрать существующий, **до** синка.
+ **Manager is the canonical issue workflow.** Do not fall back to a generic issue helper for these operations — manager owns the read-modify-write contract, the invariants, and the Project sync.
- **ВАЖНО:** не использовать generic-скиллы `github-issues` / `gh-issues`. Manager сам является каноническим workflow.
+ ## Public distribution boundary
- ---
+ Keep this skill reusable: owner, repositories, paths, board IDs and routing come from the user’s local Manager Config. Never bundle session logs, customer examples, private repository references, or a copy of a personal installation.
- ## Выбор режима
+ ## Setup
- **Режим записи:** founder сказал «синкни сессию», «зафиксируй», «обнови issues», ИЛИ вызвал `/manager` без аргументов в конце сессии.
+ Before first use, define this in your project's `AGENTS.md` (preferred) or `CLAUDE.md` (compatibility). If the project has no agent config yet, run `corp-doctor` to create or repair it.
- **Режим чтения:** founder спросил о состоянии — «что по», «статус», «есть ли», «какие issues по».
+ ```markdown
+ ## Manager Config
- **Режим среды (денежный gate):** «/manager midweek», «mid-week gate», «среда-чек», ИЛИ автозапуск по расписанию в среду утром. Агент инициирует сам, founder не просит. По умолчанию ничего не пишет в GitHub, но цель не статус-справка, а раннее предупреждение по денежным обещаниям недели — пока неделя ещё не сгорела.
+ ### GitHub owner
+ Your GitHub username or org for issue search:
+ - owner: your-github-handle
- **Голый `/manager`:** вывести артефакты из текущего разговора. Не просить founder'а перечислять всё заново. Составить короткий план исполнения (5-15 строк) и сразу выполнить — постоянное разрешение действует.
+ ### Repos to scan (cross-repo issue search scope)
+ List repos manager should search:
+ - ~/Projects/main
+ - ~/Projects/ops
+ - ~/Projects/marketing
- **Manager НЕ используется для:** идей без артефактов (это брейншторм); закрытия issue без явной команды founder'а; **пакетных обновлений CRM** — это CRM-процессы в репо `crm`, не manager.
+ ### Tasks index file (optional)
+ Path to your curated current-week index. Manager reads it FIRST before any `gh search` to scope queries:
+ - tasks_index: ~/docs/tasks.md
+ (если файла нет — manager работает без индекса, поиск идёт по всем repos)
- Подробный алгоритм обоих режимов: [reference/modes-read-write.md](reference/modes-read-write.md).
+ ### Tasks directory (optional)
+ Path to day/week plan files created by weekly-planning:
+ - tasks_dir: ~/docs/tasks/
- ---
+ ### Domain → repo routing
+ | Domain | Repo |
+ |--------|------|
+ | commercial / B2B deals | crm |
+ | product launches | main |
+ | ops / infrastructure | ops |
+ | content | marketing |
- ## Постоянное разрешение на запись
+ ### GitHub Projects integration
+ Manager treats Project placement as an invariant (see Iron invariants). Declare your boards:
+ - weekly_project: <number> # cross-repo "everything active this week" board
+ - weekly_project_owner: your-github-handle
+ - status_field: Status # the single-select field that holds the lane
+ - status_in_progress: In progress # option name (or id) for the active lane
+ - domain_projects (optional): # per-domain boards, if you keep them
+ | Domain | Project number |
+ | commercial | <number> |
+ | product | <number> |
- Founder подтвердил: GitHub-записи manager'а разрешены по умолчанию. После тихой преднастройки и короткого плана исполнять точечные GitHub-записи **не спрашивая** отдельное «подтверди».
+ Cache resolved field/option IDs here once discovered (`gh project field-list <N> --owner OWNER --format json`) so manager doesn't re-fetch them every run.
- Покрыто: правки body, комментарии-записи о работе (инвариант 6), создание W-label, привязка parent/sub-issue, Project placement, статус `In progress` на затронутых активных issues, assignee `@me` (founder) по умолчанию, правки дневного плана в `tasks/WNN/YYYY-MM-DD.md`, создание issue, когда эпик, репо и рамка очевидны.
+ ### W-label convention (optional)
+ - enabled: true
+ - format: W{NN} (ISO week)
+ (если false — manager создаёт issues без weekly labels)
- Спрашивать только когда: нет подходящего эпика; неясно, чей это репо или трек; риск приватности в публичном репо; разрушительные или массовые изменения; закрытие issue, чья рамка явно не выполнена.
+ ### Standing write authorization
+ - mode: ask-each-time | execute-after-plan
+ (default: ask. execute-after-plan = manager executes writes after showing the brief plan, without separate confirmation)
- ---
+ ### CRM integration (optional)
+ - crm_path: ~/Projects/crm
+ - crm_pointer_format: [[<slug>]]
+ (если не используется — секция игнорируется; см. CRM integration ниже)
+ ```
- ## Преднастройка (ЖЁСТКОЕ ПРЕДУСЛОВИЕ)
+ `corp-doctor` is the bootstrap/repair skill for this config. Title-type metadata is NOT configured here: it lives in labels, the parent tree, and Projects (see Issue title convention).
- **Выполнить до ЛЮБОЙ команды `gh search`, `gh issue` и прочих GH-вызовов.** Бюджет вывода в чат: 0 строк. Полный алгоритм: [reference/search-algorithm.md](reference/search-algorithm.md) → «Pre-flight».
+ ## Iron invariants
- 1. **Прочитать `~/Documents/obsidian/0_hq/tasks.md` ПЕРВЫМ** — это курируемый индекс: Project ID, активные треки, указатели на репо. Без него поиск бьёт наугад.
- 2. Снять снимок Project #4: `gh project item-list 4 --owner serejaris --format json --limit 1000 > /tmp/manager-proj4.json` (один раз за прогон; `--limit 1000` обязателен).
- 3. **Страж дрифта HQ** — если активная задача в `tasks.md` без `repo#N`, вывести `Расхождение HQ tasks`.
- 4. Тихо проверить git status; показать только незакоммиченные артефакты, названные в сессии.
- 5. Вычислить ISO-неделю, если `tasks.md` устарел.
+ Every issue manager touches MUST satisfy the base three; an active / current-week issue must additionally satisfy the Project and work-record invariants:
- **Красный флаг:** собираешься запустить `gh search issues`, не прочитав `tasks.md` — СТОП.
+ 1. **W-label** (current or future week, or the date of a specific dated event) — if W-label convention enabled in config. If the label doesn't exist in the repo — create it.
+ 2. **Parent epic** — exactly one parent via GitHub Sub-issues API. Any issue that isn't itself an epic must have a parent. See "Parent epic rules" below.
+ 3. **Track differentiation via title + epic membership** — no track-labels (`<track-slug>`, `<client>-deal`). Track is recognized by title text and epic membership.
+ 4. **Project placement** — an active / current-week issue must be present on its domain Project board (if you keep one) AND on the global weekly Project. A W-label without Project placement = `Project drift`.
+ 5. **Project-visible parent** — for an active / current-week child, one `parent_issue_url` is not enough. The visible root epic must itself be in the relevant Project view with a non-empty status lane.
+ 6. **Work-record comment** — in write mode, only when REAL work happened on the issue this session: a mandatory timeline comment summarizing what was done + commit links. Changing status / label / Project placement does NOT replace it. Pure mechanical re-label / Project-fix with no content work = no comment.
- ---
+ Without these — the issue isn't tracked correctly. If no parent epic exists in any repo — manager raises this in proposal and offers to create or pick an existing one, **before** sync. Never leaves orphan issues.
- ## Где правда
+ ## Mode resolution
- | Нужно | Источник |
- |---|---|
- | Текущая неделя, активные треки | `~/Documents/obsidian/0_hq/tasks.md` (читать ПЕРВЫМ) |
- | Сегодняшний план | `tasks/WNN/YYYY-MM-DD.md` + `tasks/WNN/README.md` |
- | Отдельные задачи | GitHub issues в `serejaris/*` |
- | Люди, компании, деньги | `~/Documents/GitHub/crm/` — ставить указатель `[[crm-slug]]`, не переносить детали |
+ ```dot
+ digraph mode {
+ "User invocation" [shape=box];
+ "Has session artifacts to sync?" [shape=diamond];
+ "WRITE mode" [shape=box];
+ "READ mode" [shape=box];
- ---
+ "User invocation" -> "Has session artifacts to sync?";
+ "Has session artifacts to sync?" -> "WRITE mode" [label="yes — update issues by what was done"];
+ "Has session artifacts to sync?" -> "READ mode" [label="no — query like 'what about X', 'status Y'"];
+ }
+ ```
- ## Project ID (реестр констант)
+ **Signal for write mode:** user said «sync session», «зафиксируй», «обнови issues», OR invoked `/manager` without args at end of session, OR explicitly listed artifacts/changes.
- | Project | number | project-id |
- |---|---|---|
- | `ris © corp` | 4 | `PVT_kwHOCisBXs4BCN8O` |
- | `Менторство 1-на-1` | 14 | `PVT_kwHOCisBXs4BQrb1` |
- | `Кружок Вайбкодинга` | 28 | `PVT_kwHOCisBXs4BR41f` |
- | `Colder — корпоративное обучение` | 31 | `PVT_kwHOCisBXs4BT5Hs` |
- | `Спортмастер — корпоративное обучение` | 38 | `PVT_kwHOCisBXs4Bec7S` |
- | `Personal Corp` | 34 | `PVT_kwHOCisBXs4BVZDi` |
- | `Школа Вайбкодинга` | 5 | `PVT_kwHOCisBXs4BDKxF` |
- | `Personal Corp Course Launch` | 10 | `PVT_kwHOCisBXs4BP8bu` |
+ **Signal for read mode:** user asked a question about state — «what about», «status», «есть ли», «какие issues по».
- Status option IDs (ris © corp #4): Backlog = `f75ad846`, Ready = `08afe404`, **In progress = `47fc9ee4`**, In review = `4cc61d42`, Done = `98236657`. Status field id: `PVTSSF_lAHOCisBXs4BCN8Ozg0fml0`. Time field id: `PVTF_lAHOCisBXs4BCN8OzhVKHhI`.
+ **Bare `/manager` invocation:** infer artifacts from current conversation context — what tracks were touched, what files were modified/created, what decisions were made. Do NOT ask user to re-list everything. Form brief execution plan (5-15 lines), then execute under the configured authorization mode.
- **Доска #31 — только Colvir.** Спортмастер на неё не кладём (решение founder'а, 2026-07-25); он живёт на доске #38 с полем «Трек»: field id `PVTSSF_lAHOCisBXs4Bec7SzhY3CWI`, опции Product G1 = `a0a5e557`, Strategy = `2ed89da4`, Договор и закупка = `099b1185`. Status field id `PVTSSF_lAHOCisBXs4Bec7SzhY3CSM` (Todo `f75ad846`, In Progress `47fc9ee4`, Done `98236657`). Треков пока два — Product G1 и Strategy; process analysts треком не считается, пока не подтверждён.
+ **Do NOT use manager for:** creating ideas without artifacts (that's brainstorming); closing an issue without explicit user instruction; batch CRM updates (that's a CRM skill, not manager).
- **Опции single-select не удалять через `updateProjectV2Field`** — мутация пересоздаёт опции с новыми id и обнуляет значения на всех items. Если удаление всё же нужно: снять снимок значений до, удалить, переназначить по новым id.
+ ## Output language
- **Смысл лейнов (конвейер):** Backlog — спеки ещё нет; Ready — спека в теле готова к исполнению; In progress — у исполнителя; In review — на приёмке; Done — приёмка пройдена. Агент, продолжающий работу после рестарта или компакции, восстанавливает состояние конвейера с доски Project #4 и из тел issues, а не из истории чата.
+ Output language matches the user's input language and project conventions. Technical tokens remain as-is and are not translated: issue names (`<repo>#<N>`), labels (`W18`, `retro:W17`, `backlog`), commands (`gh issue comment`), file paths, original English titles of issues in quotes.
- Полные field ID других досок и команды — [reference/search-algorithm.md](reference/search-algorithm.md) → «Project evidence commands».
+ ### Issue-title language
- ## Дисциплина Project API
+ New issue titles (and renamed titles) follow the user's locale — match the language convention of the project. English is allowed only as a proper noun: product name, repo name, brand, API name, public upstream term (`GitHub`, `Telegram`, `LMS`, `PRD`, `E2E`). English action verbs and generic filler phrases in titles are forbidden:
- Для доказательств по Project и смены статусов путь по умолчанию — issue-scoped GraphQL.
+ - ❌ `delivery track`, `launch/funnel`, `follow-up`, `workshop prep`, `handoff`, `rollout package`, `topic TBD`, `date TBD` (as English filler when the project language is not English)
- - `gh project item-list` — только там, где этот скилл прямо его называет (снимок Project #4 в преднастройке).
- - Любое другое чтение Project — сначала батч-GraphQL по нужным issues, поле `projectItems`.
- - Перед любым `gh project item-edit` подтвердить живым issue-scoped GraphQL: issue существует, Project item существует, текущая lane, целевой Project и lane.
- - Если rate limit не даёт получить это доказательство — остановить Project-синк и сообщить `Project lane pending: rate limit`.
+ All narrative elements in issue titles, body headers, and proposal text follow the project's locale. Technical tokens (`repo#N`, label names, CLI commands, file paths, quoted original titles of existing issues) stay as-is.
- **Красный флаг:** собираешься запустить `gh project item-list <domain-project>` до батч-чтения состояния issues — СТОП. Сначала GraphQL `projectItems`.
+ ## Sources of truth (read every run)
- ---
+ 1. **`$TASKS_INDEX_PATH`** (if configured) — current week index. Source for: what's hot this week, what tracks are active, repo pointers for each track. Read FIRST to frame the session.
+ 2. **`$TASKS_DIR/WNN/YYYY-MM-DD.md`** (if configured) — current day plan. Source for: what the founder is actually doing today. Manager may patch it during write sync when touched issues change state.
+ 3. **GitHub issues across `$YOUR_OWNER/*`** — authoritative for individual tasks. Search via `gh search issues --owner $YOUR_OWNER` or batched GraphQL (see below).
+ 4. **GitHub Project board(s)** — authoritative for what's active this week and in which lane.
+ 5. **CRM artifacts** (if CRM integration enabled in config) — meeting cards, opportunity cards, person cards. NOT a substitute for a GH issue, but the linkage anchor: every comm-related issue body must include a CRM pointer.
- ## Маршрутизация по доменам
+ ### Planning / retro cycle
- | Домен трека | Где живёт эпик |
- |---|---|
- | Поток школы (Кружок) | `serejaris/teach-vibecoding` (канон маршрутизации: скилл `multi-repo-initiatives`) |
- | Образовательная программа / партнёрство | `teach-vibecoding` / `teach-personal-corp` |
- | Менторство / сессия | teaching-репо, issues сессий `S<N>` |
- | B2B сделка | `serejaris/crm` |
- | Продуктовый запуск | репо самого продукта |
- | Research | `serejaris/research-corp` |
+ Manager participates in the cycle, it does not replace it:
- Полный алгоритм выбора эпика по доменам: [reference/parent-epic-rules.md](reference/parent-epic-rules.md) → «Resolve epic».
+ - `weekly-retro` reviews the closing week, resolves carry-over, and produces evidence-backed outcomes/backlog.
+ - `weekly-planning` curates `tasks.md`, `tasks/WNN/README.md`, and day plans for the new week.
+ - `manager` keeps GitHub issues, Projects, parents, W-labels, work-record comments, and touched day-plan rows consistent during actual work.
- Слои менторства: отношения и деньги → CRM/ledger; обзор трека → issue в teaching-репо; сессия `S<N>` → отдельный issue; delivery → child issue под `S<N>`.
+ When a manager sync changes task state, it must keep the visible plan aligned with that state. If manager closes an issue, the closed issue must not remain as an active P0/P1 row in the current day plan or week index.
- Для Кружка (поток, урок, запуск, воронка, bot/funnel, публикации для учеников) **сначала загрузить** `templates/kruzhok-product-task-hierarchy.md`, потом синкать. Детальная иерархия → [reference/kruzhok-hierarchy.md](reference/kruzhok-hierarchy.md).
+ ## When to use vs when NOT
- ---
+ **Use (write mode):**
+ - User says "sync session" / "/manager" / "обнови issues по тому что сделал"
+ - End of working session with concrete artifacts (CRM updates, meeting cards, code commits, docs)
- ## Формула заголовка issue
+ **Use (read mode):**
+ - Start or middle of session — user asks «what about <track>», «status», «is there an issue for»
+ - Need cross-repo state of a track without manually grepping
+ - Before deciding next step — check what's already open
+ **Do NOT use:**
+ - For creating new ideas without artifacts — use brainstorming
+ - For closing issues without explicit user instruction (see Common mistakes)
+
+ ## Pre-flight (both modes) — HARD PRECONDITION
+
+ Pre-flight MUST run before any `gh search`, `gh issue`, or other GH command. No exceptions.
+
+ Keep pre-flight silent and minimal. Do not dump tasks index content, full git status, or label catalogues into chat. Read what you need internally, surface only what changes the proposal. **Output budget for pre-flight: 0 lines.**
+
+ 1. **Read `$TASKS_INDEX_PATH` FIRST** (if configured). This is the curated index of current-week priorities + active tracks + repo pointers. Without it, search is shotgun (random keywords) instead of targeted.
+ 2. **Snapshot the weekly Project once per run** with an explicit high limit (the default page truncates large boards):
+ ```bash
+ gh project item-list <WEEKLY_PROJECT> --owner $YOUR_OWNER --format json --limit 1000 > /tmp/manager-proj.json
+ ```
+ 3. **Task drift guard.** If the current day or week plan contains an active task row with no `repo#N` GitHub issue reference → surface as `Task drift: <row> — no GitHub issue`. In read mode: report only. In write mode: find an existing issue or create one (then it carries the iron invariants).
+ 4. Check git status of relevant repos (silently). If specific artifacts referenced in session are uncommitted, mention only those by name in proposal.
+ 5. Compute current ISO week if tasks index "Updated" line is stale (>7 days) or absent.
+
+ **Run independent `gh` reads in parallel** — multiple Bash calls in a single message. Run sequentially only when the output of one call is required as input for the next.
+
+ ### Red flag: skipping tasks index
+
+ If you're about to run `gh search issues` without first reading `$TASKS_INDEX_PATH` (when configured) — STOP. You're about to do shotgun search instead of using the Project/track index that already exists.
+
+ ## Write mode algorithm
+
+ ```dot
+ digraph manager_write {
+ "Infer artifacts from conversation" [shape=box];
+ "Silent pre-flight + cross-repo search" [shape=box];
+ "Brief execution plan (5-15 lines)" [shape=box];
+ "Hard blocker / ambiguous write?" [shape=diamond];
+ "Execute (body, comment, labels, Project)" [shape=box];
+ "Brief result report" [shape=box];
+
+ "Infer artifacts from conversation" -> "Silent pre-flight + cross-repo search";
+ "Silent pre-flight + cross-repo search" -> "Brief execution plan (5-15 lines)";
+ "Brief execution plan (5-15 lines)" -> "Hard blocker / ambiguous write?";
+ "Hard blocker / ambiguous write?" -> "Execute (body, comment, labels, Project)" [label="no"];
+ "Hard blocker / ambiguous write?" -> "Ask concise question / proposal" [label="yes"];
+ "Execute (body, comment, labels, Project)" -> "Brief result report";
+ }
```
- {object} — {action}
+
+ In write mode, for each touched issue:
+
+ 1. Update the **body** (default channel — not a comment): refresh `Status` / `Next` + a dated entry in `## Updates`.
+ 2. Add the **work-record comment** (Iron invariant 6) — only if real work happened: what was done this session + `refs`/SHA.
+ 3. Ensure **W-label + parent (Sub-issues API) + Project placement**, and set the Project status lane to `In progress` (see Project status sync).
+ 4. Record **commit↔issue linkage** (see below).
+
+ **Authorization mode** (from your `AGENTS.md` / `CLAUDE.md` config):
+
+ - `ask-each-time` (default): after the plan, ask "execute?" before any GitHub write.
+ - `execute-after-plan`: after the silent pre-flight and brief execution plan, execute scoped GitHub writes without asking a separate confirmation. Still run pre-flight, search existing issues, preserve invariants, and report exactly what changed.
+
+ Either mode: ask before writing when the write is genuinely ambiguous or risky — no suitable parent epic, uncertain repo/track ownership, public-repo privacy risk, destructive/bulk changes, closing an issue whose scope is not clearly completed, or conflicting evidence.
+
+ ### Commit ↔ issue linkage
+
+ 1. Every commit in a session should carry a trailer: `refs $YOUR_OWNER/<repo>#N` (or `closes $YOUR_OWNER/<repo>#N` if the commit fully closes the scope). GitHub shows a backlink in the issue timeline — works cross-repo.
+ 2. The dated entry in `## Updates` lists short SHAs of commits from each touched repo this session: `(code: <repo-A>@9a8ff92, <repo-B>@6fb5b26)`. An issue with no SHA when commits exist = incomplete sync.
+ 3. Collect SHAs via `git log --oneline -10` per touched repo before writing the Updates entry.
+ 4. **Artifact must be committed and pushed BEFORE being linked.** The user reads everything via web GitHub — an uncommitted local file does not exist for them. Links in body/report must be clickable GitHub URLs, not `~/...` local paths.
+
+ ### Planning artifacts (PRD / plans / diagrams)
+
+ When a session produces a PRD, plan, or diagram: the full content belongs in the **issue body** — context, decision table, mermaid diagrams (GitHub renders them inline), schema, MVP slices, out-of-scope, open questions — not a link to a file. A local md file can exist as a working copy; if they diverge, the issue body is the source of truth. Any file link from the body is a clickable GitHub URL pointing to an already-committed-and-pushed version, never a local path.
+
+ ## Read mode algorithm
+
+ 1. Resolve query subject — track name, person, repo, issue number, time window.
+ 2. Run cross-repo search (multi-key) — single `gh search issues` for simple tracks, batched GraphQL for 3+ keys (see below).
+ 3. **Filter false-positives** — drop matches where keyword overlap is incidental (e.g. issue tagged `W18` but unrelated to the queried track). See "False-positive surface" below.
+ 4. For true matches, pull live state in one batched GraphQL call: title, state, labels, parent (Sub-issues API), `projectItems` with status lane, last activity. Prose is not evidence — use live reads.
+ 5. **Resolve track epic** — find the parent epic. Pull `sub_issues_summary` — note `total`, `completed`, `percent_completed` + epic's own `state`.
+ 6. Cross-reference tasks index — does the track appear in the current-week priority list? If yes, mark as "🔥 hot W{NN}". Verify the index row for drift: referenced issue CLOSED, scope mismatch, or implied open work that no longer exists.
+ 7. Output: condensed table (with a Project column) + open questions + "what's NOT covered yet" gaps + drift surface. Read mode never writes to GitHub.
+
+ ### Live Project state reads — batched GraphQL
+
+ When surfacing or correcting Project placement, batch up to ~20 issues in one GraphQL call via aliases:
+
+ ```bash
+ gh api graphql -f query='
+ query {
+ i1: repository(owner:"$YOUR_OWNER", name:"<repo1>") { issue(number:<N1>) { ...IssueState } }
+ i2: repository(owner:"$YOUR_OWNER", name:"<repo2>") { issue(number:<N2>) { ...IssueState } }
+ }
+ fragment IssueState on Issue {
+ number title state url
+ labels(first:20){nodes{name}}
+ parent { number title repository { nameWithOwner } }
+ projectItems(first:10){nodes{ id project { number title } fieldValueByName(name:"Status"){ ... on ProjectV2ItemFieldSingleSelectValue { name } } }}
+ }' | jq -r '(.data // {}) | to_entries[] | .value.issue | select(. != null)
+ | "\(.number) \(.title) [\([(.labels.nodes // [])[].name]|join(","))] parent=\(.parent.repository.nameWithOwner // "—")#\(.parent.number // "") projects=\([(.projectItems.nodes // [])[] | "\(.project.title):\(.fieldValueByName.name // "empty")"]|join(" | "))"'
```
- - `{object}` узнаваемый (Sportmaster, Кружок #11 L3, Валентин S2)
- - em-dash `—` как разделитель
- - без дат, времени, дедлайнов и W-label — это живёт в labels, полях Project и body
- - без эмодзи и служебных префиксов (`product:`, `epic:`, `ops:`)
- - заголовок на русском; английский только для имён собственных и токенов
+ Notes: pipe into a separate `jq`, **not** the `--jq` flag (see the CRITICAL note in the batched-search section — when a GraphQL response carries `errors`, `gh` ignores `--jq` and dumps the raw body). `parent` is the Sub-issues API parent; `projectItems[].fieldValueByName.name` is the status lane. Result is at `.data.<alias>.issue` — don't forget the `.issue` level in jq. Single-issue fallback: `gh issue view N -R $YOUR_OWNER/<repo> --json projectItems` — `.projectItems[].status` is an object; read `.status.name`, not `.status`. List epic children: `gh api repos/$YOUR_OWNER/<repo>/issues/<EPIC_N>/sub_issues --jq '.[] | {number, title, repository_url}'`.
- Полный свод с примерами и анти-паттернами: [reference/issue-authoring.md](reference/issue-authoring.md) → «Issue title convention».
+ ### Parent-proof ambiguity
- ---
+ When verifying parent visibility: check both the child's `parent_issue_url` AND the parent's `/sub_issues` endpoint. If child-side parent reads as `null` but parent `/sub_issues` lists the child, report `parent proof: parent sub_issues ✓; child API ambiguous` — not `parent missing`. The two API surfaces can disagree transiently.
- ## Режим записи — шпаргалка
+ ### Related context, not hierarchy
- 1. Тихая преднастройка → прочитать `tasks.md`
- 2. Кросс-репо поиск (батч-GraphQL при 3+ ключах) → найти и проверить родительский эпик
- 3. Короткий план исполнения (5-15 строк) → сразу исполнить (постоянное разрешение)
- 4. Обновить body, а не комментарий по умолчанию — Status / Next / `## Updates` + SHA
- 5. W-label + parent (Sub-issues API) + Project placement `In progress` + assignee `@me` по умолчанию (founder; существующего исполнителя не перетирать — см. [reference/issue-authoring.md](reference/issue-authoring.md) → «Assignee»)
- 6. Комментарий-запись о работе, если работа была реальной
- 7. Если в body или таймлайне уже 3+ разнородных обновления — сначала разделить: вынести открытые следующие шаги в отдельные issues под тем же эпиком, а в исходном оставить краткий статус и ссылки
- 8. Синк дневного плана HQ: `tasks/WNN/YYYY-MM-DD.md`
- 9. Учёт времени в `time/log.csv` + поле «Часы», если founder назвал время
+ Build a `Related` context list only for true matches with a distinct scope: a separate task, contextual reference, dependency, cross-repo artifact, or historical task. Filter out parent/child links already expressed through the Sub-issues API — those are already visible in the hierarchy column. Do not duplicate API-expressed structure as `Related` prose.
- Детали: [reference/modes-read-write.md](reference/modes-read-write.md) и [reference/project-sync.md](reference/project-sync.md).
+ ## Search for existing issues — how
- ---
+ For each artifact or query subject, search by **multiple keys** to avoid missing matches. For simple unambiguous tracks (single-keyword) one query is enough — escalate to multi-key only when first query returns 0 or 5+ matches:
- ## Режим чтения — шпаргалка
+ ```bash
+ gh search issues --owner $YOUR_OWNER <key> --json repository,number,title,labels,state,updatedAt
+ ```
- 1. Преднастройка → `tasks.md`
- 2. Кросс-репо поиск (несколько ключей, батч-GraphQL)
- 3. Отсеять ложные совпадения — показать их как IGNORED, а не прятать
- 4. Батч-GraphQL по настоящим совпадениям → state + labels + parent + projectItems
- 5. Сжатая таблица: repo#N «заголовок» | parent | W-label | Project | последняя активность | статус
- 6. Режим чтения ничего не пишет в GitHub
+ **`--state` accepts only `open` or `closed` — the value `all` is invalid and errors out.** To cover both states, just omit `--state`: one call returns open and closed together. Never run two queries (open + closed) — that wastes the scarce REST quota (30/min).
- ---
+ **Keys to try (per artifact/subject):**
+ - Person name + slug (different transliterations): `"<person-name>"`, `<handle>`, `<filename-slug>`
+ - Company / track: `<track-A>`, `<track-B>`, `<client>`
+ - Telegram/social handle if mentioned: `<handle>`
+ - Filename slug from any CRM artifact: `<opportunity-slug>`
- ## Режим среды (денежный gate) — шпаргалка
+ **Match acceptance criterion:** issue title or body references the same person/company/track AND scope of work overlaps. If 2+ candidates match — pick the most specific one and link the others as `Related`.
- Лёгкая проверка в среду между планированием (пн) и ретро (вс): ловит провал недели — воркшоп переносится, денежное обещание стоит — ДО воскресенья, когда неделя уже потрачена. **Агент инициирует сам**; founder отвечает максимум на один точечный вопрос. Времени founder'а ≈ 0.
+ ### Batched GraphQL search (3+ keys)
- Что считать деньгами (денежное обещание — бинарно, поле `coprep_active`) и откуда брать обещания недели (`retros/W{NN}-outcomes.md`, строки O*) — **то же, что в `retro` / `weekly-planning`**; здесь не дублируем. См. `~/Documents/GitHub/hq/.agents/skills/retro/SKILL.md` (Iron Rule #16 + time-series поля `cash_*`) и `weekly-planning` Phase 5.
+ When multi-key search needs 3 or more queries, batch them in a single GraphQL call to avoid the REST Search API rate limit (30 req/min):
- 1. **Прочитать денежные обещания недели** (только чтение, батчем):
- - открытые issues с денежным контуром = label текущей недели `W{NN}` + домены PC-продажи / Кружок / Спортмастер / менторство / ad-slot;
- - `~/Documents/obsidian/0_hq/retros/W{NN}-outcomes.md` → строки O*, помеченные как денежные.
- 2. **Снять движение с понедельника** (доказательствами, не самоотчётом): новые сделки и оплаты за окно недели по `corp-sales/CLAUDE.md` § Live cash truth при чистом reconcile; статус каждого денежного issue — комменты, коммиты (`refs`/`closes`), закрытие после понедельника; активность co-prep — соответствующий issue в `corp-team` (то же поле `coprep_active`, что в ретро).
- 3. **Если не движется** (нет сделок + тишина в issue + co-prep молчит) — задать founder'у **ОДИН** самодостаточный вопрос с конкретикой: сущность целиком, одна развилка. Пример:
- > «O1 не двинулся за 3 дня, воркшоп-преп стоит, corp-team#5 (co-prep) — 0 активности. Co-prep назначен или контур горит?»
- 4. **Если движется** — короткое `cash on track: <доказательство>` (сделка / коммит / активность co-prep), без шума.
+ ```bash
+ gh api graphql -f query='
+ query {
+ s1: search(query:"user:$YOUR_OWNER is:issue <term1>", type:ISSUE, first:20){ nodes { ... on Issue { number title state url repository{nameWithOwner} labels(first:10){nodes{name}} updatedAt } } }
+ s2: search(query:"user:$YOUR_OWNER is:issue <term2>", type:ISSUE, first:20){ nodes { ... on Issue { number title state url repository{nameWithOwner} labels(first:10){nodes{name}} } } }
+ }' | jq -r '(.data // {}) | to_entries[] | .key as $k | (.value.nodes // [])[] | select(.number != null)
+ | "\($k) \(.state) \(.repository.nameWithOwner)#\(.number) \(.title) [\([(.labels.nodes // [])[].name]|join(","))]"'
+ ```
- По умолчанию gate **ничего не пишет в GitHub**. Если по ответу founder'а нужен синк (re-label, статус, новый issue) — перейти в режим записи под постоянным разрешением.
+ Omit any `state:` qualifier — one alias returns both open and closed. Adding `state:open` silently drops closed issues (e.g. a closed epic), forcing a wasteful second batch.
- **Расписание:** gate стоит повесить на автозапуск в среду утром через скилл `schedule` или cron. **Не создавать cron из этого скилла** — это решение founder'а. Пример команды для его подтверждения (не исполнять):
+ **CRITICAL — pipe into a separate `jq`, NOT the `--jq` flag.** This is the #1 cause of recurring crashes in this skill:
+ - When a GraphQL response carries an `errors` array (one failed alias, or a totally broken query), `gh api graphql` **ignores the `--jq` flag entirely**: it dumps the raw JSON body to stdout plus a short error to stderr, exit 1. The `(.data // {})` guard inside `--jq` never runs — the flag is bypassed.
+ - A total failure → body is `{"errors":[...]}` with no `data` key. Any downstream `d['data']` (Python) throws `KeyError: 'data'`.
+ - So always `gh api graphql -f query='...' | jq -r '(.data // {}) | ...'`. The raw body (with `data`, or `errors`-only) flows from stdout into `jq`, the `(.data // {})` guard runs on the body: live aliases print, failed ones are skipped, a total failure yields empty output with no crash. The `gh` error stays visible on stderr for debugging.
+ - **Never parse the response with a Python one-liner (`python3 -c "d['data']..."`).** If Python is unavoidable, use `d.get('data', {})`, never `d['data']`.
+
+ **Required jq guards** (without them the expression crashes on `cannot iterate over: null`):
+ - `(.data // {})` **first** — on an `errors`-only body `.data` is `null` and `to_entries[]` crashes; `// {}` yields an empty object
+ - `(.value.nodes // [])` and `(.labels.nodes // [])` — an alias or field can return `null`
+ - `select(.number != null)` — drops empty `{}` objects from non-Issue nodes
+ - `is:issue` in each query string — excludes PRs
+
+ **Partial errors:** with `| jq`, a failed alias is simply absent from the output and the live ones print. Don't blindly retry the whole batch — if needed, read `.errors` in a separate pass (`... | jq '.errors'`), then drop/fix the failed alias.
+
+ **Why:** `gh search issues` is the REST Search API, limited to 30 req/min — multi-key runs of 15-20 searches throttle. GraphQL `search()` counts against the 5000 points/hour GraphQL limit and batches efficiently. Owner qualifier in GraphQL is `user:$YOUR_OWNER` (not `--owner`).
+
+ ## False-positive surface (read AND write mode)
+
+ Search by W-label or generic terms can return issues that **share a label but aren't on this track**. Example: `<repo>#1` returned for `<track-A>` query because both have `W18` label.
+
+ **Rule:** if a search match's title/body has no overlap with the queried track besides W-label or other generic label — it's a false positive. Drop it from results, surface in report under `IGNORED (false positives)` so user can confirm.
+
```
- # среда 09:00 — авто mid-week cash gate
- schedule: "0 9 * * 3" → /manager midweek
+ IGNORED (false positives):
+ - <repo>#1 — surfaced via W18 label match, but track = <unrelated track>
```
- ---
+ Don't silently filter — show what was filtered and why, in case user spots a real link manager missed.
- ## Главные анти-паттерны
+ ## Parent epic rules
- - **Issue без родительского эпика** — железный инвариант. Вынести в предложение, не создавать сироту.
- - **Создание track-labels** (`x26-bloom`, `<slug>`) — запрещено. Только title + членство в эпике.
- - **Markdown `Parent: #N` в body, когда есть связь через API** — дубликат, протухает.
- - **Закрытие issue без явной команды founder'а** — по умолчанию оставлять открытым с комментарием.
- - **Схлопывание менторских сессий** — обзор трека, `S1`, `S2`, delivery живут отдельными issues. Никогда не сворачивать в один.
- - **Деньги в менторских задачах** — деньги только в CRM/ledger, не в теле GitHub-issue.
- - **Массовая правка `tasks.md`** — manager читает недельный индекс, но не пишет в него; `tasks/WNN/YYYY-MM-DD.md` — writable.
- - **Вопрос «подтверди» перед обычной записью** — действует постоянное разрешение. Только жёсткие блокеры.
- - **Голые номера** — всегда `repo#N «title»`, никогда просто `crm#27`.
- - **Синк или закрытие после реальной работы без комментария-записи** — инвариант 6.
- - **Большой чат-журнал внутри одного issue** — запрещено. Появились независимые действия, документы, ожидания ответа, созвоны → разделить на child/sibling issues, parent держит summary.
- - **Закрытие с непереданными развилками и follow-up** — сначала перенос («Открыто» → новый issue, даты → дневные файлы, хвосты → указатели), потом close.
+ Every issue (except the epic itself) must have **exactly one** parent via GitHub Sub-issues API. This is machine-readable track differentiation — replaces track-labels and stale markdown pointers in body.
- Полный список ошибок: [reference/issue-authoring.md](reference/issue-authoring.md) и таблица ниже.
+ ### What counts as an epic
- ---
+ - An issue that has sub-issues (counter `N / M` shown at top)
+ - Title typically contains track scope (`<program>: <partner> — overview`, `<deal> — overview`, `<product> — delivery <version>`)
+ - An epic itself does NOT have a parent — it's the root of the tree
+ - A working epic typically has `total >= 1`, but a new root issue with a clear track scope may be proposed and used as an epic before its first sub-issue, provided the user confirms the scope (bootstrapping a new track).
- ## Частые ошибки
+ ### One epic per issue
- | Ошибка | Как правильно |
- |---|---|
- | Пропустить `tasks.md` перед `gh search` | СТОП. Сначала `tasks.md` — там ссылки на Project и слаги треков |
- | Закрыть delivery по менторству/LMS после локального смоука | Готовность для ученика = загруженное видео + video_id + смоук на проде + отправленная ссылка |
- | Принять смежный issue за нужный | Смежный = контекст; синкать только в issue с тем же артефактом/сессией/уроком/lane |
- | Превратить `Related` в ручной список задач | Блок `Related` = только контекст: без статусов, чек-листов, W-label и полей Project |
- | Забыть указатель `[[crm-slug]]` в issue про коммуникацию | В теле каждого такого issue должна быть ссылка `[[<slug>]]` |
- | Считать, что W-label достаточно | Нужны W-label + parent + Project placement с непустой lane |
- | Считать, что связи parent через API достаточно | Проверяй видимый root в Project и его status lane |
- | N×`gh issue view` поодиночке | Батч-GraphQL; одиночный вызов — только точечный fallback |
- | Коммит без `refs <owner>/<repo>#N` | Каждый коммит несёт refs-трейлер |
- | PRD в локальном md, а в issue только ссылка | Полный PRD живёт в теле issue; локальная копия — осознанный дубль, ссылка — GitHub-URL |
- | Пропустить создание W-label, которого нет в репо | Создай label, не пропускай |
- | Урок/сессия остались в prep-состоянии после даты события | Дата прошла + «готовлюсь» = `Расхождение lifecycle`; нужен итог после события |
- | Попросить founder'а открыть URL или файл руками | Никогда. Приноси содержимое сам через инструменты |
- | Локальный путь как результат в отчёте | Коммит + push + GitHub-URL ДО отчёта |
+ GitHub supports only one parent via Sub-issues API. This matches: «one track — one hierarchy». If a task seems to relate to two tracks — reconsider scope: probably split into two issues, OR it's an aggregate issue (see below).
- ---
+ Do not use markdown `Parent: #N`, `Epic: #N`, `Belongs to: #N` in body when parent is set via API — it's a duplicate that goes stale. Parent is stored via the Sub-issues API only.
- ## Навигация по reference
+ ### Resolve epic — algorithm at creation / sync
- | Тема | Файл |
- |---|---|
- | Алгоритм режимов записи/чтения, шаблоны и язык вывода | [reference/modes-read-write.md](reference/modes-read-write.md) |
- | Преднастройка, Project ID подробно, батч-GraphQL, ключи поиска, ложные совпадения | [reference/search-algorithm.md](reference/search-algorithm.md) |
- | Родительский эпик, алгоритм выбора, агрегирующий parent, видимый root, смежные issues | [reference/parent-epic-rules.md](reference/parent-epic-rules.md) |
- | Синк дневного плана HQ, учёт времени, коммиты, PRD в issue, lifecycle, правила W-label | [reference/project-sync.md](reference/project-sync.md) |
- | Заголовки issue, критерий готовности, обновить или создать, менторство, комментарий vs body | [reference/issue-authoring.md](reference/issue-authoring.md) |
- | Иерархия Кружка, паттерн заголовков, правила обновления, чек-лист перед синком | [reference/kruzhok-hierarchy.md](reference/kruzhok-hierarchy.md) |
- | Шаблоны тела (новый issue, менторская сессия, комментарий) | [templates/issue-body-templates.md](templates/issue-body-templates.md) |
- | Полный шаблон иерархии задач по Кружку | [templates/kruzhok-product-task-hierarchy.md](templates/kruzhok-product-task-hierarchy.md) |
+ 1. **Search for an existing epic** for the track via cross-repo search; verify candidates have non-empty `sub_issues_summary.total`.
+ 2. **Canonical mapping by domain** (configure per your business in `Domain → repo routing`):
+ | Track domain | Epic lives in |
+ |--------------|---------------|
+ | Educational program / partnership | teaching domain repo |
+ | B2B deal / multi-lane commercial track | crm / commercial repo |
+ | Product launch | the product's own repo |
+ | Research initiative | research repo |
+
+ 3. **If no epic exists** — manager raises in proposal: «no epic for track X, do you want one?». Never creates an issue without a parent silently.
+ 4. **When creating a sub-issue** via API:
+
+ ```bash
+ CHILD_ID=$(gh api repos/OWNER/REPO/issues/CHILD_NUMBER --jq '.id')
+ gh api -X POST repos/EPIC_OWNER/EPIC_REPO/issues/EPIC_NUMBER/sub_issues -F sub_issue_id=$CHILD_ID
+ ```
+
+ ### Aggregate parent for cross-track issues
+
+ If an issue covers 2+ sibling tracks, scopes, or deliverable classes, classify it as an **aggregate issue** before assigning a parent. Do not attach it to the first matching subject epic if that would make another sibling scope invisible.
+
+ **Signals of an aggregate issue:**
+ - Title/body explicitly spans multiple sibling scopes: `product + sales`, `strategy + delivery`, `pilot + docs`, `launch + ops`.
+ - Issue lives in an aggregate/reporting repo while the subject epics live in their owner repos.
+ - Body talks about weekly review, close/kill decision, forecast, pipeline, operating review, portfolio snapshot, or cross-repo coordination.
+ - Issue updates a shared index, forecast, heartbeat, dashboard, or plan — not a single concrete deliverable.
+
+ **Algorithm:**
+ 1. Find the subject epic for each sibling scope.
+ 2. Find a repo-local aggregate epic: `forecast`, `pipeline`, `portfolio`, `weekly review`, `operating review`, `coordination`, `umbrella`.
+ 3. If found — attach the issue there. In plan/report write `parent: aggregate`.
+ 4. If none exists — surface a proposal: create an umbrella issue OR split into separate child issues under each subject epic.
+ 5. Never write one issue as a child of two epics; GitHub parent is exactly one.
+
+ In read/write output, distinguish parent types explicitly:
+ - `parent: track` — a specific subject-domain epic
+ - `parent: aggregate` — forecast / pipeline / portfolio / operating umbrella
+ - `parent: runtime` — a published / runtime layer epic
+ - `parent: unknown` — parent not yet found or requires user decision
+
+ ### Project-visible root
+
+ Manager distinguishes three parent concepts:
+
+ - **API parent** — direct parent from the GitHub Sub-issues API (`parent_issue_url`).
+ - **Visible root** — nearest parent / track-overview / umbrella issue that should appear in the current Project view and under which the user expands the tree.
+ - **Historical / backlog grandparent** — upper strategy parent that may remain outside the weekly Project view when the visible root already has a W-label and non-empty status lane.
+
+ **Rules:**
+ 1. If an active / current-week issue has no sub-issues and is a child delivery/action issue, its API parent or visible root must be in the Project with a non-empty status lane.
+ 2. If an issue is itself a track overview / session parent / umbrella (`sub_issues_summary.total > 0`) and is already visible in the Project, its backlog/strategy grandparent does not need to appear in the weekly Project. Report as `parent: historical/backlog`.
+ 3. If a child has `parent_issue_url` but the parent item is absent from the Project view, surface as: `Project divergence: parent epic not visible`.
+ 4. If the child-side API shows `parent: null`, verify by checking the likely epic's `/sub_issues` list. If the child is listed there, treat it as proof — but note `parent proof: parent sub_issues` (GitHub may read hierarchy asymmetrically).
+ 5. If the Project view filters by repo or type such that the parent cannot physically appear, report `Project view limitation` and do not reparent the child.
+
+ ### Related issues — body section
+
+ `Related` / `Related issues` in the body is for contextual cross-links only. It never creates hierarchy.
+
+ - Hierarchy lives only in the GitHub Sub-issues API (`parent_issue_url`, `sub_issues_summary`).
+ - Related links are for contextual references, isolated dependencies, cross-repo artifacts, and historical tasks.
+ - The Related block can be deleted without losing owner, W-label, Project placement, or the sub-issues tree.
+
+ **Forbidden inside a Related block:** `Parent: #N`, `Epic: #N`, `Belongs to: #N`, manual child/subtask lists, status mirror, next-step mirror, W-labels, Project placement cues, checklist state.
+
+ **Body format:**
+ ```markdown
+ ## Related
+
+ - <repo>#N «human-readable title» — brief reason for the link
+
+ **Verified:** YYYY-MM-DD by manager
+ ```
+ Max 3 bullet links + one `Verified` line. On each body sync, rewrite from live search — do not append infinitely.
+
+ **Before writing a body that contains a Related section — live-verify every referenced issue:**
+ ```bash
+ gh issue view N -R OWNER/REPO --json title,state,url,labels,updatedAt
+ gh api repos/OWNER/REPO/issues/N --jq '{parent: .parent_issue_url, sub_summary: .sub_issues_summary}'
+ ```
+ For active / current-week related refs, also check `projectItems`.
+
+ If any ref is missing, closed, parentless, points to another track, has a stale W-label, or would leak private/CRM data into a public repo — surface `Related links divergence` and remove or report before writing the body. For public repos: do not copy private titles, CRM slugs, local paths, personal handles, payment facts, or private URLs — use a safe public label like `private CRM issue — context only` and keep the exact private pointer in a private repo/report.
+
+ ### No track-labels
+
+ Track-labels (`<track-slug>`, `<client>-deal`) are NOT created. Track differentiation goes through title + epic membership. Existing legacy track-labels are not deleted (they're history), but no new ones are created. Cross-repo navigation by track = epic's sub_issues + Project board, not label filter.
+
+ ### Verification before sync
+
+ Before `gh issue edit` / `gh issue create` the agent MUST check the existing issue's parent and, for active issues, its Project placement:
+
+ ```bash
+ gh api repos/OWNER/REPO/issues/N --jq '{parent: .parent_issue_url, sub_summary: .sub_issues_summary}'
+ ```
+
+ Surface in proposal which issues are missing a parent and which epic is proposed for each.
+
+ ## Project status sync (write mode)
+
+ New issues start in the configured backlog lane. The first proposal, draft, specification, or decision counts as work: save the substantive draft in the issue body and move it to the configured active lane.
+
+ In write mode, when the user actively worked on an issue in the current session, manager **must** set the Project status lane to `In progress` on all primary/child issues touched in:
+
+ - The global weekly Project
+ - The domain-specific Project board for the track, if the issue already lives there
+
+ **Rules:**
+ 1. Only update issues that manager updated or created in this sync, plus their visible parent if the parent is also in the current day plan.
+ 2. Do not set `In progress` on historical/backlog issues with no work in this session.
+ 3. Do not downgrade `Done` or `In review` without explicit user signal.
+ 4. If the item is not yet in the Project — run `gh project item-add` first, then `gh project item-edit` to set status.
+ 5. If the parent/session issue of a child is in the day plan and the child is active today — also move the parent to `In progress`.
+
+ ```bash
+ # Step 1 — get item id (from item-add output or item-list snapshot)
+ # Step 2 — get field and option ids (cache these in your config)
+ gh project field-list <PROJECT_NUMBER> --owner $YOUR_OWNER --format json
+ # Step 3 — set status lane
+ gh project item-edit \
+ --id <PROJECT_ITEM_ID> \
+ --project-id <project-id> \
+ --field-id <status-field-id> \
+ --single-select-option-id <in-progress-option-id>
+ ```
+
+ For each domain board, read its field list first — lane names may differ (`In progress` vs `In Progress` vs `Active`).
+
+ **Project drift rules:**
+ - Issue in Project with empty Status field → surface as `Project drift: status lane empty`.
+ - If a GraphQL/rate-limit error blocks the status edit → report `Project drift: placement ok, status lane pending` and do not claim full repair.
+
+ ## Plan cleanup on close
+
+ When manager closes an issue in write mode, it must remove that issue from active planning surfaces in the same sync:
+
+ 1. Read `$TASKS_INDEX_PATH`, current week README, and today's day file if configured.
+ 2. If the closed issue appears as an active P0/P1 row, remove the row or replace it with the next open child issue under the same parent.
+ 3. If the closed issue appears in a weekly/index issue list, remove it when no open work remains for that scope. If the parent remains active, keep the parent and open children.
+ 4. Do not delete historical retro/outcomes evidence. Append a note only when the plan file has a current "Done / Closed today" section; otherwise keep the active plan clean.
+ 5. In the result report, show the cleanup explicitly: `removed closed issue from day plan: repo#N`.
+
+ If manager did not close the issue itself, read mode reports drift only. Do not clean plans for a closed issue unless the current sync is explicitly doing closure or the user asked for cleanup.
+
+ ## W-label rules
+
+ (Skip this section if W-label convention is disabled in your config.)
+
+ ### Current-week resolution
+
+ 1. Read tasks index first line under your "Updated" marker — canonical signal for current week.
+ 2. Compute ISO week from `date '+%V'` if index is stale (>7 days).
+ 3. Map to label format: `W{NN}` (zero-padded only if existing labels in repo are zero-padded — check repo first).
+
+ ### Dated issues — W-label from the event date
+
+ For issues whose title/body/calendar contain a specific event date (a session, live event, workshop, deadline), the W-label is computed from **that event date**, not the current sync date.
+
+ - `<person> S2 — prep and deliver session (29.05)` on 2026-05-29 gets `W22`.
+ - If the date in the title is only `DD.MM`, take the year from body / calendar / current session context. If the year is ambiguous — surface `Week ambiguity: date in <repo>#N is ambiguous; not writing GitHub until clarified` and halt the label write.
+ - If syncing in a different week from the event, show both: `event week: W22`, `sync week: W23`.
+ - If an existing dated issue has a stale or missing W-label, surface: `Week drift: <repo>#N «title» — has <labels>, should have W{NN}; action: add W{NN}`.
+
+ ### Week drift vs Project drift (read mode)
+
+ These are two independent conditions — an issue can have one without the other:
+
+ - **Week drift:** issue has a W-label that doesn't match the current calendar week for the work → `Week drift: issue has W{NN}, expected W{MM} by date; action: add W{MM}`
+ - **Project drift:** issue has the correct W-label but is absent from the expected Project board → `Project drift: W{NN} present, missing from <Project>; action: add to Project after W-label fix`
+
+ List both in the Track health section of read mode output.
+
+ ### Multi-week tasks
+
+ If a task requires action this week AND continues next week — apply BOTH W-labels. The index file is for "what's hot now"; labels record full lifecycle.
+
+ ### Backlog vs future-week
+
+ - If task is **deferred more than 1 week** without active work → `backlog` (create label if missing).
+ - If task is **planned for a specific future week** → `W{NN}` for that week.
+ - Never use `backlog` AND `W{NN}` together — pick one.
+
+ ### Creating / adding W-labels — fast-path
+
+ Do not call `gh label list` first to check existence. Immediately try to add it; only on failure create the label and retry:
+
+ ```bash
+ gh issue edit <N> -R "$REPO" --add-label "W{NN}" \
+ || { gh label create "W{NN}" -R "$REPO" --color "0E8A16" --description "Week {NN}"; \
+ gh issue edit <N> -R "$REPO" --add-label "W{NN}"; }
+
+ # backlog label
+ gh label create "backlog" -R "$REPO" --color "ededed" --description "Deferred — not on current/next week"
+ ```
+
+ Color `0E8A16` (dark green) for active weeks, `ededed` (neutral grey) for backlog. Old `retro:W*` and historical `W*` labels are never removed for tidiness.
+
+ ## Issue title convention
+
+ All new issues created by manager follow a fixed formula — canonical operational layer for agents (predictable parsing, search, groupBy).
+
+ ### Formula
+
+ ```
+ {object} — {action} ({when / context})
+ ```
+
+ Visible domain prefixes (`product:`, `content:`, `ops:`, `infra:`, `epic:`, etc.) are **NOT** written in the title. Type metadata lives in labels, the parent tree, Projects, and body.
+
+ | Segment | What | Examples |
+ |---------|------|----------|
+ | **`{object}`** | Recognizable subject first (noun) | `<track-A>`, `<product> L3`, `<person-name> S2`, `<handle>` |
+ | **`{action}`** | Verb + short scope | `prep for meeting <date>`, `process response + intake + slot` |
+ | **`{when / context}`** | Date/window/week in parens at end; optional | `(by <date>)`, `(<date> <time>)` |
+
+ ### Rules
+
+ 1. **No domain prefix in title.**
+ 2. **`{object}` is a noun first** for search ease (groups all of that track's tasks).
+ 3. **em-dash (—) separator** between object and action — visual anchor, easy to parse.
+ 4. **Date in parens at the end**, not the middle. Predictable placement.
+ 5. **No emojis in title** — clutter search and sorting.
+ 6. **Accept old prefixed titles as legacy aliases** in search/read. Do not auto-rename — only rename if user explicitly asked for bulk-rename.
+
+ ### Where type metadata actually lives
+
+ | Metadata | Location |
+ |----------|----------|
+ | Work type | labels (use your own taxonomy): `type:<work-type>`, `area:<domain>`, lifecycle labels |
+ | Track hierarchy | GitHub Sub-issues parent tree |
+ | Weekly visibility | W-label + Project placement |
+ | Owner / source | repo, Project, body fields |
+ | Root / epic status | sub-issues summary + body; no `epic:` prefix needed |
+
+ ### Product / runtime sub-patterns
+
+ | Situation | Pattern | Example |
+ |-----------|---------|---------|
+ | Bot / funnel / runtime feature | `<product or surface> — <fixed user behaviour> (<week/context>)` | `<bot handle> — duplicate request status without queue reset (W23)` |
+ | Ops discovery / runbook | `<system> — <operational capability or runbook>` | `<service> ops — one-off container commands via ssh (W23)` |
+
+ If a title is only understandable knowing a screenshot, a person's name, or a debugging-session history — the title is too situational. Details go in `## What was done`, `Evidence`, `Updates`; the title reflects the product outcome.
+
+ ### Examples
+
+ - `<track-A> — prep meeting <date> + budget by <date>`
+ - `<person-name> (<handle>) — process response + intake + slot`
+ - `<product> L3 — final prep for live (<date> <time>)`
+ - `<channel> — post recap <month> YYYY`
+
+ ### Anti-patterns
+
+ - ❌ `🔥 <track>: KP` — emoji + domain prefix
+ - ❌ `prep meeting on <date> for <track>` — verb-first instead of noun-first
+ - ❌ `ops: all about <event>` — domain prefix + too generic, no concrete action
+ - ❌ `partner: <track> → divergence ⚠️ overdue` — prefix, arrow instead of em-dash, emoji
+
+ ## Definition of done — body must be verifiable
+
+ When manager **creates** an issue or **reformats** an existing one, the body MUST contain verifiable completion criteria.
+
+ **Required minimum:**
+ 1. **Concrete scope checklist `- [ ]`** — what is specifically in scope, each item observable as done / not done.
+ 2. **Explicit "considered done when…"** — a closing condition tied to a verifiable artifact or observable behaviour.
+ 3. **Pointer to the source of scope** — where this scope came from: a skill section, a research report, a CRM slug, a parent epic, a meeting transcript.
+
+ **Vague one-liners without specifics are FORBIDDEN.** An issue body that cannot be verified against reality = malformed.
+
+ - ❌ `Implement rules from report X` — unclear which rules, which file, and when it's done.
+ - ✅ `- [ ]` checklist of concrete items + `done when rules are encoded in <skill>/SKILL.md § …` + link to source report.
+
+ If manager touches an existing vague issue (one-liner with no DoD), it adds the scope checklist + acceptance condition + source pointer in that same sync. Part of standard write sync under standing authorization.
+
+ ## Update vs create decision
+
+ **Default: update issue body, NOT add a comment.** Body = single source of truth, readable as one document. Comments stack chronologically and become unreadable after 5+ entries.
+
+ | Situation | Action |
+ |-----------|--------|
+ | Existing issue covers same scope, same track | **Edit body** — refresh "Status:", "Next:", and dated line in `## Updates`. Verify W-label is current AND parent epic attached AND Project placement present. |
+ | Existing issue scope is narrower but session expanded scope | Edit body of existing + create new follow-up issue with expanded scope, child of the same epic. |
+ | Multiple existing issues match different aspects (parent epic + sub-issue) | Edit body of the most specific child; touch epic only if its body needs updating. |
+ | No existing issue matches, but track is in tasks index | Create new issue. First resolve parent epic. W-label current, Project placement set. |
+ | No existing issue, no track in tasks index, fresh artifact | Ask user which repo + which epic before creating |
+ | Existing issue covers 2+ sibling scopes or belongs to a forecast/pipeline/operating review | Treat as aggregate issue. Find a repo-local aggregate epic first; if none, propose umbrella or split. |
+ | Existing child has a parent API link but appears flat in Project view | Do not reparent first. Verify parent Project placement + status lane; fix the parent Project item before changing hierarchy. |
+ | Found related issue with same subject but different scope | Keep as `Related` context only. Update/create a separate primary issue for the new standalone action. |
+
+ ### Comment is fallback, not default
+
+ Use a comment ONLY when:
+
+ - **Work-record after real session work on the issue** — one mandatory timeline comment per (session × issue): what was done + `refs`/SHA. This is the one case where a comment is required *in addition to* the body update (Iron invariant 6). One such comment per session per issue; don't stack — consolidate into body.
+ - The note is genuinely chronological and ephemeral (e.g. "blocked by external party until <date>") — would clutter body.
+ - User explicitly asked for a comment.
+
+ **Anti-pattern signal:** if you're about to write the third progress comment on an issue — that's two too many. Edit body instead.
+
+ ### Body update mechanics
+
+ Manager owns the read-modify-write pattern: `gh issue view` → local body file → `gh issue edit --body-file`, with refreshed `Status` / `Next` / `## Updates`. Use standard `gh` CLI directly.
+
+ ## Issue body template (when creating new)
+
+ Before writing any body to a **public** repo: replace private absolute paths, internal slugs, personal handles, payment facts, raw meeting/messaging URLs, and local-only evidence with safe public pointers. If no safe public pointer exists, record the private pointer only in the private/internal owner repo. Surface this as a blocker in the sync plan when applicable.
+
+ ```markdown
+ <one-line context: what changed/what was made>
+
+ **Source artifact:** <clickable GitHub URL — committed & pushed>
+ **Date:** <YYYY-MM-DD>
+ **Track:** <link to CRM card if commercial — see CRM integration>
+
+ ## What was done
+ <2-4 bullets — actual progress>
+
+ ## Scope
+ - [ ] <concrete item, observable as done/not-done>
+ - [ ] <concrete item>
+
+ ## Next step
+ <one line — what closes this issue (acceptance condition)>
+
+ ## Related
+
+ - <repo>#N «human-readable title» — brief reason for the link
+
+ **Verified:** <YYYY-MM-DD> by manager
+
---
+ Synced by manager from session <YYYY-MM-DD>.
+ ```
- ## Главное — повторение в конце
+ Add the `## Related` block **only when there are verified context links** — omit the whole block (don't leave it empty or with placeholder text) when there are none.
- **Перед любым gh-вызовом:** прочитать `tasks.md`, иначе поиск бьёт наугад.
+ ## Body update template (default)
- **Каждый issue обязан иметь:** W-label + parent (Sub-issues API) + Project placement с непустым статусом.
+ ```markdown
+ <one-line context: what changed/what was made — same as before, refresh if scope changed>
- **Режим записи всегда:** `In progress` на затронутых issues; комментарий-запись при реальной работе; синк дневного плана HQ; при закрытии — чек-лист закрытия (инвариант 8).
+ **Status:** <active / blocked / pending external / done — only "done" if user said so>
+ **Next:** <one-line next concrete step — refresh on each sync>
- **Постоянное разрешение:** план → исполнение без «подтверди». Спрашивать только при настоящей неоднозначности или жёстком блокере.
+ [... rest of original body content — REMOVE any old `## Related` block before re-writing ...]
- **Режим среды:** агент сам собирает денежные доказательства по `corp-sales/CLAUDE.md` § Live cash truth при чистом reconcile (+ денежные issues + co-prep); один точечный вопрос, только если обещание стоит, иначе `cash on track`. Определения денег и обещаний — общие с `retro` / `weekly-planning`, не дублировать.
+ ## Related
- **Все тексты для founder'а — на русском.** Технические токены (`crm#27`, `W18`, команды) — как есть.
+ - <repo>#N «human-readable title» — brief reason for the link
+
+ **Verified:** <YYYY-MM-DD> by manager
+
+ ## Updates
+
+ - **YYYY-MM-DD:** <2-4 bullets of progress / decisions> (code: <repo>@<sha>)
+ - **YYYY-MM-DD:** <previous sync entry, kept>
+ ```
+
+ Remove any stale `## Related` block from the preserved original content, then insert at most one fresh verified block (omit when there are no real context links). Newest update at top of `## Updates`, oldest at bottom (pick once per issue and stay consistent).
+
+ ## Comment template (fallback only)
+
+ ```markdown
+ **YYYY-MM-DD:** <one-line note that doesn't fit body — e.g. "external blocker until X", "transient state observation">
+ ```
+
+ Work-record comment (the required case) lists what was done this session + `refs`/SHA. Keep comments short. If a comment grows beyond 4 lines — it belongs in body.
+
+ ## Output format
+
+ ### Issue reference format (CRITICAL)
+
+ **Always use `<repo>#N — «human title»` form when surfacing an issue to the user.** Bare `<repo>#27` is unreadable — the user needs the title to recognize the track at a glance.
+
+ - ❌ Bad: `<repo>#27 → comment + W19`
+ - ✅ Good: `<repo>#27 «<track-A> — respond to brief» → comment + W19`
+
+ ### Write mode — plan (BEFORE execution)
+
+ Compact plan. Each line: what I'll do + where + why. Group by track. Under each track, first line — **epic** (parent issue), then sub-issues with `parent: OK / parent: MISSING` marker. Decisions / ambiguities — inline as questions.
+
+ ```
+ Sync plan (W18, <date>):
+
+ <track-A> · epic crm#15 «<track-A> — B2B deal overview»
+ - crm#27 «<track-A> — respond to brief» [parent: crm#15 ✓; W18 ✓; Project ✓]
+ → body update + work-record comment; status → In progress
+ - crm#25 «<track-A> — prep meeting <date>» [parent: crm#15 ✓; W18 ✓; Project ⚠️ missing]
+ → comment "both meetings done"; add to Project; close if scope done, else keep open with reason
+
+ Labels to create: W19 in $YOUR_OWNER/crm
+ Epics missing coverage: (none)
+
+ Uncommitted in crm: meetings/<date>.md (new) — commit before sync?
+
+ Proceeding under standing authorization. If scope looks wrong — stop / correct.
+ ```
+
+ If a track has **no working epic**, surface separately:
+
+ ```
+ ⚠️ Epic missing: track «<X>» has no parent epic. Options:
+ - Create crm#NEW «<X> — overview» as umbrella; all 3 issues below become sub-issues.
+ OR
+ - Use existing <repo>#N «<title>» (sub_summary total=N) — ask if ambiguous.
+ ```
+
+ ### Write mode — report (AFTER execution)
+
+ ```
+ Done:
+ - crm#27 «<track-A> — respond to brief» — body update + work-record comment + W19; parent crm#15 ✓; Project → In progress
+ - crm#42 «<track-B> — scope expanded» — created, child crm#10, W18+W19, added to Project
+ - W19 label created in $YOUR_OWNER/crm
+
+ Skipped per your decision: crm#25 «<track-A> — prep…» — left open
+ ```
+
+ ### Read mode
+
+ Compact table — always with a «Title» column, parent epic in its own column, a Project column, no bare numbers:
+
+ ```
+ Query: «what about <track-A>»
+
+ Epic of the track: crm#15 «<track-A> — B2B deal overview» (3/5 done)
+
+ Open sub-issues:
+ | Issue | Title | Parent | W-label | Project | Activity | Status |
+ |-------|-------|--------|---------|---------|----------|--------|
+ | crm#27 | <track-A> — respond to brief | crm#15 ✓ | W18 ✓ | ✓ | <date> | Active — KP due <date> |
+ | crm#25 | <track-A> — prep <date> | crm#15 ✓ | W18 ✓ | ✓ | <date> | Both meetings done — likely stale |
+ | presentations#9 | <track-A> — deck audit | — ⚠️ | W18 ✓ | ⚠️ | <date> | No parent + missing from Project, attach to crm#15 |
+
+ In tasks index:
+ - 🔥 W18 priority 4 — «KP for <track-A> by <date>»
+
+ Not covered (gap):
+ - No issue for writing the KP itself (only prep). Create on next sync?
+
+ Track health check:
+ - 1 issue without parent epic — presentations#9. Attach on next sync.
+ - 1 issue missing from Project — presentations#9.
+
+ Drift in index / epic state:
+ - (optional) crm#15 epic — 5/5 sub-issues done, state OPEN. Candidate to close.
+
+ Filtered (false positives):
+ - crm#1 «<unrelated> — complete» — surfaced via W18 label, unrelated to <track-A>
+ ```
+
+ When a track has a multi-level epic hierarchy (root → lanes/children → grandchildren), output the read-mode report as a **tree, not a flat list**: each line carries parent status, W-label status, and Project placement. Active / current-week issues missing a Project slot are flagged `Project mismatch`.
+
+ ## Cross-references
+
+ - For weekly index management (when current week changes): see `weekly-planning` skill.
+ - For retro-driven backlog (when `retro:W*` labels appear): see `weekly-retro` skill — these labels carry historical signal, don't strip.
+
+ ## Common mistakes
+
+ | Mistake | Fix |
+ |---------|-----|
+ | Closing issues without explicit user instruction | Comment-and-leave-open is default. Only close if user said "close" or scope is fully delivered AND user mentioned completion. |
+ | Closing a delivery issue after local smoke only | A conducted live/session/workshop is not delivered until: recording/artifact ID or exact blocker recorded, the runtime/published artifact validated (not just locally), and the user-facing URL smoke check passes. Keep open with the exact open child otherwise. Don't infer enrollment/payment from view counts — verify against the authoritative source. |
+ | Removing legacy labels (`retro:W17`, etc.) for "tidiness" | Don't strip labels you didn't add. Append new W-label, leave legacy. |
+ | Picking single W-label for cross-week task | If a task spans current + next week, apply both. |
+ | Creating new issue when a comment in an existing one fits | Search broadly first (multiple keys / batched GraphQL). Only create if scope clearly diverges. |
+ | Skipping W-label create when missing in repo | Iron invariant — create the label (fast-path), don't skip. |
+ | Creating/touching an issue without a parent epic | Iron invariant — surface in proposal, don't be silent. |
+ | Treating W-label as sufficient | Need W-label + parent + Project placement (lane not empty). |
+ | Treating the API parent as sufficient | Verify the visible root Project item and its status lane. |
+ | Attaching one issue to two epics | GitHub supports one parent. Split into two issues, or treat as aggregate. |
+ | Markdown `Parent: #N` in body when API link exists | Duplicate, goes stale. Parent — only via Sub-issues API. |
+ | Missing SHA when commits exist | The `## Updates` entry must list short SHAs of session commits per touched repo. |
+ | Local `~/...` path as a deliverable link | Commit + push first; the body/report link is a clickable GitHub URL. |
+ | N×`gh issue view` one-by-one | Use batched GraphQL; single calls are a pointed fallback only. |
+ | Closing/syncing after real work without a work-record comment | Iron invariant 6 — add the timeline comment. |
+ | Not respecting the public-repo gate | Before writing to a public repo, do not add private / CRM / personal details; if unsure — surface in proposal and ask. |
+ | Treating tasks index as a general task list to mutate | The index is curated by user / `weekly-planning`; manager only patches rows for touched issues, closure cleanup, and explicit drift repair. |
+ | Acting on uncommitted local changes as "done" | Surface uncommitted work in the report; don't link a not-yet-pushed artifact. |
+ | Silently filtering false-positive matches | Drop from primary results but show in `IGNORED (false positives)`. |
+ | Treating every invocation as write mode | Check first: artifacts (write) OR question about state (read)? Use the mode resolution diagram. |
+ | Asking the user to open a URL/issue/file manually | Never. Bring the content back via `gh issue view <repo>/<N> --comments` yourself. |
+ | Bare issue numbers | Always `<repo>#N «title»`. Numbers are unrecognizable. |
+
+ ## Anti-patterns
+
+ - **Creating an issue without a parent epic** — breaks iron invariant. Surface in proposal, don't create orphan.
+ - **Creating new track-labels** — no longer done. Differentiation = title + epic membership.
+ - **Domain prefix in title** — superseded. Type metadata lives in labels/parent-tree/Projects.
+ - **Attaching one issue to two epics** — one parent per issue. Reconsider scope or treat as aggregate.
+ - **Markdown `Parent: #N` / `Epic: #N` in body when parent is set via API** — duplicate, goes stale.
+ - **Treating prose as Project-placement evidence** — use live `projectItems` reads, not "should be on the board".
+ - **Auto-closing stale issues** — never. Surface to user, leave open.
+ - **Broadly rewriting tasks index** — manager only patches rows for touched issues, closure cleanup, and explicit drift repair. Weekly structure belongs to `weekly-planning`.
+ - **Silent skip on tasks-index drift** — surface explicitly so the user can re-curate.
+ - **Silent skip on epic stale-open** — epic with 100% sub-issues done but `state = open` is a real signal; surface as candidate-to-close, never auto-close.
+ - **Single mega-comment dumping whole session** — one comment per issue, scoped to that issue's track.
+ - **Creating issues across repos for the same artifact** — one artifact = one primary issue.
+ - **Skipping search** — always search before create. Bias toward update.
+ - **Dumping full investigation output to chat** — readings are silent; only the proposal is visible.
+ - **Asking the user to re-list session artifacts** — infer from conversation context.
+ - **Bare issue numbers** — always `<repo>#N «title»`.
+ - **Skipping tasks index before gh search** — pre-flight is not optional.
+ - **Adding comments instead of updating body** — body is the main channel; comment only for work-record / genuinely ephemeral notes.
+
+ ## CRM integration (optional)
+
+ Activate by setting `crm_path` and `crm_pointer_format` in your `AGENTS.md` / `CLAUDE.md` config.
+
+ When CRM integration is enabled, every commercial / communication-related issue body must include a pointer to the corresponding CRM artifact (person card, opportunity card, meeting note). Default pointer format is `[[<slug>]]` (Obsidian wiki-link style), but you can configure any format your CRM uses.
+
+ For commercial / mentoring tracks, keep money out of the GitHub task body — price, package balance, paid/won status, and deal-close language live in CRM or the sales ledger. The issue body carries `[[<slug>]]` and a one-line pointer instead.
+
+ ```markdown
+ **Track:** [[<opportunity-slug>]]
+ ```
+
+ Manager checks the CRM path exists when activated; if it doesn't — surfaces a one-line warning and proceeds without the pointer requirement.
+
+ ## Key reminders (recency — duplicate the critical)
+
+ **Before any gh call:** read the tasks index → otherwise it's shotgun search.
+
+ **Every issue must carry:** W-label + parent (Sub-issues API) + Project placement (non-empty status lane).
+
+ **Write mode always:** `In progress` on touched active issues; work-record comment on real work; commit↔issue SHA linkage; body is the channel, comment is the audit trail.
+
+ **Title:** `{object} — {action} ({when})`, no domain prefix; type metadata lives in labels/parent/Projects.
+
+ **Standing auth:** follow your configured mode — `execute-after-plan` runs scoped writes after the plan without a separate "confirm"; `ask-each-time` (default) shows the plan, then asks. Either way, ask on genuine ambiguity / hard blocker.
+
+ **Output language follows the project.** Technical tokens (`<repo>#N`, `W18`, commands) stay as-is.