| name | session-closure |
| description | > Use when this capability is needed. |
Session Closure Protocol
Contents
- Closure Steps
- Additional Documentation
Closure Steps
Step 0: Check Permissions (ONE-TIME SETUP)
Purpose: Verify session-skills permissions are configured to prevent repeated permission prompts.
Why this matters:
- Claude Code's interactive permission approval doesn't persist across sessions
- Without pre-approved permissions, users get repeated prompts for every skill script
- One-time setup enables smooth session-resume and session-closure operation
Implementation:
Run the permission check script:
"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/check_permissions.sh" "${PROJECT_ROOT:-$PWD}"
Script behavior:
- All permissions present: Exits silently (code 0) → proceed to Step 0.5
- Permissions missing/outdated: Exits with details (code 1) → offer configuration
- No settings file: Exits with MISSING_FILE marker → offer to create
When configuration needed:
The script outputs structured information:
- MISSING_REQUIRED: Critical permissions needed for skills to function
- MISSING_RECOMMENDED: Optional permissions for better UX (git, rsync, etc.)
- FOUND_OLD: Deprecated patterns that should be removed (e.g.,
session-* wildcards)
Present configuration offer to user:
🔧 Session skills need one-time permission setup
[If missing file:]
No .claude/settings.local.json found. I'll create one with required permissions.
[If missing patterns:]
Missing required permissions ([count] patterns):
- Skill(session-closure)
- Skill(session-resume)
- [List other missing REQUIRED patterns]
[If old patterns found:]
Found deprecated patterns ([count] to remove):
- Bash(~/.claude/skills/session-closure/scripts/*)
- [List other FOUND_OLD patterns]
I can configure these automatically using this inline script:
[Show inline bash script that will be executed]
May I update .claude/settings.local.json to add these permissions?
After user approval, execute inline configuration script:
#!/bin/bash
PROJECT_DIR="${PROJECT_ROOT:-$PWD}"
SETTINGS_FILE="$PROJECT_DIR/.claude/settings.local.json"
mkdir -p "$PROJECT_DIR/.claude"
REQUIRED_PATTERNS='[
"Skill(session-closure)",
"Skill(session-resume)",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/check_permissions.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-resume}/scripts/check_permissions.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/check_uncommitted_changes.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/archive_resume.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/validate_resume.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/commit_resume.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-resume}/scripts/check_uncommitted_changes.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-resume}/scripts/list_archives.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Bash(\"${SKILL_BASE:-$HOME/.claude/skills/session-resume}/scripts/check_staleness.sh\" \"${PROJECT_ROOT:-$PWD}\")",
"Read(~/.claude/skills/session-closure/**)",
"Read(~/.claude/skills/session-resume/**)"
]'
OLD_PATTERNS=(
'Bash(~/.claude/skills/session-closure/scripts/*)'
'Bash(~/.claude/skills/session-resume/scripts/*)'
)
if [ ! -f "$SETTINGS_FILE" ]; then
cat > "$SETTINGS_FILE" <<EOF
{
"permissions": {
"allow": $REQUIRED_PATTERNS,
"deny": [],
"ask": []
}
}
EOF
-v jq >/dev/null 2>&1;
REQUIRED_JSON=$( | jq -c )
jq --argjson new \
\
> &&
After configuration:
- Proceed to Step 0.5 (uncommitted changes check)
- Future sessions will skip this step (permissions already configured)
Error handling:
- Script not found: Display error, proceed with warning (user will get permission prompts)
- Script fails: Display error, proceed with warning
- User declines: Proceed anyway (user will approve permissions interactively)
Step 0.1: Project Pre-Check Hook (OPTIONAL)
Purpose: Allow projects to run custom preparation before the uncommitted changes check.
Why this matters:
- Projects may have files that should be stashed, not committed (e.g., Apple Pages autosave)
- Project-specific protocols exist in LOCAL_CONTEXT.md but skills don't read them
- This hook enables mechanical enforcement of project-specific behavior
- Backward compatible: skipped if no hook exists
Implementation:
Check for and run project hook if it exists:
HOOK_PATH="${PROJECT_ROOT:-$PWD}/.claude/hooks/session-pre-check.sh"
if [ -x "$HOOK_PATH" ]; then
"$HOOK_PATH" "${PROJECT_ROOT:-$PWD}"
fi
Hook location: .claude/hooks/session-pre-check.sh (project-level)
Hook contract:
- Receives project root as first argument
- Exit code 0 = proceed to Step 0.5
- Exit code non-zero = abort closure with hook's stderr/stdout as message
- Hook is responsible for its own user communication
Common use cases:
- Stash files that shouldn't be committed (
.pages, .numbers, temp files)
- Run project-specific preparation scripts
- Check project-specific preconditions
Example hook (stash Apple Pages files):
#!/bin/bash
PROJECT_ROOT="${1:-$PWD}"
cd "$PROJECT_ROOT" || exit 1
PAGES_FILES=$(git status --porcelain | grep '\.pages$' | awk '{print $2}')
if [ -n "$PAGES_FILES" ]; then
echo "📦 Stashing Apple Pages files (autosave noise)..."
git stash push -m "session-pre-check: .pages files" -- $PAGES_FILES
echo "✓ Stashed. Will auto-pop after session skill completes."
fi
exit 0
If hook doesn't exist: Skip silently, proceed to Step 0.5
Error handling:
- Hook not executable: Display warning, proceed to Step 0.5
- Hook fails (non-zero): Display hook output, abort closure
- Hook timeout: Not enforced (project's responsibility)
Step 0.5: Handle ALL Uncommitted Changes
Before archiving or creating new resume, check for ANY uncommitted changes in the repository.
Why: User may have manually edited files between sessions. These changes contain important context that should be reviewed and preserved in git history.
Implementation:
Run the uncommitted changes detection script:
"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/check_uncommitted_changes.sh" "${PROJECT_ROOT:-$PWD}"
Script behavior:
- Not a git repo: Exits silently (code 0) → proceed to Step 1
- No uncommitted changes: Exits silently (code 0) → proceed to Step 1
- Uncommitted changes detected: BLOCKS with detailed output (exit code 1)
When changes detected (BLOCKING):
The script displays:
- Contextual header: What changed (resume only, project files only, or both)
- File list:
git status --short output
- Full diffs: All modifications shown with
git diff HEAD
- Untracked file contents: Transparency about new files
- Secret file warning: If .env, credentials, keys detected
- Clear instructions: Steps to commit manually with CORE_PROCESSES.md reference
Required action when blocked:
When uncommitted changes are detected, you MUST commit them before proceeding:
- Review changes: Script displays full diffs
- Check for secrets: Script warns if .env, credentials, keys found
- Commit manually:
git add <files>
git commit -S -s -m "Pre-closure changes: $(date +%Y-%m-%d-%H%M)
CLAUDE_RESUME.md: [what changed]
LOCAL_CONTEXT.md: [what changed]
[other files]: [what changed]"
- User says "close context" again → Step 0 passes (clean state)
- Continue closure → Proceed to Step 1
Why blocking is necessary:
- Separates user changes from session closure work
- Maintains clean git checkpoints for recovery
- Ensures explicit approval for all commits (protocol requirement)
- Prevents silent commits of potentially sensitive changes
Error handling:
- Script not found: Display error, proceed with warning
- Script fails: Display error, suggest manual
git status
- Git command fails: Script handles gracefully
Step 1: Archive Existing Resume
Run archive script before creating new resume:
"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/archive_resume.sh" "${PROJECT_ROOT:-$PWD}"
Script behavior:
- If CLAUDE_RESUME.md doesn't exist: Skip
- If tracked in git: Skip (git history is archive)
- Otherwise: Move to
archives/CLAUDE_RESUME/<timestamp>.md
Output messages:
- "✓ No previous resume to archive"
- "✅ CLAUDE_RESUME.md tracked in git with no uncommitted changes"
- "⚠️ CLAUDE_RESUME.md has uncommitted changes" (recommends commit)
- "📦 Archived to archives/CLAUDE_RESUME/YYYY-MM-DD-HHMM.md"
Step 2: Assess Session State
Analyze the session: What completed? What decisions made and why? Tasks pending? Blockers? Insights? Critical context?
If context is limited, focus on essential state. Optional sections (Key Decisions, Insights & Learnings) can be skipped.
Step 3: Create CLAUDE_RESUME.md
Location (two supported locations):
.claude/CLAUDE_RESUME.md (preferred, aligns with Claude Code patterns)
CLAUDE_RESUME.md (legacy, project root)
Use same location as existing resume if one exists. For new resumes, prefer .claude/ if that directory exists.
Format: See references/RESUME_FORMAT_v1.3.md for complete specification.
BEFORE creating file, verify you will include ALL required sections:
Required sections (verify before writing):
Optional sections (include if applicable and context allows):
After verifying checklist, create file with these sections:
- Header (project name, date, duration, status)
- Last Activity Completed
- Pending Tasks
- Key Decisions Made (optional)
- Insights & Learnings (optional)
- Session Summary
- Sync Status (if external authoritative sources exist)
- Pending Outbound Handoffs (if handoffs sent awaiting response)
- Project Status (required)
- Next Session Focus
- Footer (version, timestamp, instructions)
Step 4: Verify Resume Creation
Validate resume after creation:
"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/validate_resume.sh" "${PROJECT_ROOT:-$PWD}"
Checks: File exists, required sections present, footer format correct.
Output:
- "✅ Resume validation passed" (success)
- "❌ Resume validation failed: [missing sections]" (failure)
If validation fails: Add missing sections, re-run validation.
Step 5: Commit New Resume
See CORE_PROCESSES.md § Git Commit Protocol for commit requirements.
Quick reference: git commit -S -s -m "message" (no Claude attribution)
Run commit script:
"${SKILL_BASE:-$HOME/.claude/skills/session-closure}/scripts/commit_resume.sh" "${PROJECT_ROOT:-$PWD}"
Script behavior:
- Verifies ONLY CLAUDE_RESUME.md has uncommitted changes
- Commits with standardized message and -S -s flags
- Blocks if unexpected files changed (safety check)
Output:
✅ Session resume committed - Success
✓ No uncommitted changes - Already clean
✓ Not a git repository - Skipped
❌ ERROR: Unexpected changes detected - Unexpected files modified
Hook enforcement: User-level hooks (~/.claude/hooks/) validate all commits:
git-commit-compliance.py: -S -s flags, message quality, no attribution
git-workflow-guidance.py: Separate git add from git commit
Step 6: Confirmation
Report completion after validation:
✅ Session closure complete.
📄 CLAUDE_RESUME.md created and validated
[Archive output if applicable]
Summary: [One sentence about session outcome]
💡 Next session: Say "resume" to continue from here.
Additional Documentation
- references/README.md - Installation, usage, and troubleshooting guide
- references/RESUME_FORMAT_v1.3.md - Complete resume format specification (required reading)
- references/CONTRIBUTING.md - Development, testing, and contribution guide
Session-closure skill v0.5.1 - Added pre-check hook, .claude/ location support, version sync (January 2026)
Source: christophera/claude_code_tools — distributed by TomeVault.