session-spinup

v2026.09.24

Read-only session-start briefing of open tasks, git state, journal todos — reports, never edits code. Use when user says spin up, what was I doing, or pick up where I left off.

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

session-spinup

Read-only orientation at session start — the inverse of session-plugin:session-wrap: where wrap writes loose threads, spinup reads them back. The failure mode this prevents: the user sits down, doesn't remember what was open, and starts fresh on something else while yesterday's PR sits stale.

The deterministic work — project detection, the survey, GitHub-issue dedup against taskwarrior, staleness, journal extraction — is done by scripts/session-survey.sh (shared with session-wrap, session-end, and the spinup nudge hook). This skill runs that collector once, then applies judgment: filter the digest to what matters and suggest next moves.

When to Use This Skill

Use this skill when...Use alternative when...
User says "spin up", "what was I doing", "pick up where I left off"Resuming a TDD cycle on known state → project-plugin:project-continue
Fresh session opens with open threads (hook-nudged)Cross-project queue health → taskwarrior-plugin:task-status
Orienting before picking the next moveUnfamiliar codebase orientation → project-plugin:project-discovery

Configuration

Same file as the other session skills: .claude/session-plugin.local.md (project) → ~/.claude/session-plugin.local.md (user-global) → none. When journal is configured and the session matches journal_scopes, pass the journal flags to the collector so the briefing includes unchecked todos from the most recent dated note. Schema: session-wrap/REFERENCE.md.

The signal filter

The collector gathers everything; you surface only what the user would otherwise miss — 3-6 item target, 10+ means trim.

