archived/skills/recap/SKILL.md
Reconstruct plain-English narrative of recent work from session summaries
npx skillsauth add nicsuzor/academicops recapInstall 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.
Taxonomy note: This skill provides analysis (HOW) for reconstructing narrative context from session summaries. See [[TAXONOMY.md]] for the skill/workflow distinction.
Reads session summary files to reconstruct a plain-English narrative of what the user was working on, where attention shifted, and what got derailed.
This skill analyzes the JSON session summaries in $AOPS_SESSIONS/summaries/ to produce:
/recap # Last 3 days (default)
/recap 7 # Last 7 days
/recap today # Today only
/recap yesterday # Yesterday only
import json, os, glob
from datetime import datetime, timedelta, timezone
# Parse arguments
days = 3 # default, or parse from args
summaries_dir = os.path.join(os.environ.get('AOPS_SESSIONS', os.path.expanduser('~/.polecat/sessions')), 'summaries')
# Calculate date range
end_date = datetime.now(timezone.utc)
start_date = end_date - timedelta(days=days)
# Find all summary files in range
all_files = sorted(glob.glob(os.path.join(summaries_dir, '*.json')))
sessions = []
for f in all_files:
basename = os.path.basename(f)
# Skip auto-commit sessions — they're noise
if 'commit-changed' in basename or basename.startswith('sessions-'):
continue
with open(f) as fh:
try:
data = json.load(fh)
except json.JSONDecodeError:
continue
# Parse date from the JSON data
date_str = data.get('date', '')
if not date_str:
continue
try:
# Handle ISO format with timezone
session_date = datetime.fromisoformat(date_str)
if session_date.tzinfo is None:
session_date = session_date.replace(tzinfo=timezone.utc)
if session_date.astimezone(timezone.utc) < start_date:
continue
except (ValueError, TypeError):
continue
# Extract user prompts from timeline events
prompts = []
for event in data.get('timeline_events', []):
if event.get('type') == 'user_prompt':
prompts.append(event.get('description', ''))
sessions.append({
'file': basename,
'session_id': data.get('session_id', ''),
'date': date_str,
'project': data.get('project', 'unknown'),
'summary': data.get('summary'),
'outcome': data.get('outcome'),
'accomplishments': data.get('accomplishments', []),
'friction_points': data.get('friction_points', []),
'proposed_changes': data.get('proposed_changes', []),
'prompts': prompts,
'duration_min': data.get('token_metrics', {}).get('efficiency', {}).get('session_duration_minutes', 0),
'tokens_out': data.get('token_metrics', {}).get('totals', {}).get('output_tokens', 0),
})
# Sort chronologically
sessions.sort(key=lambda s: s['date'])
Group sessions by date (calendar day), then within each day by project. For each session, note:
prompts and summary)outcome and accomplishments)friction_points)A context switch is when the project changes between consecutive sessions, or when the user's prompts within a session shift topic significantly.
A distraction is a context switch to a short session (< 5 min or < 500 output tokens) that doesn't produce accomplishments — it suggests the user poked at something and then came back.
A rabbit hole is a long session (> 30 min) that started as one thing but the prompts show it evolved into something different.
An unfinished thread is a session where the user asked about something but the outcome is null or the accomplishments are empty, and there's no follow-up session on the same topic.
Present the narrative as a readable story, organized by day. Use this structure:
## [Day, Date]
### Morning / Afternoon / Evening (based on timestamps)
**[Project]**: [What was being worked on, in plain English]
- [Key prompts paraphrased]
- [Outcome: what was accomplished or left unfinished]
→ _Context switch_: [why this looks like a switch — different project, different topic]
### Distraction detector
- [Short sessions that didn't produce results]
- [Topic jumps that suggest the user got pulled away]
### Threads left hanging
- [Topics started but not completed, with no follow-up]
At the end, include:
## Overall
**Main threads**: [The 2-3 primary things the user was actually trying to accomplish]
**Biggest distractions**: [What pulled attention away most often]
**Completion rate**: [X of Y substantive sessions produced concrete outcomes]
**Suggestion**: [Based on the pattern, what should the user focus on next]
sessions- (auto-commit bots)commit-changed in the filename^[a-f0-9]{7,8}$)Many sessions have null summaries (insights not generated). For these:
timeline_events[].description (user prompts) to infer what was happeningproject to group by workstreamtoken_metrics.efficiency.session_duration_minutes to gauge depth of engagementaops project are framework development workdiffie, galileo, brain, mem etc. are research/content projects/aops-core:strategy or /daily prompts are planning/reflection, not production work/session-insights - Generate detailed insights for individual sessions/daily - Daily briefing and planning/path - Narrative path reconstruction from session transcriptsdata-ai
Canonical session close — commit, push, PR, release_task, reflection blocks, handover. Use /dump for emergency bail (no commit/PR/reflection).
data-ai
Emergency session bail — fast resume task + short handover, no commit/PR/reflection. For when you (or the user) need a clean context now. Use /end-session for canonical close.
data-ai
Daily note lifecycle — compose and maintain a factual daily note. Reports the state of the day; does not prioritise or recommend. SSoT for daily note structure.
testing
Launder supervisor/worker task-log output into a Nic-facing narrative — what happened, where things are headed, and what (if anything) is genuinely his to decide. Never relays raw process detail (worker IDs, thread pointers, log paths) or verbatim task-log stream-of-consciousness.