Skip to content
Development
Skill

/session-snapshot

Internal skill for commands. Write a recovery-grade session snapshot (file-primary) for /lets:end and for the --session snapshot-only flag of /lets:end and /lets:note. Always writes a .lets/sessions/ file; adds a one-line task pointer only when a task is unambiguously active. Do

From plugin
lets-workflow
1725 skills15 agents26 commands

Claude Code

$ npx -y skills add restarter/lets-workflow --skill session-snapshot --agent claude-code

SKILL.md

session-snapshot.SKILL.md
name: session-snapshot
description: Internal skill for commands. Write a recovery-grade session snapshot (file-primary) for /lets:end and for the --session snapshot-only flag of /lets:end and /lets:note. Always writes a .lets/sessions/ file; adds a one-line task pointer only when a task is unambiguously active. Do not trigger on user conversation - only when those commands need the snapshot.
user-invocable: false

Session Snapshot

Shared snapshot primitive for `/lets:end` (settlement + snapshot) and for the `--session` snapshot-only flag on both `/lets:end` and `/lets:note`. **Single source of truth** - every caller delegates here so the template and file/pointer behavior never drift.

Goal: ONE recovery-grade `## RESUME` snapshot, **file-primary** - it ALWAYS lands in a `.lets/sessions/` file (the single trail `/lets:start` reads), regardless of task state (feature / trunk / --main / no-task). The active task gets only a ONE-LINE pointer to that file, and only when a task is unambiguously active (via detect-task, NEVER a `list-by-status | head -1` guess).

> **Contract - this skill ONLY writes the snapshot (file + optional pointer).** It does NOT end the session, push, merge, commit, or close anything. The caller decides what else to do.

Arguments (from the caller)

Passed via the `Skill` invocation's `args` string as space-separated `key=value` pairs (e.g. `args: "kind=end pointer=off task-id=lets-abc range=session: X..HEAD (3 commits)"`). Put `range=` / `task-id=` LAST when the value contains spaces - each consumes the rest of the string. Any omitted key falls to its default.

  • `kind` = `session` (default) | `end` - selects the `### Record` line ONLY; both resolve to the same `artifact-path` kind (`snapshot`), because a mid-session record and a session-end record are the same artifact written at different moments. There is no `precompact` kind: a snapshot taken before a `/compact` is just a mid-session one, and naming the caller's next intention in a permanent file is what made the old flag dishonest. Step 3 owns the filename, never build it here.
  • `pointer` = `off` (default) | `auto` - whether the skill writes the standalone one-line task pointer. `off` is the SAFE default (a caller that forgets never double-writes a task comment); a caller that wants the skill to write the pointer passes `auto` explicitly (both snapshot-only callers do). `/lets:end` default passes `off` when it folds the pointer into its own progress comment, `auto` otherwise.
  • `range` (optional) - a RANGE_DESC string (e.g. `session: <ref>..HEAD (N commits)`). A caller that passes one WINS - `/lets:end`'s default flow does, because it already read the boundary to gate its own offers. When it is absent, Step 2 resolves it through `session-boundary` rather than omitting the block, for EVERY kind. Every snapshot is read back by the same consumer, `/lets:start`, for the same purpose - where the work began - so none of them has a reason to be written without its range (lets-yprsv).
  • `task-id` (optional) - pre-resolved active task from the caller's own detect-task.

Step 1: Active task

If the caller passed `task-id`, use it. Else run `Skill(skill: "lets:detect-task")`. "Unambiguously active" = detect-task returns exactly one task. No task (or ambiguous) -> file only, no pointer, no prompt.

Step 2: Gather state

git branch --show-current
git log --oneline -5
git status --short          # uncommitted / untracked
git rev-parse --short HEAD
HEAD_SHA=$(git rev-parse HEAD); echo "HEAD_SHA=$HEAD_SHA"

# Session id + transcript path - BOTH from the Bash-injected env var (ONE channel; matches take-task Step 5).
SID=$CLAUDE_CODE_SESSION_ID
TRANSCRIPT_PATH=$(find "$HOME/.claude/projects" -maxdepth 2 -name "${CLAUDE_CODE_SESSION_ID}.jsonl" 2>/dev/null | head -1)
TRANSCRIPT_PATH=${TRANSCRIPT_PATH:-"(not found)"}
# ECHO both - a bash var is invisible to the Write tool; the model needs the printed values for the template.
echo "SID=$SID"
echo "TRANSCRIPT_PATH=$TRANSCRIPT_PATH"
# Peers of this repo + this chat's own binding (names only, never another session's full id).
command -v lets >/dev/null 2>&1 && lets peers who --json 2>/dev/null
sed -n 's/^orc: //p' "$(git rev-parse --show-toplevel)/.lets/sessions/.task-$(git branch --show-current | tr '/' '-')" 2>/dev/null | head -1

Range (when the caller passed none)

If `range` was NOT passed, invoke `Skill(skill: "lets:session-boundary")` and use its echoed `SESSION_RANGE_DESC` as the RANGE_DESC for Step 3's `### Range` block; surface its stderr NOTEs. Do NOT re-derive the boundary here - that ladder lives in `session-boundary` alone (lets-370mx). If the skill is unavailable, omit the `### Range` block rather than writing an unqualified number.

Step 3: Write the snapshot FILE (ALWAYS)

Resolve the path via `Skill(skill: "lets:artifact-path", args: "kind=snapshot ext=md")` for both kinds; pass `task=<id>` when the caller already resolved one. The echoed `ARTIFACT_FILE` is `$SNAP_FILE` and its basename is `$SNAP_BASENAME` - reuse both VERBATIM in Step 4 + the Return, never recompute (a second `date` drifts the pointer off the file actually written). Shape: `.lets/sessions/{date}-{HHMM}-{task-id|branch-slug-6hex}-snapshot[-vN].md` - task-scoped, `-vN` on collision, so parallel worktrees sharing `.lets/` never overwrite each other (lets-05c4s).

Write `$SNAP_FILE` (the echoed path) via the Write tool with the template below, substituting the bash-captured `$SID` / `$TRANSCRIPT_PATH` from Step 2 - and reuse `$SNAP_BASENAME` verbatim in Step 4 + the Return, never recomputing the minute-precise timestamp. Use ONLY that single bash session-id channel (`$CLAUDE_CODE_SESSION_ID`, captured as `$SID`) - do NOT use the command-load-time template channel (the `CLAUDE_SESSION_ID` template variable in `${...}` form), which is fragile inside a multiline Write arg (lets-bdkvd QA #13) and would itself be substituted here if written literally. English; one continu

Read more
@restarter
Ships withlets-workflow

A development workflow plugin for Claude Code Stop babysitting your AI. Start shipping with it.

1725 skills15 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
17
Star history of restarter/lets-workflow on GitHub, a chart by star-history.com

Other skills on lets-workflow.

goal-test

goal-test

Local sandbox for experimenting with Claude Code's /goal command (stop-hook condition + LLM-evaluator driving autonomous work…

loop-bb-pr

loop-bb-pr

Compose a /loop that monitors a Bitbucket PR for activity (new comments, review state changes, merge, decline) via the bb-api…

loop-gh-pr

loop-gh-pr

Compose a /loop that watches all open GitHub PRs for activity (new PRs, new commits, new comments) and auto-prepares a READ-ONLY…

loop-test

loop-test

Local sandbox for experimenting with Claude Code's /loop command (interval + dynamic/self-paced scheduling) applied to LETS…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about session-snapshot.

Which coding agents can use session-snapshot?
session-snapshot installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.