| name | session-end |
| description | End-of-session orchestrator. Previews which of wrap/distill/feedback/taskwarrior-sync qualify, single confirm, then sequence. Use when winding down a session. |
| allowed-tools | Bash(bash *), Bash(task *), Bash(git *), Bash(gh *), Read, Skill, AskUserQuestion, TodoWrite |
| created | "2026-06-10T00:00:00.000Z" |
| modified | "2026-08-06T00:00:00.000Z" |
| compatibility | claude-code |
| reviewed | "2026-06-24T00:00:00.000Z" |
session-end
One survey, one preview, one confirmation โ then run only the
end-of-session passes that actually qualify. This is the orchestrator
over three capture skills that used to compete for the wind-down moment
(design decisions D3/D4, docs/archive/session-plugin-workflow.md):
| Pass | Skill | Captures |
|---|
| Wrap | session-plugin:session-wrap | Loose threads โ taskwarrior, optional journal, GitHub issues, upstream issue/PR candidates |
| Distill | session-plugin:session-distill | Durable learnings โ rules, skill updates, justfile recipes, process/methodology (script+recipe or project-local .claude/skills/) |
| Feedback | feedback-plugin:feedback-session | Notable plugin/skill interactions โ GitHub issues on claude-plugins |
| Taskwarrior sync | (inline, no sub-skill) | Close done tasks, update statuses, add follow-ups no open PR/issue already tracks; uses stable UUIDs |
| Blueprint tracker-sync | blueprint-plugin:blueprint-feature-tracker-sync | Drain closed WO-linked tasks from tracker tasks.pending โ tasks.completed (--drain-wave) |
When to Use This Skill
| Use this skill when... | Use alternative when... |
|---|
| User winds down ("wrap up", "done for today") and more than one pass may apply | Only loose threads to capture โ session-plugin:session-wrap directly |
| The Stop-hook nudge offered this skill and the user confirmed | Only learnings to codify โ session-plugin:session-distill directly |
User invokes /session-end | Mid-session single-task close โ taskwarrior-plugin:task-done |
Execution
Execute this orchestration. Not fully automatic by design: filing
GitHub issues and writing a journal are not git restore-able, so the
single confirmation gate below is mandatory.
Step 1: Survey once
One shared decision pass โ do not let each sub-skill re-survey. Run the
shared collector (the same one the wrap/spinup skills and the nudge hook
use); it emits detection, git state, PRs, taskwarrior tasks with stable
UUIDs, and recent commits in one parallel-safe pass. Note two scoping
keys in its TASKWARRIOR section: TASK_SCOPE (project /
remote-name / ancestor-name / all-projects-fallback / unknown /
none) names where OPEN_TASKS was actually counted, and
PROJECT_CONFIDENCE (high / low) says whether that slug can be
trusted โ the detected project is a directory-basename guess and can be
wrong (chezmoi source dirs, worktrees, portfolio checkouts, renamed
clones). A third pair, PROJECT_AMBIGUOUS / PROJECT_AMBIGUOUS_TASKS,
appears only when the detected slug owns zero tasks while a named
ancestor slug owns some:
bash "${CLAUDE_SKILL_DIR}/../../scripts/session-survey.sh" --with-commits --with-blueprint
Pass --project <name> to override the detected project. Hand the digest
to the confirmed passes in Step 4 so they don't re-survey. Plus the
conversation: what finished, what's hanging, what was learned, what
plugin/skill friction or wins occurred.
For the Distill qualify gate (Step 2), also run the distill collector's
coarse summary โ the mechanical half of the Distill signal (recipe candidates,
hot files, process groupings). It degrades to TRANSCRIPT_AVAILABLE=false when
no transcript is reachable, so treat a SKIP as "no mechanical signal, judge
conceptually only":
bash "${CLAUDE_SKILL_DIR}/../../scripts/distill-survey.sh" --session-id "${CLAUDE_SESSION_ID}" --summary
Step 2: Qualify each pass
Apply each skill's own signal filter strictly; silently skip passes
that don't qualify โ offering an empty pass is the drown-in-signals
failure mode.
| Pass | Qualifies when |
|---|
| Wrap | โฅ1 genuine loose thread per session-wrap's LOG IT filter |
| Distill | A durable, generalizable learning emerged AND the repo has a distillable surface (.claude/rules/ or a justfile). Corroborate the mechanical half with the distill collector's --summary (below): RECIPE_CANDIDATE_COUNT / HOT_FILE_COUNT / PROCESS_SIGNAL > 0 means recipes/hot-files/process are worth a pass even if no conceptual rule emerged |
| Feedback | A plugin/skill behaved notably well or badly โ bug, enhancement, or positive worth filing |
| Taskwarrior sync | TASK_AVAILABLE=true AND (OPEN_TASKS โฅ 1 OR RECENT_TASK_COUNT โฅ 1 OR PROJECT_AMBIGUOUS_TASKS โฅ 1) in the Step 1 digest. When PROJECT_CONFIDENCE=low, name the scope actually used (TASK_SCOPE, plus PROJECT_RESOLVED when set) in the Step 3 preview and offer --project <slug> โ a low-confidence zero is an unqueried project, never a clean queue. When PROJECT_AMBIGUOUS is set, render the preview as 0 here, N under <slug> and offer --project <slug>; this fires even at PROJECT_CONFIDENCE=high, because a user-asserted --project and a repo declaration both deliberately keep high โ so the low-confidence escape below does not cover it |
| Blueprint tracker-sync | UNDRAINED_COUNT โฅ 1 in the Step 1 digest's BLUEPRINT section. Non-blueprint / tracker-missing repos auto-disqualify (count is 0) โ silent skip. If blueprint-plugin isn't installed, note it and skip (as with Feedback) |
Blueprint auto-drain (ADR-0020 level 1): when the qualifying repo's
docs/blueprint/manifest.json has automation.autonomy_level โฅ 1 and
task_registry["feature-tracker-sync"].auto_run == true, the Blueprint
tracker-sync pass is auto-confirmed: leave it out of the Step 3 question,
run it in Step 4 order without asking, and report a one-line receipt in Step 5
(Blueprint tracker-sync: drained N WO(s) automatically (auto_run)). All other
passes still go through the Step 3 confirmation. Check the gate with:
jq -r 'if ((.automation.autonomy_level // 0) >= 1) and (.task_registry["feature-tracker-sync"].auto_run == true) then "auto" else "ask" end' docs/blueprint/manifest.json 2>/dev/null
If nothing qualifies, say so in one line and end โ no preview, no
question.
Step 3: One preview, one confirmation
Present a single compact preview: each qualifying pass with a one-line
reason and its concrete payload (the wrap items; the distill proposal
sketch; the feedback finding; the open taskwarrior items with their UUIDs;
for blueprint: Blueprint tracker-sync โ N closed WO task(s) not drained from the feature tracker: WO-โฆ).
Then one AskUserQuestion (multiSelect) listing the qualifying passes
as options, qualifying ones described with their reasons. The user picks
any subset; "Other" covers adjustments.
Never end the turn on a freeform "y/n" text question โ ending the turn
fires Stop hooks mid-confirmation (the race that motivated this
orchestrator). AskUserQuestion keeps the turn open.
Step 4: Sequence the confirmed passes
Run in this order, each via the Skill tool (or inline for taskwarrior
sync), passing along the Step 1 survey so they don't re-do it:
-
Taskwarrior sync (if confirmed) โ run inline before Wrap so Wrap
sees the updated queue state. For each open/active task: ask the user
(via AskUserQuestion) whether to mark done, update, or leave. Address
tasks by stable UUID (task +LATEST uuids after creation;
task <uuid> done / task <uuid> modify for existing tasks). Never
use volatile numeric IDs โ they shift when other tasks complete. Any
follow-up added here obeys Wrap's redundancy test: an open PR or
assigned issue in the Step 1 digest's PRS / GITHUB_DRIFT sections
is already its own tracker โ annotate, never mirror it into a task.
-
session-plugin:session-wrap โ closes/annotates/adds tasks so later
passes see the final queue state. Any upstream issue/PR candidates
it surfaces appear in the Step 3 preview and route per-candidate in
Wrap's own Step 4 (track-for-later vs verify-then-file) under this
mandatory confirmation gate โ filing an upstream issue is not
git restore-able, exactly what the gate exists for. A File now
candidate always routes through
workflow-orchestration-plugin:workflow-verify-before-filing โ
agent-patterns-plugin:cold-read-gate โ file; never blind
-
Blueprint tracker-sync (if confirmed) โ runs after passes 1โ2
because both mutate the taskwarrior queue and may close more WO-linked
tasks after the Step 1 survey. Re-derive the wave inline right before
delegating (never reuse the survey's UNDRAINED_WOS as the drain list):
task bpid.any: status:completed export 2>/dev/null | jq -r --slurpfile t docs/blueprint/feature-tracker.json '([.[] | .bpid // empty] | unique) as $closed | (($t[0].tasks.pending // []) | map(.id)) as $pending | [$closed[] | select(. as $w | $pending | index($w))] | join(",")'
Then invoke /blueprint:blueprint-feature-tracker-sync --drain-wave <list>
with no evidence flags โ the sync skill sources evidence from
taskwarrior annotations itself (its priority order: files โ inline โ
annotation โ ask). If the re-derived list is empty, report "already
drained" and move on. Cross-plugin: if blueprint-plugin isn't
installed, note it and skip
-
session-plugin:session-distill โ apply mode per its own flow; the
user already confirmed the pass, so skip a second blanket prompt but
keep distill's per-category destructive-change prompts
-
โ cross-plugin; if the feedback
plugin isn't installed, note it and skip
Step 5: Report
One short block: what each executed pass wrote (tasks touched / closed,
files edited, issues filed) and which passes were skipped as not qualifying.
Seam: distill vs feedback
"Discovered a better flag / a skill suggested something subtly wrong" โ
feedback (issue on claude-plugins). "Found a reusable project
pattern, rule, or recipe" โ distill (artifact in this repo). When
both apply, both run โ they write to different places.
Auto-surfacing
A Stop hook (hooks/session-end-nudge.sh) offers this skill at most
once per session when the user's own messages carry a wind-down phrase.
It is offer-only and stays silent when this skill (or wrap/distill) is
already in the transcript. Pre-silence:
touch ~/.cache/claude-session-end-nudge/<session_id>.
Agentic Optimizations
| Context | Command |
|---|
| One-pass survey (detection + git + PRs + tasks-with-UUIDs + commits + blueprint tracker state) | bash "${CLAUDE_SKILL_DIR}/../../scripts/session-survey.sh" --with-commits --with-blueprint |
| Trust the task count? | TASK_SCOPE= + PROJECT_CONFIDENCE= in the TASKWARRIOR section (low โ re-run with --project <slug> before treating 0 as clean) |
| Distill qualify signal (recipe/hot-file/process counts) | bash "${CLAUDE_SKILL_DIR}/../../scripts/distill-survey.sh" --session-id "${CLAUDE_SESSION_ID}" --summary |
| Re-derive the drain wave before delegating | task bpid.any: status:completed export | jq โฆ intersected with tracker tasks.pending (Step 4.3) |
| Stable UUID for latest task | task +LATEST uuids |
| Mark task done by UUID | task <uuid> done |
| Distillable surface check | find . -maxdepth 2 -path '*/.claude/rules' -o -maxdepth 1 -name 'justfile' -o -maxdepth 1 -name 'Justfile' |