SURFACE: open PR from a recent branch (especially review/CI-stale) · +ACTIVE task (work was mid-flight) · unchecked journal todo · real uncommitted edits · unpushed commits · a checkout behind upstream (BEHIND ≥ 1 — a caveat on the briefing's basis, not a task) · task whose annotation reads "blocked on X" where X may now be unblocked · GitHub drift issue (the GITHUB_DRIFT section — assigned, open, untracked locally) · blueprint tracker state when a tracker exists (ready/blocked counts, in-flight WOs) · undrained closed WOs (UNDRAINED_COUNT ≥ 1 — the tracker lags reality; a wind-down /session-end reconciles).

DO NOT SURFACE: completed tasks · merged PRs · closed issues · issues already represented by a surfaced task (the collector already dedups these out of GITHUB_DRIFT) · recurring-reminder / dataview machinery · weeks-stale tasks with no recent annotation (that's task-status's job) · +ACTIVE tasks from a different project (the STALE_ACTIVE_ELSEWHERE section — at most one footnote line, never a scope hijack) · the BLUEPRINT section when MANIFEST=false or TRACKER=false.

Context

  • Project config: !find . -maxdepth 2 -path '*/.claude/session-plugin.local.md'

Harnesses that don't execute !`…` context commands show the line above as text; in that case run the find yourself before Step 1.

Execution

Execute this read-only briefing:

Step 1: Read config, then run the collector once

Read .claude/session-plugin.local.md (project, then ~/.claude/ fallback) for the taskwarrior project-naming map and journal settings. Then run the shared collector — it does detection, survey, dedup, and staleness in one pass and emits a structured digest:

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

Add --project <name> when the config naming map maps the cwd to a project other than the repo basename. When the session is in journal scope, add --with-journal --journal-path <dir> (plus --journal-todo-heading / --journal-todo-stop if the config overrides the defaults). The digest sections: PROJECT, GIT, PRS, TASKWARRIOR (each task with its stable UUID + STALE_DAYS, plus TASK_SCOPE / PROJECT_CONFIDENCE / TASKS_ALL_PROJECTS and the RECENT_TASK_* fallback rows), GITHUB_DRIFT, JOURNAL, BLUEPRINT, STALE_ACTIVE_ELSEWHERE.

Step 1b: If GH_READY=false, fetch GitHub state via MCP instead

The PRS and GITHUB_DRIFT sections carry GH_READY=. When it is false (no gh CLI or unauthenticated — the normal state in Claude Code on the web), their zeros mean not queried, not "nothing open". Do not present them as a clean state. Instead:

  1. If GitHub MCP tools are available (mcp__github__list_issues, mcp__github__list_pull_requests — load via ToolSearch if needed), fetch the repo's open issues assigned to the user and open PRs authored by them, then apply the same dedup the collector would have: drop issues whose number appears as a task ghid UDA or as a #N / issues/N token in the TASKWARRIOR section's descriptions or annotations. Treat what survives as the GITHUB_DRIFT set.
  2. If no GitHub path exists at all, the briefing's github line must say github: not queried (gh unavailable) — never omit it silently.

GH_FAIL_REASON= says which of these you are in, so retry only where retrying can work: re-run the collector once for timeout (raising SESSION_SURVEY_GH_TIMEOUT), api-error, or unknown, quoting GH_FAIL_DETAIL= (gh's first stderr line) if it fails again; go straight to MCP for auth (gh auth login fixes the CLI path) and no-cli; and for no-remote there is nothing to query at all, so say that rather than reporting a gap. Full remediation table: session-plugin:session-end.

Step 1c: If PROJECT_CONFIDENCE=low, do not claim a clean queue

The TASKWARRIOR section carries TASK_SCOPE= and PROJECT_CONFIDENCE=. The project slug is detected from the repo directory basename — a guess that is wrong for chezmoi source dirs, worktrees, monorepo subdirs, portfolio checkouts, and repos cloned under another name. Only PROJECT_CONFIDENCE=high licenses "nothing pending under project:<name>". Otherwise:

TASK_SCOPEWhat to say / do
remote-nameThe count is real but came from PROJECT_RESOLVED= — name that slug in the briefing, not the directory basename
ancestor-nameAn ancestor repo's slug was adopted (DETECTION=cwd-repo-basename-ancestor); the count is real but belongs to PROJECT_RESOLVED= — name that slug, not the directory
all-projects-fallbackNever say the queue is clean. Present the RECENT_TASK_* rows as "recently touched (project scope unresolved)" with TASKS_ALL_PROJECTS as the denominator, and offer to re-run with --project <name>
unknown / noneState taskwarrior: not queried — jq or task was unavailable, so the zeros are unqueried

DETECTION= names how the slug was chosen: override (--project), declared (a .claude/session.json .project string), cwd-repo-basename (the guess), cwd-repo-basename-ancestor (an adopted ancestor), or ambiguous.

Also independently of TASK_SCOPE: when PROJECT_PREFIX_SIBLINGS=<slugs> and PROJECT_PREFIX_SIBLING_TASKS=N are present, other slugs share the detected slug's prefix — which taskwarrior's own CLI filter (task project:<slug>) would have swept in, making a wrong slug look verified. Say N under <slugs> alongside the count and offer --project <slug>; never present the scoped count as the whole picture. PROJECT_EXACT_TASKS= is the slug alone, without its . subprojects.

Independently of TASK_SCOPE, when PROJECT_AMBIGUOUS=<slug> and PROJECT_AMBIGUOUS_TASKS=N are present the detected slug owns zero tasks while that ancestor slug owns N. Brief it as 0 here, N under <slug> — never as a clean queue, even at PROJECT_CONFIDENCE=high (a user-asserted --project or a repo declaration deliberately keeps high).

A RECENT_TASK_* row carries no ghid / annotations / +ACTIVE flag — it is a pointer, not a full task. Resolve the slug before acting on one.

Step 2: Apply the signal filter

Cut the digest to the 3-6 things that matter, using the filter above. The collector has already done the mechanical drops (dedup, cross-project separation, staleness numbers); your job is the judgment calls — e.g. is a "blocked on X" annotation now unblocked, is an 11-day-stale PR worth a nudge.

Step 3: Present

Compact briefing, one section per source, reflecting only the cwd project. Say "git state: clean" / "nothing pending under project:<name>" explicitly rather than omitting sections. A STALE_ACTIVE_ELSEWHERE entry gets a single footnote line at the very end, never its own scope. When the repo has a feature tracker, add one blueprint line — blueprint: 14 ready · 2 blocked · in flight: WO-031 · undrained: WO-045 — omitting empty fragments; omit the line entirely when the tracker is absent. Example briefing: REFERENCE.md.

Step 4: Offer next moves

Suggest 2-4 concrete "next moves" and let the user pick — never auto-resume a task or start a workflow. Spinup makes the open threads visible; the user decides.

Auto-surfacing

A SessionStart hook (hooks/session-spinup-nudge.sh) runs the same collector in --summary mode and injects a one-time context note when a fresh session opens with open threads. It offers; it never runs the skill. Pre-silence: touch ~/.cache/claude-session-spinup-nudge/<session_id>.

Agentic Optimizations

ContextCommand
Full digest (detection + survey + dedup + staleness + blueprint tracker state)bash "${CLAUDE_SKILL_DIR}/../../scripts/session-survey.sh" --with-dedup --with-blueprint
With journal todosadd --with-journal --journal-path <dir>
Override detected projectadd --project <name>
Coarse counts only (hook shape)add --summary
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-spinup

Default branch

main

Latest commit

1668324

Tree SHA

b2d4cc3