session-wrap

v2026.09.24

End-of-session capture to taskwarrior, optional journal, GitHub issues. Use when user says wrap up, session wrap, or done for now.

GitHub
Install command
npx skhub add laurigates/session-wrap
Markdown
SKILL.md

session-wrap

End-of-session capture for the things that won't surface on their own next time the user sits down. The failure mode this prevents: follow-up work gets agreed in conversation, the session ends, and a week later the user can't remember what was left hanging.

When to Use This Skill

Use this skill when...Use alternative when...
User says "wrap up", "session wrap", "done for now"Full end-of-session pass incl. distill/feedback → session-plugin:session-end
Loose threads need capturing before the session endsCapturing reusable learnings (rules/recipes) → session-plugin:session-distill
One task needs closing with audit trail mid-session→ taskwarrior-plugin:task-done

Configuration

Read per-user/per-project config before doing anything:

  1. .claude/session-plugin.local.md in the project (wins)
  2. ~/.claude/session-plugin.local.md (user-global fallback)
  3. Neither exists → taskwarrior + GitHub-issue destinations only; no journal

YAML frontmatter carries the journal settings (journal, journal_path, journal_template, heading targets, journal_scopes); the markdown body carries freeform scope-detection heuristics and the user's taskwarrior project-naming map — read it and apply it as context. Full schema and a worked example: REFERENCE.md.

Destinations

DestinationWhenWhat goes there
taskwarriorEvery wrapMark completed tasks done; annotate in-flight tasks with PR / blocker / state; add tasks only for threads no open PR or issue already tracks (see "Don't duplicate an existing tracker")
Journal (e.g. Obsidian daily note)Only when configured AND the session matches journal_scopesNarrative log entry; actionable todo items
GitHub issuesOnly when cwd has a github.com origin AND a PR merged (or is about to) with post-merge follow-upsOne issue per follow-up, linked from the PR description
Upstream issue/PR candidateA bug/gap noticed in a third-party github.com repo, or a local fix that belongs upstreamTrack for later (+upstream task) OR a verified issue / local-fix backport — never filed blind (Step 4 routes each candidate)

Out-of-scope sessions get only the taskwarrior pass (plus GitHub issues if applicable). Default to skipping the journal when scope is unclear — better than spamming it. Ask once if genuinely ambiguous.

The signal filter

This is the whole point. Log only what the user would miss tomorrow.

LOG IT: task started but blocked · manual follow-up outside Claude Code · deferred decision · untracked loose thread (bug noticed in passing, doc to write) · investigation finding worth not losing · upstream candidate (bug/docs-gap/feature-gap noticed in a dependency, or a local fix that belongs upstream — route it in Step 4, never file blind).

