skills/ris-manager/SKILL.md
--- name: ris-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, create with parent epic + W-label) and read (status lookup across repos). Triggers on "/ris-manager", "sync session", "обнови issues", "синкни сессию", "зафиксируй прогресс", "статус задачи", "что по <track>", "есть ли issue по", "track status", "what about <track>". --- # Ris Manager — bidirectio
npx skillsauth add serejaris/ris-claude-code skills/ris-managerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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. Manager has two modes:
Before first use, define this in your project's CLAUDE.md:
## Ris 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 |
### Issue title domains (closed list)
Closed list used in title formula `{domain}: {object} — {action}`. Customize for your business:
- product, content, partner, crm, infra, legal, ops, meta
### 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: [[<slug>]]
(если не используется — секция игнорируется; см. CRM integration ниже)
No separate init skill needed — this section is the setup.
Every issue manager touches MUST have all three:
<track-slug>, <client>-deal). Track is recognized by title text and epic membership.Without all three — 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.
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 /ris-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 /ris-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.
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.
$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.$YOUR_OWNER/* — authoritative for individual tasks. Search via gh search issues --owner $YOUR_OWNER.Use (write mode):
Use (read mode):
Do NOT use:
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.
$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.Output budget for pre-flight: 0 lines. All findings go into the proposal.
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.
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 (comments, issues, labels)" [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 (comments, issues, labels)" [label="no"];
"Hard blocker / ambiguous write?" -> "Ask concise question / proposal" [label="yes"];
"Execute (comments, issues, labels)" -> "Brief result report";
}
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 parent/W-label 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.
gh search issues --owner $YOUR_OWNER with multiple keys (synonyms, handles, slugs).W18 but unrelated to the queried track). See "False-positive surface" below.sub_issues_summary (gh api repos/<owner>/<repo>/issues/<N> --jq '.sub_issues_summary') — note total, completed, percent_completed + epic's own state.sub_issues_summary.percent_completed = 100 AND state = open. Candidate for closing. Surface as "stale epic" — don't close without user instruction.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:
gh search issues --owner $YOUR_OWNER --state open <key> --json repository,number,title,labels,updatedAt
Keys to try (per artifact/subject):
"<person-name>", <handle>, <filename-slug><track-A>, <track-B>, <client><handle><opportunity-slug>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 in the comment ("related: #N").
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.
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.
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.
N / M shown at top)epic:, <program>: <partner> — overview, ops: <deal> — overview, <product>: delivery <version>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, one per track.
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.
First, search for an existing epic for the track via cross-repo search:
# Issues with non-empty sub_issues_summary.total are epic candidates
gh search issues --owner $YOUR_OWNER "<track-keyword>" --json repository,number,title,url --limit 20
# For each, verify:
gh api repos/<owner>/<repo>/issues/<N> --jq '{title, sub_summary: .sub_issues_summary}'
Working epics always have total >= 1.
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 |
If no epic exists — manager raises in proposal: «no epic for track X, do you want one? If yes — I'll create in <repo> with title <...>». Never creates an issue without a parent silently.
When creating a sub-issue via API:
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
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.
Before gh issue edit / gh issue create the agent MUST:
# (1) If working with an existing issue — what's its parent?
gh api repos/OWNER/REPO/issues/N --jq '{parent: .parent_issue_url, sub_summary: .sub_issues_summary}'
# (2) If parent is absent and the issue is not itself an epic — search for the epic, don't bypass the check
Surface in proposal which issues are missing a parent and which epic is proposed for each.
(Skip this section if W-label convention is disabled in your config.)
date '+%V' if index is stale (>7 days).W{NN} (zero-padded only if existing labels in repo are zero-padded — check repo first).If a task requires action this week AND continues next week — apply BOTH W-labels. Don't pick "the most prominent" — both apply. The index file is for "what's hot now"; labels record full lifecycle.
backlog (create label if missing).W{NN} for that week.backlog AND W{NN} together — pick one.# W-week label (current/future week)
gh label create "W18" -R "$REPO" \
--color "0E8A16" \
--description "Week 18 (Apr 27 - May 3, YYYY)"
# 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.
All new issues created by manager follow a fixed formula — canonical operational layer for agents (predictable parsing, search, groupBy).
{domain}: {object} — {action} ({when / context})
| Segment | What | Examples |
|---------|------|----------|
| {domain} | Closed list from your config. Lowercase. | ops, content, partner, … |
| {object} | Concrete subject (noun, first position) | <track-A>, <product> L3, <deal>, <handle>, <topic> |
| {action} | Verb + short scope | prep for meeting <date>, process response + slot intake |
| {when / context} | Date/window/week in parens at end; optional | (by <date>), (<date> <time>) |
{domain} always from the closed list in your config — don't proliferate variants.{object} is a noun first for search ease (partner: <track-A> groups all that track's tasks).em-dash (—) separator between object and action — visual anchor, easy to parse.partner: <track-A> — prep meeting <date> + budget by <date>mentoring: <person-name> (<handle>) — process response + intake + slotproduct: <product> L3 — final prep for live (<date> <time>)content: <channel> — post recap <month> YYYYlegal: <topic> — complete registration, overdue W17infra: <service> — full-coverage sync without backlogmeta: cross-repo W-label — finalize canonical approachSprint 2 pre-record — setup warp/claude... — no domain🔥 <track>: KP — emoji in titleprep meeting on <date> for <track> — verb-first instead of noun-firstops: all about <event> — too generic, no concrete actionpartner: <track> → divergence ⚠️ overdue — arrow instead of em-dash, emojiIf manager touches an issue with an old title — don't rename automatically. Only rename if user explicitly asked for bulk-rename. Migration of existing issues is a separate task.
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 — user ends up scrolling through history to find current state.
| 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 is attached (if no parent — surface in proposal). |
| Existing issue scope is narrower (e.g. prep meeting) but session expanded scope | Edit body of existing + create new follow-up issue with expanded scope. New issue is a child of the same epic. |
| Multiple existing issues match different aspects (e.g. 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 for the track. If epic exists — link via sub_issues API. If not — surface in proposal: «no epic, create / pick?». W-label current. |
| No existing issue, no track in tasks index, fresh artifact | Ask user which repo + which epic before creating |
Use a comment ONLY when:
## Updates section in body).Anti-pattern signal: if you're about to write the third comment on an issue with the same kind of progress update — that's two too many. Edit body instead.
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 per the rules in this skill.
<one-line context: what changed/what was made>
**Source artifact:** <absolute path or URL>
**Date:** <YYYY-MM-DD>
**Track:** <link to CRM card if commercial — see CRM integration>
## What was done
<2-4 bullets — actual progress>
## Next step
<one line — what closes this issue>
---
Synced by ris-manager from session <YYYY-MM-DD>.
<one-line context: what changed/what was made — same as before, refresh if scope changed>
**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 ...]
## Updates
- **YYYY-MM-DD:** <2-4 bullets of progress / decisions / shifts in this sync>
- **YYYY-MM-DD:** <previous sync entry, kept>
- ...
Newest update at top of ## Updates section, oldest at bottom (or vice versa — pick once per issue and stay consistent within it).
**YYYY-MM-DD:** <one-line note that doesn't fit body — e.g. "external blocker until X", "transient state observation">
Keep comments short. If a comment grows beyond 4 lines — it belongs in body.
Always use <repo>#N — «human title» form when surfacing an issue to the user. Bare <repo>#27 is unreadable — user needs the title to recognize the track at a glance.
<repo>#27 → comment + W19<repo>#27 «<track-A> · strategy — respond to brief» → comment + W19In compact lists, you may put title in quotes/parens; in tables, title goes in its own column. Never just the number.
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> · strategy track — respond to brief» [parent: crm#15 ✓]
→ comment about pricing / timeline; +W19 (next step in W19)
- crm#25 «<track-A>: prep meeting <date> + final <date>» [parent: crm#15 ✓]
→ comment "both meetings done"; close if prep scope fully done; else keep open with reason
<track-B> · epic crm#10 «<track-B>: partnership Q2»
- crm#24 «<track-B>: opp divergence + overdue» [parent: crm#10 ✓]
→ comment about async-first + scope expansion
- teach-vibecoding#250 «<track-B>: program in LMS» [parent: MISSING]
→ attach as child crm#10 + comment about video by <date>
- NEW issue in crm: «<track-B>: scope expanded without re-pricing — raise on sync by <date>» (W18+W19, child crm#10)
Labels to create: W19 in $YOUR_OWNER/crm
Epics missing coverage:
- (none — all session tracks have an epic)
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 «ops: <X> — overview» as umbrella; all 3 issues below become sub-issues.
OR
- Use existing <repo>#N «<title>» (sub_summary total=N) — ask if ambiguous.
Done:
- crm#27 «<track-A> · strategy track» — body update + W19; parent: crm#15 ✓
- crm#24 «<track-B>: opp divergence» — body update; parent: crm#10 ✓
- teach-vibecoding#250 «<track-B>» — body update + attached as child crm#10
- crm#42 «<track-B>: scope expanded» — created, child crm#10, W18+W19
- W19 label created in $YOUR_OWNER/crm
Skipped per your decision: crm#25 «<track-A>: prep…» — left open
Compact table — always with a «Title» column, parent epic in its own 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 | Activity | Status |
|-------|-------|--------|---------|----------|--------|
| crm#27 | <track-A> · strategy — respond to brief | crm#15 ✓ | W18 | <date> | Active — KP due <date> |
| crm#25 | <track-A>: prep <date> + final <date> | crm#15 ✓ | W18 | <date> | Both meetings done — likely stale |
| corp-decks#9 | <track-A>: deck — express audit | — ⚠️ | W18 | <date> | No parent, 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 — corp-decks#9. Attach on next sync.
- W-label OK on all 3.
Drift in index / epic state:
- (optional) crm#15 epic — 5/5 sub-issues done, state OPEN. Candidate to close.
- (optional) tasks index row «X» references crm#NN that's already CLOSED — index stale.
Filtered (false positives):
- crm#1 «<unrelated>: complete» — surfaced via W18 label, unrelated to <track-A>
weekly-planning skill.retro:W* labels appear): see weekly-retro skill — these labels carry historical signal, don't strip.| Mistake | Fix |
|---------|-----|
| Closing issues without explicit user instruction | Comment-and-leave-open is default. Only close if user said "close" or issue scope is fully delivered AND user mentioned completion. |
| 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 task spans current week + next week, apply both. See W-label rules. |
| Creating new issue when comment in existing fits | Search broadly first. Multiple keys. Only create if scope clearly diverges. |
| Skipping W-label create when missing in repo | Iron invariant — every issue must have W-label (if convention enabled). Create the label, don't skip. |
| Creating/touching an issue without a parent epic | Iron invariant — every issue (except the epic itself) must have a parent via Sub-issues API. If parent is absent — surface in proposal, don't be silent. |
| Creating a new track-label (<track-slug> etc.) | No longer done. Track differentiation = title + epic membership. Existing legacy labels are kept but not extended. |
| Attaching one issue to two epics | GitHub supports one parent. If a task relates to two tracks — reconsider scope, split into two issues, one per track. |
| Markdown Parent: #N in body when API link exists | Duplicate, goes stale. Parent — only via Sub-issues API. Body — what the task is and how to do it. |
| Not respecting 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 task list to mutate | The tasks index file is read-only context for manager. Don't edit it. Index is curated by user / weekly-planning skill. |
| Acting on uncommitted local changes as "done" | If git status shows uncommitted work — surface in UNCOMMITTED section of report. Don't block sync, but flag so user can commit before issue comments link to a not-yet-pushed artifact. |
| Silently filtering false-positive matches | Drop from primary results but show in IGNORED (false positives) section. Don't hide — user may spot a real link manager missed. |
| Treating every invocation as write mode | Check first: did user give artifacts/changes (write) OR ask a question about state (read)? Use mode resolution diagram at top of skill. |
Parent: #N / Epic: #N in body when parent is set via API — duplicate, goes stale. Body = what the task is; parent = Sub-issues API.state = open is a real signal: either delivery has loose ends not captured as sub-issues, or epic is closeable. Surface as candidate-to-close; never auto-close.<repo>#27 alone. Always <repo>#27 «title». Numbers are unrecognizable; titles convey track at a glance.gh search is shotgun across random keywords. Pre-flight is not optional.gh issue view <repo>/<N> --comments yourself and bring the content back. Don't hand the work back to the user.gh issue edit --body-file with refreshed Status/Next + dated entry in ## Updates. Comment only if note is genuinely ephemeral or user explicitly asked.Activate by setting crm_path and crm_pointer_format in your 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.
Example body fragment:
**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.
tools
Use when transitioning from retro to weekly plan, prioritizing backlog, choosing outcomes for the week, or when user says "план на неделю", "планирование", "W13 plan", "outcomes", "приоритизация". Runs after weekly-retro skill.
testing
Use when preparing for, running, or closing a live meeting with an AI assistant dashboard. Triggers on "meeting copilot", "live copilot", "prepare for a call", "update copilot", "close the session", or requests to turn transcript chunks into meeting questions, topic maps, decisions, and follow-ups.
tools
Use when conducting weekly retrospective, reviewing past week, or when user says "retro", "weekly retro", "week review". Triggers at end of week or start of new week.
tools
Use when creating GitHub issues, adding tasks to backlog, or when unsure which repo/project an issue belongs to. Triggers on "создай задачу", "issue", "добавь в бэклог", "task routing", "куда положить задачу".