--- name: manager description: >- 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 read (status lookup across repos with parent/W-label/Project health). Triggers on "/manager", "sync session", "обнови issues", "синкни сессию", "зафиксируй прогресс", "статус задачи", "что по ", "есть ли issue по", "track status", "what about ". --- # Manager — bidirectional GitHub issues bridge Part of the Personal Corp framework — running a one-person business through AI agents. 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. **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. **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. ## Setup Before first use, define this in your project's `CLAUDE.md`: ```markdown ## Manager Config ### GitHub owner Your GitHub username or org for issue search: - owner: your-github-handle ### Repos to scan (cross-repo issue search scope) List repos manager should search: - ~/Projects/main - ~/Projects/ops - ~/Projects/marketing ### Tasks index file (optional) Path to your curated "what's hot this week" file. Manager reads it FIRST before any `gh search` to scope queries: - tasks_index: ~/docs/tasks.md (если файла нет — manager работает без индекса, поиск идёт по всем repos) ### 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: # 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 | | | product | | Cache resolved field/option IDs here once discovered (`gh project field-list --owner OWNER --format json`) so manager doesn't re-fetch them every run. ### W-label convention (optional) - enabled: true - format: W{NN} (ISO week) (если false — manager создаёт issues без weekly labels) ### 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: [[]] (если не используется — секция игнорируется; см. CRM integration ниже) ``` No separate init skill needed — this section is the setup. Title-type metadata is NOT configured here: it lives in labels, the parent tree, and Projects (see Issue title convention). ## Iron invariants Every issue manager touches MUST satisfy the base three; an active / current-week issue must additionally satisfy the Project and work-record invariants: 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 (``, `-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 ```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'"]; } ``` **Signal for write mode:** user said «sync session», «зафиксируй», «обнови issues», OR invoked `/manager` without args at end of session, OR explicitly listed artifacts/changes. **Signal for read mode:** user asked a question about state — «what about», «status», «есть ли», «какие issues по». **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. **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). ## Output language Output language matches the user's input language and project conventions. Technical tokens remain as-is and are not translated: issue names (`#`), labels (`W18`, `retro:W17`, `backlog`), commands (`gh issue comment`), file paths, original English titles of issues in quotes. ### Issue-title language 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: - ❌ `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) 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. ## 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. **GitHub issues across `$YOUR_OWNER/*`** — authoritative for individual tasks. Search via `gh search issues --owner $YOUR_OWNER` or batched GraphQL (see below). 3. **GitHub Project board(s)** — authoritative for what's active this week and in which lane. 4. **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. ## 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) **Use (read mode):** - Start or middle of session — user asks «what about », «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 --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: — no GitHub issue`. In read mode: report only. In write mode: find an existing issue or create one (then it carries the iron invariants). Manager does not rewrite the tasks index itself — index curation is the `weekly-planning` skill's job. 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"; } ``` 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 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/#N` (or `closes $YOUR_OWNER/#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: @9a8ff92, @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:"") { issue(number:) { ...IssueState } } i2: repository(owner:"$YOUR_OWNER", name:"") { issue(number:) { ...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(" | "))"' ``` 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..issue` — don't forget the `.issue` level in jq. Single-issue fallback: `gh issue view N -R $YOUR_OWNER/ --json projectItems` — `.projectItems[].status` is an object; read `.status.name`, not `.status`. List epic children: `gh api repos/$YOUR_OWNER//issues//sub_issues --jq '.[] | {number, title, repository_url}'`. ### 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 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. ## 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 --json repository,number,title,labels,state,updatedAt ``` **`--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): `""`, ``, `` - Company / track: ``, ``, `` - Telegram/social handle if mentioned: `` - Filename slug from any CRM artifact: `` **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`. ### Batched GraphQL search (3+ keys) 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): ```bash gh api graphql -f query=' query { s1: search(query:"user:$YOUR_OWNER is:issue ", 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 ", 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(","))]"' ``` 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. **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: `#1` returned for `` 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. ``` IGNORED (false positives): - #1 — surfaced via W18 label match, but track = ``` Don't silently filter — show what was filtered and why, in case user spots a real link manager missed. ## Parent epic rules 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. ### What counts as an epic - An issue that has sub-issues (counter `N / M` shown at top) - Title typically contains track scope (`: — overview`, ` — overview`, ` — delivery `) - 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 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. ### Resolve epic — algorithm at creation / sync 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 - #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 (``, `-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) 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 --owner $YOUR_OWNER --format json # Step 3 — set status lane gh project item-edit \ --id \ --project-id \ --field-id \ --single-select-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. ## 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. - ` 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 #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: #N «title» — has , 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 ; 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 -R "$REPO" --add-label "W{NN}" \ || { gh label create "W{NN}" -R "$REPO" --color "0E8A16" --description "Week {NN}"; \ gh issue edit -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) | ``, ` L3`, ` S2`, `` | | **`{action}`** | Verb + short scope | `prep for meeting `, `process response + intake + slot` | | **`{when / context}`** | Date/window/week in parens at end; optional | `(by )`, `(