DO NOT LOG: work that finished cleanly (mark the task done, don't narrate it) · an open PR or assigned issue as its own task — the PR/issue is the tracker (below) · anything already tracked that didn't change state · routine ops · self-resolving items ("CI still running") · conversational context · speculation ("might refactor X someday") · anything already tracked upstream (an existing third-party issue/PR that didn't change).

Litmus, both clauses: "If I don't write this down, will the user notice the gap tomorrow — and is there no open PR or issue already carrying it?" Both yes → log. Either no → skip. 3-6 items per wrap is the right shape; 10+ means the filter is too loose. Worked examples: REFERENCE.md.

Don't duplicate an existing tracker

An open PR or assigned issue is its own tracker. The Step 1 digest's PRS section carries every open PR (with PR_n_STALE_DAYS) and GITHUB_DRIFT every assigned-but-untracked issue, and session-plugin:session-spinup surfaces both next session — so a task reading "PR #N is open / needs merging" only duplicates them, and taskwarrior-plugin:task-reconcile closes it on merge anyway. A task earns its existence when it carries something the PR or issue does not:

SituationDestination
PR open, awaiting review/merge, nothing else to saynothing — the PRS section is the reminder
PR open and an existing task covers that workannotate the existing task with the PR URL (this is what lets reconcile close it on merge) — never a second task
Assigned GitHub issue, no local tasknothing — GITHUB_DRIFT surfaces it at spinup
A manual step, deferred decision, or blocker the PR/issue body doesn't recordtaskwarrior task — or, for a post-merge step, one GitHub issue linked from the PR

Check a candidate's PR/issue number against PRS / GITHUB_DRIFT before adding — a hit means annotate, not add. Same test for journal todos.

Execution

Execute this wrap workflow:

Step 1: Survey

Run the shared read-only collector — it does project detection, the git/PR/taskwarrior survey, and recent commits in one parallel-safe pass, emitting each task with its stable UUID so Steps 2/4 never operate on a volatile numeric ID:

bash "${CLAUDE_SKILL_DIR}/../../scripts/session-survey.sh" --with-commits --with-dedup

Pass --project <name> when the config naming map maps the cwd to a project other than the repo basename; when detection is ambiguous (DETECTION=ambiguous) and unclear, list task _projects and ask once. --with-dedup populates GITHUB_DRIFT, which the "Don't duplicate an existing tracker" section below reads — without it the section is always empty and the check silently passes against nothing. That section's GH_READY matters too: false means PRS/GITHUB_DRIFT are present but unqueried, not "nothing open" — never treat an empty section under GH_READY=false as license to add a task that duplicates an untracked PR/issue. The GH_FAIL_REASON= beside it says whether that is worth fixing before you file: re-run once for timeout / api-error / unknown; for auth / no-cli the dedup set is simply unavailable this session, so keep the bar for adding a task high; for no-remote there is no PR/issue to duplicate and the caveat does not apply. Then read the conversation itself — what was kicked off but not finished, discussed but not done.

Step 2: Categorise

CategoryAction
Done this sessiontask <uuid> done
In-flight, well-trackedAnnotate the existing task with the new state
Already tracked by an open PR / assigned issueNo task — annotate an existing task with the URL if one covers the work; otherwise skip (spinup replays it)
In-flight, untrackedNew taskwarrior task or journal todo (not both)
Loose thread, in journal scopeJournal log (narrative) or todo (action)
Loose thread, out of scopeTaskwarrior only, with project:<name>
Post-merge follow-up (GitHub repo)One gh issue create per follow-up; link from the PR
Upstream candidate (third-party repo)Per-candidate routing in Step 4 (track for later or verify-then-file)
Noise (per filter)Skip silently

Resolve numeric task IDs to UUIDs at read time (task _get <id>.uuid) and operate on UUIDs — IDs shift when any task completes.

Step 3: Preview and confirm

Show a compact preview of everything about to be written (per-destination blocks; one block per project if several were touched).

Then confirm with AskUserQuestion — options like "Apply", "Apply without journal", "Adjust first". Never end the turn on a freeform "Apply? (y/n)" text question: ending the turn fires Stop hooks, which can inject content and split the confirmation (this raced the old nudge hook in production). AskUserQuestion keeps the turn open — no Stop event, no race. Where AskUserQuestion is unavailable (a harness without the tool), ask in plain text and end the turn.

Step 4: Apply

Taskwarrior: task <uuid> done / task <uuid> annotate "..." / task add project:<name> priority:M +<tag> '<description>'. Annotate before closing. Journal: append per the configured headings — mechanics in REFERENCE.md. GitHub: one issue per follow-up, then edit the PR description to link them.

Upstream candidates: route each one with an AskUserQuestion — two equal-weight options (no default lean):

  • Track for later → task add project:<name> +upstream '<desc — name the upstream repo + what/why>'. No outward action; the +upstream tag is where "file this upstream" work surfaces later (taskwarrior-plugin:task-add).

  • File now → hand off, in order:

    1. workflow-orchestration-plugin:workflow-verify-before-filing — verify the bug still exists at upstream HEAD and dedup against the tracker.
    2. agent-patterns-plugin:cold-read-gate — body legibility + internal-context-leak check before anything is published (public-export-sanitization.md).
    3. File the issue (git-plugin:github-issue-writing) or open the local-fix backport. When commenting on an existing issue, read the full thread first (git-plugin:git-issue-scoping).

    Graceful degradation: if workflow-orchestration-plugin is not installed (mirrors the feedback-plugin / blueprint-plugin cross-plugin fallback in session-end), fall back to git-plugin:github-issue-writing + an explicit manual upstream-HEAD verification, or route to Track for later instead — never file unverified.

Step 5: Report

One paragraph: what was written where, plus the count of items skipped as noise so the user can sanity-check the filter.

Auto-surfacing

A Stop hook (hooks/session-end-nudge.sh) offers session-plugin:session-end (which can route here) once per session on genuine user wind-down phrasing. It stays silent while this skill is running. Pre-silence for a session: touch ~/.cache/claude-session-end-nudge/<session_id>.

Agentic Optimizations

ContextCommand
Survey (detection + git + PRs + tasks-with-UUIDs + commits + GitHub-drift dedup)bash "${CLAUDE_SKILL_DIR}/../../scripts/session-survey.sh" --with-commits --with-dedup
Batch close by UUIDtask rc.confirmation:no <uuid> done
Add a tasktask rc.confirmation:no add project:<name> +<tag> '<desc>'
Known projectstask _projects
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

session-plugin/skills/session-wrap

Default branch

main

Latest commit

1668324

Tree SHA

b2d4cc3