session-review

End-of-session orchestrator. Auto-saves decisions (mnemo:memory-routing) and creates session notes (mnemo:session-notes) without asking. Then recommends remaining skills. Triggers on: 'что забыли', 'session review', 'что осталось', 'all done?', 'review', end of significant work. The ONLY command users need at session end — handles everything.

mnemo:review — Skill-Aware Session Completeness Analyzer

You are performing a thorough end-of-session review. Analyze everything: what was done, what was missed, which skills should have been invoked, and offer to execute them.

Session Data (Preprocessed)

Git State

!echo "=== STATUS ===" && git status --short 2>/dev/null && echo "=== BRANCH ===" && git branch --show-current 2>/dev/null && echo "=== LOG ===" && git log --oneline -10 2>/dev/null && echo "=== UNCOMMITTED ===" && git diff --stat 2>/dev/null && echo "=== STAGED ===" && git diff --staged --stat 2>/dev/null

Open PRs

!gh pr list --author @me --state open --json number,title,url 2>/dev/null || echo "gh: not available"

Tools & Skills Used This Session

!`python3 << 'PYEOF' import json, sys, os, glob

session_id = '${CLAUDE_SESSION_ID}' if not session_id or '${' in session_id: print('SESSION_ID: not available') sys.exit(0)

home = os.path.expanduser('~') jsonl_path = None for d in glob.glob(os.path.join(home, '.claude/projects/*/')): candidate = os.path.join(d, session_id + '.jsonl') if os.path.exists(candidate): jsonl_path = candidate break

if not jsonl_path: print('JSONL: not found — use conversation context for analysis') sys.exit(0)

tools = {} skills = [] commits = 0 files_written = set() errors = 0

with open(jsonl_path) as f: for line in f: try: msg = json.loads(line) content = msg.get('message', {}).get('content', []) if not isinstance(content, list): continue for block in content: if not isinstance(block, dict): continue if block.get('type') == 'tool_use': name = block.get('name', '') tools[name] = tools.get(name, 0) + 1 inp = block.get('input', {}) if name == 'Skill': s = inp.get('skill', '') if s: skills.append(s) elif name in ('Write', 'Edit'): fp = inp.get('file_path', '') if fp: files_written.add(fp) elif name == 'Bash': cmd = inp.get('command', '') if 'git commit' in cmd: commits += 1 elif block.get('type') == 'tool_result' and block.get('is_error'): errors += 1 except: continue

print(f'TOTAL_TOOL_CALLS: {sum(tools.values())}') for t, c in sorted(tools.items(), key=lambda x: -x[1])[:20]: print(f' {t}: {c}') print(f'\nSKILLS_INVOKED: {", ".join(skills) if skills else "none"}') print(f'FILES_MODIFIED: {len(files_written)}') if files_written: exts = {} for fp in files_written: ext = os.path.splitext(fp)[1] or 'no-ext' exts[ext] = exts.get(ext, 0) + 1 print(f' Extensions: {", ".join(f"{e}({c})" for e, c in sorted(exts.items(), key=lambda x: -x[1]))}') for fp in sorted(files_written)[:15]: print(f' {fp}') print(f'COMMITS: {commits}') print(f'ERRORS_SEEN: {errors}') PYEOF `

All Available Skills (Auto-Discovered)

!`python3 << 'PYEOF' import os, glob, re

home = os.path.expanduser('~') skills = [] seen = set()

patterns = [ os.path.join(home, '.claude/skills//SKILL.md'), os.path.join(home, '.claude/plugins//skills//SKILL.md'), os.path.join(home, '.claude/plugins/cache////skills//SKILL.md'), os.path.join(home, '.claude/plugins/marketplaces//plugins//skills//SKILL.md'), '.claude/skills//SKILL.md', 'plugins//skills/*/SKILL.md', ]

for pat in patterns: for path in glob.glob(pat): if path in seen: continue seen.add(path) try: with open(path) as f: head = f.read(600) name_m = re.search(r'^name:\s*["']?(.+?)["']?\s*$', head, re.M) desc_m = re.search(r'^description:\s*["']?(.+?)["']?\s*$', head, re.M) if not name_m: continue name = name_m.group(1).strip() desc = desc_m.group(1).strip()[:100] if desc_m else ''

        parts = path.replace(home, '~').split('/')
        plugin = ''
        if 'plugins' in parts:
            idx = parts.index('plugins')
            candidate = parts[idx + 1] if idx + 1 < len(parts) else ''
            if candidate == 'marketplaces' and idx + 3 < len(parts):
                plugin = parts[idx + 3]
            else:
                plugin = candidate

        qualified = f'{plugin}:{name}' if plugin else name
        if qualified not in seen:
            seen.add(qualified)
            skills.append(f'{qualified} — {desc}')
    except:
        continue

skills.sort() for s in skills: print(s) print(f'\nTOTAL_SKILLS: {len(skills)}') PYEOF `

