| name | nightly |
| description | End-of-day cleanup and maintenance routine. Calculates Sleep Score (0-100) based on uncommitted work, branch cleanup, issue updates, CI status, and service shutdown. Automatically captures session state to STATUS.json. Use at end of work day before closing Claude Code. |
Nightly Routine
Overview
Automated end-of-day maintenance that ensures clean project state before leaving for the day.
Core principle: Leave the codebase in a clean, resumable state with zero manual overhead.
Trigger: End of work day, before closing Claude Code
Duration: ~10-15 seconds (vs. ~60 seconds manual)
Sleep Score (0-100)
Comprehensive health check across 6 dimensions:
| Check | Points | Criteria |
|---|---|---|
| Uncommitted work saved | 25 | No uncommitted changes OR committed |
| Branches cleaned | 20 | No stale merged branches |
| Issues updated | 20 | Today's issues have status updates |
| CI passing | 15 | Latest CI run successful |
| Services stopped | 10 | No dev services running |
| Logs archived | 10 | Session logs saved |
Score Interpretation:
- 90-100: Perfect shutdown - ready for tomorrow
- 70-89: Good - minor cleanup needed
- 50-69: Fair - some uncommitted work or failed CI
- 0-49: Poor - significant cleanup required
Workflow Steps
1. Collect Project State
Using capture_state.py utility:
from popkit_shared.utils.capture_state import capture_project_state
state = capture_project_state()
# Returns: {
# 'git': {...},
# 'github': {...},
# 'services': {...}
# }
Git Analysis:
- Current branch
- Uncommitted files (count and list)
- Stashed changes count
- Last commit info
- Merged branches count
GitHub Analysis:
- Open issues (last 5)
- Recent issue updates
- Latest CI run status
Service Analysis:
- Running dev services (node, npm, pnpm, redis, postgres, supabase)
- Session log files to archive
2. Calculate Sleep Score
Using sleep_score.py module:
from pop_nightly.scripts.sleep_score import calculate_sleep_score
score, breakdown = calculate_sleep_score(state)
# score: 0-100
# breakdown: {
# 'uncommitted_work_saved': {'points': 0, 'max': 25, 'reason': '...'},
# 'branches_cleaned': {'points': 20, 'max': 20, 'reason': '...'},
# ...
# }
3. Generate Nightly Report
Using report_generator.py module:
from pop_nightly.scripts.report_generator import generate_nightly_report
report = generate_nightly_report(score, breakdown, state)
# Returns formatted markdown report with:
# - Sleep Score headline
# - Score breakdown table
# - Uncommitted changes (if any)
# - Recommendations before leaving
# - Next session actions
4. Capture Session State
Invoke pop-session-capture skill to update STATUS.json:
# This happens automatically via Skill tool invocation
# Updates STATUS.json with:
# - Nightly routine execution timestamp
# - Sleep score
# - Git status
# - In-progress work
# - Recommendations
5. Present Report to User
Display nightly report with:
- Sleep Score (0-100) with visual indicator
- Score Breakdown - What contributed to the score
- Uncommitted Changes - Files that need attention
- Recommendations - Actions before leaving
- Next Steps - What to do tomorrow morning
Data Collection Commands
Git Commands (Consolidated)
Single command to gather all git data:
{
echo "=== BRANCH ==="
git rev-parse --abbrev-ref HEAD
echo "=== COMMIT ==="
git log -1 --format="%h - %s"
echo "=== STATUS ==="
git status --porcelain
echo "=== STASHES ==="
git stash list | wc -l
echo "=== MERGED ==="
git branch --merged main | grep -v "^\*" | grep -v "main" | wc -l
} | python -c "
import sys
sections = sys.stdin.read().split('===')
data = {}
for section in sections:
if 'BRANCH' in section:
data['branch'] = section.split('===')[1].strip()
# ... parse other sections
print(json.dumps(data))
"
GitHub Commands (Consolidated)
{
gh issue list --state open --limit 5 --json number,title,updatedAt
echo "---SEPARATOR---"
gh run list --limit 1 --json conclusion,status,createdAt
} > /tmp/gh_data.json
Service Check (Consolidated)
{
ps aux | grep -E "(node|npm|pnpm|redis|postgres|supabase)" | grep -v grep
echo "---SEPARATOR---"
ls ~/.claude/logs/*.log 2>/dev/null | wc -l
} > /tmp/service_data.txt
Integration with Existing Utilities
capture_state.py
Located: packages/shared-py/popkit_shared/utils/capture_state.py
def capture_project_state() -> dict:
"""Capture complete project state for nightly routine."""
return {
'git': capture_git_state(),
'github': capture_github_state(),
'services': capture_service_state(),
'timestamp': datetime.now().isoformat()
}
routine_measurement.py
Located: packages/shared-py/popkit_shared/utils/routine_measurement.py
When invoked with --measure flag:
- Tracks tool call count
- Measures duration
- Calculates token usage
- Saves to
.claude/popkit/measurements/nightly-<timestamp>.json
routine_cache.py
Located: packages/shared-py/popkit_shared/utils/routine_cache.py
Caching strategy:
- Never cache: Git status (changes frequently)
- Cache 15 min: CI status
- Cache 1 hour: GitHub issue list
Output Format
# 🌙 Nightly Routine Report
**Date**: 2025-12-28
**Sleep Score**: 60/100 ⚠️
## Score Breakdown
| Check | Points | Status |
|-------|--------|--------|
| Uncommitted work saved | 0/25 | ❌ 3 uncommitted files |
| Branches cleaned | 20/20 | ✅ No stale branches |
| Issues updated | 20/20 | ✅ All issues current |
| CI passing | 0/15 | ❌ Latest run skipped |
| Services stopped | 10/10 | ✅ All services stopped |
| Logs archived | 10/10 | ✅ No logs to archive |
## Uncommitted Changes (3 files)
- `apps/popkit/packages/websitebuild-popkit-test-beta.txt` (deleted)
- `pnpm-lock.yaml` (modified)
- `.npmrc` (untracked)
## 📋 Recommendations
**Before Leaving:**
- Commit or stash uncommitted changes
- Review 8 stashes: `git stash list`
- Check why CI was skipped
**Next Morning:**
- Run `/popkit:routine morning` to check overnight changes
- Review and test pending PRs
- Clear stash backlog
---
STATUS.json updated ✅
Session state captured for tomorrow's resume.
Error Handling
Git Not Available
try:
git_state = capture_git_state()
except GitNotFoundError:
print("[WARN] Git not available - skipping git checks")
# Continue with partial score
GitHub CLI Not Available
try:
github_state = capture_github_state()
except GhNotFoundError:
print("[WARN] GitHub CLI not available - skipping GitHub checks")
# Continue with partial score
Service Check Failures
# Service checks are best-effort
# If they fail, assume services are stopped (safe default)
Optimization Features
Tool Call Reduction
- Baseline: 11 tool calls (manual)
- Optimized: 4 tool calls (automated)
- Reduction: 64%
Execution Time
- Baseline: ~60 seconds (manual, with thinking)
- Optimized: ~10-15 seconds (automated)
- Improvement: 75-83%
Caching
With --optimized flag:
- Uses
routine_cache.pyfor GitHub data - Reduces redundant API calls
- 40-96% token reduction (per routine.md)
Usage Examples
Basic Usage
/popkit:routine nightly
# → Runs default nightly routine
# → Calculates Sleep Score
# → Updates STATUS.json
# → Shows report
With Measurement
/popkit:routine nightly --measure
# → Runs nightly routine
# → Tracks performance metrics
# → Saves to .claude/popkit/measurements/
Quick Summary
/popkit:routine nightly quick
# → Shows one-line summary
# → Sleep Score: 60/100 - 3 uncommitted files, CI skipped
With Optimization
/popkit:routine nightly --optimized
# → Uses caching for GitHub data
# → Reduces token usage by 40-96%
Files Modified
STATUS.json - Session state updated with:
- Sleep score
- Git context
- Nightly routine timestamp
- Recommendations
.claude/popkit/measurements/ (if --measure used)
- Performance metrics
- Tool call breakdown
- Duration and token usage
Related Skills
- pop-session-capture: Updates STATUS.json (invoked automatically)
- pop-morning: Morning counterpart with Ready to Code score
- pop-routine-optimized: Optimized execution with caching
Related Commands
- /popkit:routine nightly: Main entry point
- /popkit:routine morning: Morning routine
- /popkit:next: Context-aware next action recommendations
Success Criteria
✅ Sleep Score accurately reflects project state ✅ STATUS.json always updated correctly ✅ Completes in <20 seconds ✅ Provides actionable recommendations ✅ Reduces manual workflow by 64%
Skill Type: Automated Routine Category: Workflow Automation Tier: Core (Always Available) Version: 1.0.0