$ARGUMENTS

Workflow

Step 1: Load Project Context

Read CLAUDE.md for project-specific rules:

cat CLAUDE.md 2>/dev/null | head -300

Check memory index:

cat .claude/projects/*/memory/MEMORY.md 2>/dev/null | head -100

Step 2: Determine Session Type

Classify by primary activity using preprocessed data + conversation history:

TypeKey signals
ImplementationWrite/Edit heavy, commits, new files, "feat/add" keywords
ResearchRead/Grep/WebSearch/Agent heavy, few writes
DebuggingError patterns, "fix" commits, investigation flow
RefactoringRenames, large diffs, net-zero line changes
Documentation.md files dominant, few code changes
ConfigurationConfig/CI/deploy files changed
PlanningPlan mode, brainstorm docs, no code

State the detected type explicitly.

Step 3: Full Session Scan

From conversation history + preprocessed data, identify:

  1. User requests — all explicit and implicit asks. Were they all fulfilled?
  2. Decisions made — architecture, approach, scope choices. Were they saved?
  3. Actions completed — commits, PRs, file changes, deployments
  4. TODOs mentioned — "потом", "later", "TODO", "FIXME" in conversation or code
  5. Errors encountered — all resolved? Workarounds or proper fixes?
  6. Questions asked — by user or Claude, answered or dropped?
  7. External systems — Linear tasks, GitHub PRs, Obsidian notes — updated?

Step 4: Skill Gap Analysis

Cross-reference:

  • Session type (Step 2) → expected skill categories
  • Signals detected (Step 3) → specific skill triggers
  • Skills already invoked (preprocessed SKILLS_INVOKED)
  • All available skills (preprocessed auto-discovery)

CRITICAL: Only recommend skills that appear in the auto-discovered list. Never recommend skills that aren't installed.

Trigger Matrix by Session Type

Implementation sessions:

SignalRecommended skillPriority
New code without corresponding teststest-master, test-driven-developmentCRITICAL
Web app code (.html/.tsx/.jsx/.css)vibesec, design-reviewHIGH
Diff > 100 lines, single featuresimplifyMEDIUM
Branch diverged from main, tests passshipHIGH
API endpoints added or changedapi-designerMEDIUM
Django models/views toucheddjango-expertMEDIUM
Rails code toucheddhh-rails-styleMEDIUM
Database migrations in diffpostgres-pro, data-integrity-guardianHIGH
Frontend components modifieddesign-review, polishMEDIUM

Research sessions:

SignalRecommended skillPriority
Findings/discoveries not savedmnemo:saveCRITICAL
No session summary createdmnemo:sessionHIGH
New knowledge links to existing notesmnemo:connectMEDIUM

Debugging sessions:

SignalRecommended skillPriority
Root cause identified (save as gotcha)mnemo:saveHIGH
Fix committed without regression teststest-masterCRITICAL
Investigation log worth preservingmnemo:sessionMEDIUM

All sessions (universal triggers):

SignalRecommended skillPriority
Significant work done, no session notesmnemo:sessionHIGH
Decisions in conversation, not persistedmnemo:saveHIGH
Uncommitted changes in working treecommitCRITICAL
Branch ready, no PR createdshipHIGH
Project has memory routing rules (CLAUDE.md)check all memory backendsMEDIUM
New Obsidian notes created this sessionmnemo:connect, mnemo:healthLOW
Plan created but not reviewedplan-eng-review, plan-ceo-reviewMEDIUM
Code written, no review passreview, ce:reviewMEDIUM
CLAUDE.md needs updatingclaude-md-management:revise-claude-mdLOW

Also check for custom triggers:

cat "${CLAUDE_SKILL_DIR}/skill-triggers.md" 2>/dev/null

Step 5: Cross-Reference Project Rules

From CLAUDE.md, check mandatory steps:

Rule categoryWhat to check
Git flowPR created? Correct format? Draft or ready?
CI checksTests run? Lint passing? Type-check?
Memory routingAll required backends updated? (Obsidian, claude-mem, memory/)
Session handoffHandoff note updated in Obsidian?
Task trackerLinear/GitHub issue status moved? PR linked?
DocumentationREADME/docs match code changes?
Stop-rulesAny project-specific rules violated?

Step 6: Generate Report

Respond in the user's language (match conversation language).

BLUF: score first, then details.

## Session Review

**Project:** {name}
**Branch:** {branch}
**Type:** {session type}
**Task:** {one-line summary}

### Done ({count})

| # | What | Evidence |
|---|------|----------|
| 1 | {item} | {commit hash / PR / file path} |

### Missed ({count})

| # | What | Priority | Action |
|---|------|----------|--------|
| 1 | {item} | CRITICAL | {specific action} |

### Hanging Threads ({count})

| # | What | Where mentioned | Next step |
|---|------|----------------|-----------|
| 1 | {item} | {context} | {action} |

### Skill Gap

**Invoked this session:** {list, or "none"}

**Should have been invoked:**

| # | Skill | Why | Priority |
|---|-------|-----|----------|
| 1 | /mnemo:session | Significant work done, no session notes | HIGH |

**Correctly skipped:** {skills matching signals but rightly unused, with reason}

### Score: {X}/10

| Dimension | Status | Detail |
|-----------|--------|--------|
| Code | {status} | |
| Tests | {status} | |
| Memory | {status} | |
| Docs | {status} | |
| PR / Git | {status} | |
| Skills | {used/recommended} | |

Step 7: Auto-Execute Core Skills

After the report, automatically run save + session without asking — these are the two skills that matter most and the user expects them to happen.

Auto-run (no confirmation needed):

  1. mnemo:memory-routing (save) — if unsaved decisions/findings detected, extract them and invoke:
    Skill(skill: "mnemo:memory-routing", args: "{extracted decisions and findings}")
    
  2. mnemo:session-notes (session) — if significant work was done, invoke:
    Skill(skill: "mnemo:session-notes", args: "")
    

Order matters: save before session (decisions should be persisted before session note references them).

Skip auto-run if: the skill was already invoked this session (per SKILLS_INVOKED preprocessing).

Step 8: Offer Remaining Skills

For everything else, ask the user:

Auto-completed:
  ✅ /mn:save — 3 decisions saved
  ✅ /mn:session — session note created

Also recommended:

  1. [CRITICAL] /commit — 5 uncommitted files
  2. [MEDIUM] /mn:connect — 2 new notes, find links?
  3. [LOW] /mn:health — vault audit after mass creation?

Run any? (1,2,3 / A=all / N=skip)

Execution rules:

  1. Run skills sequentially using the Skill tool
  2. Brief status after each
  3. Dependency order: /commit before /ship
  4. After all done, output updated score

Rules

  • Always thorough — full analysis, no shortcuts
  • BLUF — score and critical items first
  • Be specific — "3 unsaved decisions: X, Y, Z" not "maybe save something"
  • Don't nag — skill already ran per SKILLS_INVOKED? Skip it
  • Don't hallucinate skills — only recommend from auto-discovered list
  • Project rules override — CLAUDE.md > generic recommendations
  • Execution order — commit → review → ship → session → save
  • User's language — match conversation
  • Preprocessing fallback — if JSONL/discovery failed, gather data with Bash at runtime
  • Don't over-report — unchecked plan AC is noise if code + tests pass
  • Multiple projects — analyze each project dir separately
  • Respect completed work — /mnemo:save already ran? Acknowledge, don't re-recommend