[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71GP71X67RNTNH0VPM47FDM":3,"skill-same:01M71GP71X67RNTNH0VPM47FDM":77},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":60,"ownerDescription":61,"updatedAt":62,"install":63,"resources":76},"01M71GP71X67RNTNH0VPM47FDM","context-save",null,"Save working context (git state, decisions, remaining work) so a later session can pick up where you left off.","timurgaleev\u002Fvibestack","timurgaleev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F32696429?v=4","01M71GMS53Z9B4JQTCQEFXAE9E","Timur Galeev","01M71GMS5S1Q7BEYB3Z7GY3E85",8,"MIT","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Fskills\u002Fcontext-save\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"save","context save","context","state","can","decisions","save progress","git state","session","my","git","write","read","later","progress","work","Bash","you","up","pick","2026-11-10 10:12:30",false,"---\nname: context-save\ndescription: |\n  Save working context (git state, decisions, remaining work) so a later session can pick up where you left off.\nallowed-tools:\n  - Bash\n  - Read\n  - Write\n  - Glob\n  - Grep\n  - AskUserQuestion\ntriggers:\n  - save progress\n  - save state\n  - save my work\n  - context save\n---\n\nIf this session was compacted, the copy of this skill in context may be cut off.\nRead `${CLAUDE_SKILL_DIR}\u002FSKILL.md` from disk and resume at the step you are on.\n\n## When to invoke\n\nUse when asked to \"save progress\", \"save state\", \"context save\", or \"save my work\". Pair with \u002Fcontext-restore to resume later. Formerly \u002Fcheckpoint — renamed because Claude Code treats \u002Fcheckpoint as a native rewind alias in current environments, which was shadowing this skill.\n\n## Preamble\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" 2>\u002Fdev\u002Fnull || SLUG=\"unknown\"\n_LEARN_FILE=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F${SLUG:-unknown}\u002Flearnings.jsonl\"\nif [ -f \"$_LEARN_FILE\" ]; then\n  _LEARN_COUNT=$(wc -l \u003C \"$_LEARN_FILE\" 2>\u002Fdev\u002Fnull | tr -d ' ')\n  echo \"LEARNINGS: $_LEARN_COUNT entries loaded\"\n  if [ \"$_LEARN_COUNT\" -gt 5 ] 2>\u002Fdev\u002Fnull; then\n    \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-learnings-search\" --limit 5 2>\u002Fdev\u002Fnull || true\n  fi\nelse\n  echo \"LEARNINGS: none yet\"\nfi\n```\n\n{{include lib\u002Fsnippets\u002Fsession-host.md}}\n\n{{include lib\u002Fsnippets\u002Fdecision-brief.md}}\n\n{{include lib\u002Fsnippets\u002Fworking-protocols.md}}\n\n{{include lib\u002Fsnippets\u002Fstate-protocols.md}}\n\n# \u002Fcontext-save — Save Working Context\n\nYou are a **Staff Engineer who keeps meticulous session notes**. Your job is to\ncapture the full working context — what's being done, what decisions were made,\nwhat's left — so that any future session (even on a different branch or workspace)\ncan resume without losing a beat via `\u002Fcontext-restore`.\n\n**HARD GATE:** Do NOT implement code changes. This skill captures state only.\n\n---\n\n## Detect command\n\nParse the user's input to determine the mode:\n\n- `\u002Fcontext-save`, `\u002Fcontext-save \u003Ctitle>` or\n  `\u002Fcontext-save \u003Ctitle> -- \u003Cnext focus>` → **Save**\n- `\u002Fcontext-save list` → **List**\n\nIf the user provides a title after the command (e.g., `\u002Fcontext-save auth refactor`),\nuse it as the title. Otherwise, infer a title from the current work. Text after\n` -- ` is what the next session should start on; save it as the Next Focus.\n\nIf the user types `\u002Fcontext-save resume` or `\u002Fcontext-save restore`, tell them:\n\"Use `\u002Fcontext-restore` instead — save and restore are separate skills now.\"\n\n---\n\n## Save flow\n\n### Step 1: Gather state\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" && mkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\"\n```\n\nCollect the current working state:\n\n```bash\necho \"=== BRANCH ===\"\ngit rev-parse --abbrev-ref HEAD 2>\u002Fdev\u002Fnull\necho \"=== STATUS ===\"\ngit status --short 2>\u002Fdev\u002Fnull\necho \"=== DIFF STAT ===\"\ngit diff --stat 2>\u002Fdev\u002Fnull\necho \"=== STAGED DIFF STAT ===\"\ngit diff --cached --stat 2>\u002Fdev\u002Fnull\necho \"=== RECENT LOG ===\"\ngit log --oneline -10 2>\u002Fdev\u002Fnull\n```\n\n### Step 2: Summarize context\n\nUsing the gathered state plus your conversation history, produce a summary covering:\n\n1. **What's being worked on** — the high-level goal or feature\n2. **Decisions made** — architectural choices, trade-offs, approaches chosen and why\n3. **Remaining work** — concrete next steps, in priority order, each marked with\n   how this session knows it (see the provenance table below)\n4. **Notes** — anything a future session needs to know (gotchas, blocked items,\n   open questions, things that were tried and didn't work)\n\n**Remaining Work provenance.** A resumed session cannot tell a command you ran\nfrom one you guessed unless the item says so. Every item starts with the status\n`Open.` — never with a completion token such as `[done]` or `[executed]` — and\nends with the marker from the first row that applies:\n\n| # | The item is... | Marker | Use when this session... |\n|---|----------------|--------|--------------------------|\n| 1 | a writing step (migration, sync, insert, import, deploy, a dialog that writes), with or without a concrete path | `(target state checked)` | inspected the target's schema or state (for example its unique key) |\n| | | `(code read)` | read the writer but not the target |\n| | | `(path assumed)` | inferred the write without reading either |\n| 2 | otherwise, names a concrete path: a runnable command, CLI flag or switch, config key or value, or file or directory path | `(path run)` | executed it and observed the outcome; state the outcome in the item, before the marker (`exit 0`, `failed: \u003Creason>`) |\n| | | `(path read)` | read the code or file but did not execute it |\n| | | `(path assumed)` | inferred it without running or reading it, however confident |\n| 3 | anything else | none | (`Open.` alone) |\n\nWriting steps get their own markers because whether a write is safe to repeat\ndepends on the target's state, not on the code that performs it. Examples:\n`Open. Run the suite with CONFIG=staging, exit 0. (path run)` and\n`Open. Switch B reads config key Y. (path assumed)`.\n\nMarkers are English literals, whatever language the session used: restore\nmatches them by exact text. Before writing, check every item's final\nparenthesised token, and rewrite any that is not one of the five as\n`(path assumed)`; the Marker scan below catches what slips through.\n\n**Decisions Made claims are backed.** A decision that states what a file\ncontains (\"the config sets X\", \"only two callers\") must rest on a grep, wc or\nRead of that file in this session; otherwise end it with `(path assumed)`.\n\nIf the user provided a title, use it. Otherwise, infer a concise title (3-6 words)\nfrom the work being done.\n\n### Step 3: Compute session duration\n\nTry to determine how long this session has been active:\n\n```bash\nif [ -n \"$_TEL_START\" ]; then\n  START_EPOCH=\"$_TEL_START\"\nelif [ -n \"$PPID\" ]; then\n  _LSTART=$(ps -o lstart= -p \"$PPID\" 2>\u002Fdev\u002Fnull)\n  # BSD date (macOS) parses with -jf, GNU date (Linux) with -d. Never parse an\n  # empty start: GNU `date -d \"\"` means today at midnight.\n  [ -n \"$_LSTART\" ] && START_EPOCH=$(date -jf \"%c\" \"$_LSTART\" \"+%s\" 2>\u002Fdev\u002Fnull || date -d \"$_LSTART\" \"+%s\" 2>\u002Fdev\u002Fnull || echo \"\")\nfi\nif [ -n \"$START_EPOCH\" ]; then\n  NOW=$(date +%s)\n  DURATION=$((NOW - START_EPOCH))\n  echo \"SESSION_DURATION_S=$DURATION\"\nelse\n  echo \"SESSION_DURATION_S=unknown\"\nfi\n```\n\nIf the duration cannot be determined, omit the `session_duration_s` field from the\nsaved file.\n\n### Step 4: Write saved-context file\n\nCompute the path in bash (NOT in the LLM prompt) so user-supplied titles can't\ninject shell metacharacters into any subsequent command. The sanitizer is an\nallowlist: only `a-z 0-9 - .` survive.\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" && mkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\"\nCHECKPOINT_DIR=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\u002Fcheckpoints\"\nmkdir -p \"$CHECKPOINT_DIR\"\nTIMESTAMP=$(date +%Y%m%d-%H%M%S)\n# Bash-side title sanitize. Pass the raw title in TITLE_RAW when running this block.\n# Example: TITLE_RAW=\"wintermute progress\" bash -c '...'\nRAW=\"${TITLE_RAW:-untitled}\"\n# Lowercase, collapse whitespace to hyphens, strip to allowlist, cap length.\nTITLE_SLUG=$(printf '%s' \"$RAW\" | tr '[:upper:]' '[:lower:]' | tr -s ' \\t' '-' | tr -cd 'a-z0-9.-' | cut -c1-60)\nTITLE_SLUG=\"${TITLE_SLUG:-untitled}\"\n# Collision-safe filename: if ${TIMESTAMP}-${SLUG}.md already exists (same-second\n# double save with same title), append a short random suffix. Filenames are\n# append-only — never overwrite.\nFILE=\"${CHECKPOINT_DIR}\u002F${TIMESTAMP}-${TITLE_SLUG}.md\"\nif [ -e \"$FILE\" ]; then\n  SUFFIX=$(LC_ALL=C tr -dc 'a-z0-9' \u003C \u002Fdev\u002Furandom 2>\u002Fdev\u002Fnull | head -c 4 || printf '%04x' \"$$\")\n  FILE=\"${CHECKPOINT_DIR}\u002F${TIMESTAMP}-${TITLE_SLUG}-${SUFFIX}.md\"\nfi\necho \"CHECKPOINT_DIR=$CHECKPOINT_DIR\"\necho \"TIMESTAMP=$TIMESTAMP\"\necho \"FILE=$FILE\"\n```\n\nThe on-disk directory name is `checkpoints\u002F` (not `contexts\u002F`) — this is a legacy\npath kept so existing saved files remain loadable. Users never see it.\n\nWrite the file to the `$FILE` path printed above (use the exact string — do not\nreconstruct it in the LLM layer).\n\nThe file format:\n\n```markdown\n---\nstatus: in-progress\nbranch: {current branch name}\ntimestamp: {ISO-8601 timestamp, e.g. 2026-04-18T14:30:00-07:00}\nsession_duration_s: {computed duration, omit if unknown}\nfiles_modified:\n  - path\u002Fto\u002Ffile1\n  - path\u002Fto\u002Ffile2\n---\n\n## Working on: {title}\n\n### Summary\n\n{1-3 sentences describing the high-level goal and current progress}\n\n### Decisions Made\n\n{Bulleted list of architectural choices, trade-offs, and reasoning}\n\n### Next Focus\n\n{The text after ` -- `, verbatim; omit the section when none was given}\n\n### Remaining Work\n\n{Numbered list of concrete next steps, in priority order. Each item starts with `Open.` and ends with its provenance marker from Step 2, or no marker under row 3.}\n\n### Notes\n\n{Gotchas, blocked items, open questions, things tried that didn't work}\n\n### Suggested skills\n\n{Slash commands that fit the next step (`\u002Finvestigate`, `\u002Freview`, `\u002Fship`), one line each with why; omit when none fits}\n\n### References\n\n{Paths or URLs of plans, specs, PRs and logs this work relies on: link them, never restate their content}\n```\n\nThe `files_modified` list comes from `git status --short` (both staged and unstaged\nmodified files). Use relative paths from the repo root.\n\nThen stamp the project identity into the frontmatter. Do not write these\nfields yourself: the bin writes `remote:` (the origin with any credentials\nremoved, or `none`) and `project_root:` (the repository root), which\n`\u002Fcontext-restore` uses to refuse another project's checkpoint, plus `head:`\n(the commit checked out) and, in a linked worktree, `worktree:`, which it uses\nto tell how far the repository moved since the save. Substitute the\nexact `FILE=` path printed in Step 4:\n\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" --stamp-checkpoint \"{FILE}\" \\\n  && grep -E '^(remote|project_root|head|worktree):' \"{FILE}\"\n```\n\nIf the stamp fails, say so in the confirmation below — the save still stands,\nbut restore will treat it as an unstamped checkpoint.\n\n#### Marker scan\n\nEvery Remaining Work item that ends in a parenthesised token not among the five\nmarkers is printed (substitute the `FILE=` path):\n\n```bash\nawk '\u002F^### \u002F { inrw = ($(0) == \"### Remaining Work\"); next }\n  inrw && \u002F^([0-9]+\\.|[-*]) \u002F && match($(0), \u002F\\([^()]*\\)[[:space:]]*$\u002F) {\n    t = substr($(0), RSTART, RLENGTH); sub(\u002F[[:space:]]+$\u002F, \"\", t)\n    if (t !~ \u002F^\\((target state checked|code read|path run|path read|path assumed)\\)$\u002F) print \"UNKNOWN_MARKER: \" $(0)\n  }' \"{FILE}\"\n```\n\nFor each `UNKNOWN_MARKER:` line, rewrite that item's marker as `(path assumed)`\n(Write the whole file again) and re-run the scan until it prints nothing.\n\nThen scan the file for credentials — a session's notes quote commands, configs\nand logs:\n\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-redact\" scan --file \"{FILE}\"; echo \"REDACT_EXIT: $?\"\n```\n\n`REDACT_EXIT: 1` lists masked findings with line numbers: replace each value\nwith `[REDACTED]`, write the file again and re-scan until exit 0. `2` means the\nscan could not run — say so in the confirmation.\n\nAfter writing, confirm to the user:\n\n```\nCONTEXT SAVED\n════════════════════════════════════════\nTitle:    {title}\nBranch:   {branch}\nFile:     {path to saved file}\nModified: {N} files\nDuration: {duration or \"unknown\"}\n════════════════════════════════════════\n\nRestore later with \u002Fcontext-restore.\n```\n\n---\n\n## List flow\n\n### Step 1: Gather saved contexts\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" && mkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\"\nCHECKPOINT_DIR=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\u002Fcheckpoints\"\nif [ -d \"$CHECKPOINT_DIR\" ]; then\n  echo \"CHECKPOINT_DIR=$CHECKPOINT_DIR\"\n  # Use find + sort instead of ls -1t: filename YYYYMMDD-HHMMSS prefix is the\n  # canonical order (stable across copies\u002Frsync; mtime is not), and empty-result\n  # behavior is clean (no files → no output, no \"lists cwd\" fallback).\n  find \"$CHECKPOINT_DIR\" -maxdepth 1 -name \"*.md\" -type f 2>\u002Fdev\u002Fnull | sort -r\nelse\n  echo \"NO_CHECKPOINTS\"\nfi\n```\n\n### Step 2: Display table\n\n**Default behavior:** Show saved contexts for the **current branch** only.\n\nIf the user passes `--all` (e.g., `\u002Fcontext-save list --all`), show contexts\nfrom **all branches**.\n\nRead the frontmatter of each file to extract `status`, `branch`, and\n`timestamp`. Parse the title from the filename (the part after the timestamp).\n\nPresent as a table:\n\n```\nSAVED CONTEXTS ({branch} branch)\n════════════════════════════════════════\n#  Date        Title                    Status\n─  ──────────  ───────────────────────  ───────────\n1  2026-04-18  auth-refactor            in-progress\n2  2026-04-17  api-pagination           completed\n3  2026-04-15  db-migration-setup       in-progress\n════════════════════════════════════════\n```\n\nIf `--all` is used, add a Branch column:\n\n```\nSAVED CONTEXTS (all branches)\n════════════════════════════════════════\n#  Date        Title                    Branch              Status\n─  ──────────  ───────────────────────  ──────────────────  ───────────\n1  2026-04-18  auth-refactor            feat\u002Fauth           in-progress\n2  2026-04-17  api-pagination           main                completed\n3  2026-04-15  db-migration-setup       feat\u002Fdb-migration   in-progress\n════════════════════════════════════════\n```\n\nIf there are no saved contexts, tell the user: \"No saved contexts yet. Run\n`\u002Fcontext-save` to save your current working state.\"\n\n---\n\n## Important Rules\n\n- **Never modify code.** This skill only reads state and writes the context file.\n- **Always include the branch name** in frontmatter — critical for cross-branch\n  `\u002Fcontext-restore`.\n- **Always stamp the project identity** with `vibe-slug --stamp-checkpoint`, run\n  from inside the project — never hand-write `remote:` or `project_root:`.\n- **Saved files are append-only.** Never overwrite or delete existing files. Each\n  save creates a new file.\n- **Infer, don't interrogate.** Use git state and conversation context to fill in\n  the file. Only use AskUserQuestion if the title genuinely cannot be inferred.\n- **This is a vibestack skill, not a Claude Code built-in.** When the user types\n  `\u002Fcontext-save`, invoke this skill via the Skill tool. The old `\u002Fcheckpoint`\n  name collided with Claude Code's native `\u002Frewind` alias — the rename fixed that.\n- **Automatic snapshots are not a save.** In Claude Code a PreCompact hook writes\n  a git-state snapshot to `~\u002F.vibestack\u002Fprojects\u002F\u003Cslug>\u002Fcompact-snapshots\u002F`\n  before every compaction. It holds git state and the transcript path only,\n  never decisions, so `\u002Fcontext-save` stays the way to record decisions. Other\n  runtimes have no compaction hook in this pack.\n\n---\n\nRun this step before finishing. A saved context file is read once, by whoever\nrestores it; a learning outlives it and surfaces in every later session's\npreamble. If the session genuinely surfaced none, say \"no durable learnings this\nsession\" rather than inventing one.\n\n{{include lib\u002Fsnippets\u002Fcapture-learnings.md}}\n","If this session was compacted, the copy of this skill in context may be cut off.\nRead `${CLAUDE_SKILL_DIR}\u002FSKILL.md` from disk and resume at the step you are on.\n\n## When to invoke\n\nUse when asked to \"save progress\", \"save state\", \"context save\", or \"save my work\". Pair with \u002Fcontext-restore to resume later. Formerly \u002Fcheckpoint — renamed because Claude Code treats \u002Fcheckpoint as a native rewind alias in current environments, which was shadowing this skill.\n\n## Preamble\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" 2>\u002Fdev\u002Fnull || SLUG=\"unknown\"\n_LEARN_FILE=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F${SLUG:-unknown}\u002Flearnings.jsonl\"\nif [ -f \"$_LEARN_FILE\" ]; then\n  _LEARN_COUNT=$(wc -l \u003C \"$_LEARN_FILE\" 2>\u002Fdev\u002Fnull | tr -d ' ')\n  echo \"LEARNINGS: $_LEARN_COUNT entries loaded\"\n  if [ \"$_LEARN_COUNT\" -gt 5 ] 2>\u002Fdev\u002Fnull; then\n    \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-learnings-search\" --limit 5 2>\u002Fdev\u002Fnull || true\n  fi\nelse\n  echo \"LEARNINGS: none yet\"\nfi\n```\n\n{{include lib\u002Fsnippets\u002Fsession-host.md}}\n\n{{include lib\u002Fsnippets\u002Fdecision-brief.md}}\n\n{{include lib\u002Fsnippets\u002Fworking-protocols.md}}\n\n{{include lib\u002Fsnippets\u002Fstate-protocols.md}}\n\n# \u002Fcontext-save — Save Working Context\n\nYou are a **Staff Engineer who keeps meticulous session notes**. Your job is to\ncapture the full working context — what's being done, what decisions were made,\nwhat's left — so that any future session (even on a different branch or workspace)\ncan resume without losing a beat via `\u002Fcontext-restore`.\n\n**HARD GATE:** Do NOT implement code changes. This skill captures state only.\n\n---\n\n## Detect command\n\nParse the user's input to determine the mode:\n\n- `\u002Fcontext-save`, `\u002Fcontext-save \u003Ctitle>` or\n  `\u002Fcontext-save \u003Ctitle> -- \u003Cnext focus>` → **Save**\n- `\u002Fcontext-save list` → **List**\n\nIf the user provides a title after the command (e.g., `\u002Fcontext-save auth refactor`),\nuse it as the title. Otherwise, infer a title from the current work. Text after\n` -- ` is what the next session should start on; save it as the Next Focus.\n\nIf the user types `\u002Fcontext-save resume` or `\u002Fcontext-save restore`, tell them:\n\"Use `\u002Fcontext-restore` instead — save and restore are separate skills now.\"\n\n---\n\n## Save flow\n\n### Step 1: Gather state\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" && mkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\"\n```\n\nCollect the current working state:\n\n```bash\necho \"=== BRANCH ===\"\ngit rev-parse --abbrev-ref HEAD 2>\u002Fdev\u002Fnull\necho \"=== STATUS ===\"\ngit status --short 2>\u002Fdev\u002Fnull\necho \"=== DIFF STAT ===\"\ngit diff --stat 2>\u002Fdev\u002Fnull\necho \"=== STAGED DIFF STAT ===\"\ngit diff --cached --stat 2>\u002Fdev\u002Fnull\necho \"=== RECENT LOG ===\"\ngit log --oneline -10 2>\u002Fdev\u002Fnull\n```\n\n### Step 2: Summarize context\n\nUsing the gathered state plus your conversation history, produce a summary covering:\n\n1. **What's being worked on** — the high-level goal or feature\n2. **Decisions made** — architectural choices, trade-offs, approaches chosen and why\n3. **Remaining work** — concrete next steps, in priority order, each marked with\n   how this session knows it (see the provenance table below)\n4. **Notes** — anything a future session needs to know (gotchas, blocked items,\n   open questions, things that were tried and didn't work)\n\n**Remaining Work provenance.** A resumed session cannot tell a command you ran\nfrom one you guessed unless the item says so. Every item starts with the status\n`Open.` — never with a completion token such as `[done]` or `[executed]` — and\nends with the marker from the first row that applies:\n\n| # | The item is... | Marker | Use when this session... |\n|---|----------------|--------|--------------------------|\n| 1 | a writing step (migration, sync, insert, import, deploy, a dialog that writes), with or without a concrete path | `(target state checked)` | inspected the target's schema or state (for example its unique key) |\n| | | `(code read)` | read the writer but not the target |\n| | | `(path assumed)` | inferred the write without reading either |\n| 2 | otherwise, names a concrete path: a runnable command, CLI flag or switch, config key or value, or file or directory path | `(path run)` | executed it and observed the outcome; state the outcome in the item, before the marker (`exit 0`, `failed: \u003Creason>`) |\n| | | `(path read)` | read the code or file but did not execute it |\n| | | `(path assumed)` | inferred it without running or reading it, however confident |\n| 3 | anything else | none | (`Open.` alone) |\n\nWriting steps get their own markers because whether a write is safe to repeat\ndepends on the target's state, not on the code that performs it. Examples:\n`Open. Run the suite with CONFIG=staging, exit 0. (path run)` and\n`Open. Switch B reads config key Y. (path assumed)`.\n\nMarkers are English literals, whatever language the session used: restore\nmatches them by exact text. Before writing, check every item's final\nparenthesised token, and rewrite any that is not one of the five as\n`(path assumed)`; the Marker scan below catches what slips through.\n\n**Decisions Made claims are backed.** A decision that states what a file\ncontains (\"the config sets X\", \"only two callers\") must rest on a grep, wc or\nRead of that file in this session; otherwise end it with `(path assumed)`.\n\nIf the user provided a title, use it. Otherwise, infer a concise title (3-6 words)\nfrom the work being done.\n\n### Step 3: Compute session duration\n\nTry to determine how long this session has been active:\n\n```bash\nif [ -n \"$_TEL_START\" ]; then\n  START_EPOCH=\"$_TEL_START\"\nelif [ -n \"$PPID\" ]; then\n  _LSTART=$(ps -o lstart= -p \"$PPID\" 2>\u002Fdev\u002Fnull)\n  # BSD date (macOS) parses with -jf, GNU date (Linux) with -d. Never parse an\n  # empty start: GNU `date -d \"\"` means today at midnight.\n  [ -n \"$_LSTART\" ] && START_EPOCH=$(date -jf \"%c\" \"$_LSTART\" \"+%s\" 2>\u002Fdev\u002Fnull || date -d \"$_LSTART\" \"+%s\" 2>\u002Fdev\u002Fnull || echo \"\")\nfi\nif [ -n \"$START_EPOCH\" ]; then\n  NOW=$(date +%s)\n  DURATION=$((NOW - START_EPOCH))\n  echo \"SESSION_DURATION_S=$DURATION\"\nelse\n  echo \"SESSION_DURATION_S=unknown\"\nfi\n```\n\nIf the duration cannot be determined, omit the `session_duration_s` field from the\nsaved file.\n\n### Step 4: Write saved-context file\n\nCompute the path in bash (NOT in the LLM prompt) so user-supplied titles can't\ninject shell metacharacters into any subsequent command. The sanitizer is an\nallowlist: only `a-z 0-9 - .` survive.\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" && mkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\"\nCHECKPOINT_DIR=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\u002Fcheckpoints\"\nmkdir -p \"$CHECKPOINT_DIR\"\nTIMESTAMP=$(date +%Y%m%d-%H%M%S)\n# Bash-side title sanitize. Pass the raw title in TITLE_RAW when running this block.\n# Example: TITLE_RAW=\"wintermute progress\" bash -c '...'\nRAW=\"${TITLE_RAW:-untitled}\"\n# Lowercase, collapse whitespace to hyphens, strip to allowlist, cap length.\nTITLE_SLUG=$(printf '%s' \"$RAW\" | tr '[:upper:]' '[:lower:]' | tr -s ' \\t' '-' | tr -cd 'a-z0-9.-' | cut -c1-60)\nTITLE_SLUG=\"${TITLE_SLUG:-untitled}\"\n# Collision-safe filename: if ${TIMESTAMP}-${SLUG}.md already exists (same-second\n# double save with same title), append a short random suffix. Filenames are\n# append-only — never overwrite.\nFILE=\"${CHECKPOINT_DIR}\u002F${TIMESTAMP}-${TITLE_SLUG}.md\"\nif [ -e \"$FILE\" ]; then\n  SUFFIX=$(LC_ALL=C tr -dc 'a-z0-9' \u003C \u002Fdev\u002Furandom 2>\u002Fdev\u002Fnull | head -c 4 || printf '%04x' \"$$\")\n  FILE=\"${CHECKPOINT_DIR}\u002F${TIMESTAMP}-${TITLE_SLUG}-${SUFFIX}.md\"\nfi\necho \"CHECKPOINT_DIR=$CHECKPOINT_DIR\"\necho \"TIMESTAMP=$TIMESTAMP\"\necho \"FILE=$FILE\"\n```\n\nThe on-disk directory name is `checkpoints\u002F` (not `contexts\u002F`) — this is a legacy\npath kept so existing saved files remain loadable. Users never see it.\n\nWrite the file to the `$FILE` path printed above (use the exact string — do not\nreconstruct it in the LLM layer).\n\nThe file format:\n\n```markdown\n---\nstatus: in-progress\nbranch: {current branch name}\ntimestamp: {ISO-8601 timestamp, e.g. 2026-04-18T14:30:00-07:00}\nsession_duration_s: {computed duration, omit if unknown}\nfiles_modified:\n  - path\u002Fto\u002Ffile1\n  - path\u002Fto\u002Ffile2\n---\n\n## Working on: {title}\n\n### Summary\n\n{1-3 sentences describing the high-level goal and current progress}\n\n### Decisions Made\n\n{Bulleted list of architectural choices, trade-offs, and reasoning}\n\n### Next Focus\n\n{The text after ` -- `, verbatim; omit the section when none was given}\n\n### Remaining Work\n\n{Numbered list of concrete next steps, in priority order. Each item starts with `Open.` and ends with its provenance marker from Step 2, or no marker under row 3.}\n\n### Notes\n\n{Gotchas, blocked items, open questions, things tried that didn't work}\n\n### Suggested skills\n\n{Slash commands that fit the next step (`\u002Finvestigate`, `\u002Freview`, `\u002Fship`), one line each with why; omit when none fits}\n\n### References\n\n{Paths or URLs of plans, specs, PRs and logs this work relies on: link them, never restate their content}\n```\n\nThe `files_modified` list comes from `git status --short` (both staged and unstaged\nmodified files). Use relative paths from the repo root.\n\nThen stamp the project identity into the frontmatter. Do not write these\nfields yourself: the bin writes `remote:` (the origin with any credentials\nremoved, or `none`) and `project_root:` (the repository root), which\n`\u002Fcontext-restore` uses to refuse another project's checkpoint, plus `head:`\n(the commit checked out) and, in a linked worktree, `worktree:`, which it uses\nto tell how far the repository moved since the save. Substitute the\nexact `FILE=` path printed in Step 4:\n\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" --stamp-checkpoint \"{FILE}\" \\\n  && grep -E '^(remote|project_root|head|worktree):' \"{FILE}\"\n```\n\nIf the stamp fails, say so in the confirmation below — the save still stands,\nbut restore will treat it as an unstamped checkpoint.\n\n#### Marker scan\n\nEvery Remaining Work item that ends in a parenthesised token not among the five\nmarkers is printed (substitute the `FILE=` path):\n\n```bash\nawk '\u002F^### \u002F { inrw = ($(0) == \"### Remaining Work\"); next }\n  inrw && \u002F^([0-9]+\\.|[-*]) \u002F && match($(0), \u002F\\([^()]*\\)[[:space:]]*$\u002F) {\n    t = substr($(0), RSTART, RLENGTH); sub(\u002F[[:space:]]+$\u002F, \"\", t)\n    if (t !~ \u002F^\\((target state checked|code read|path run|path read|path assumed)\\)$\u002F) print \"UNKNOWN_MARKER: \" $(0)\n  }' \"{FILE}\"\n```\n\nFor each `UNKNOWN_MARKER:` line, rewrite that item's marker as `(path assumed)`\n(Write the whole file again) and re-run the scan until it prints nothing.\n\nThen scan the file for credentials — a session's notes quote commands, configs\nand logs:\n\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-redact\" scan --file \"{FILE}\"; echo \"REDACT_EXIT: $?\"\n```\n\n`REDACT_EXIT: 1` lists masked findings with line numbers: replace each value\nwith `[REDACTED]`, write the file again and re-scan until exit 0. `2` means the\nscan could not run — say so in the confirmation.\n\nAfter writing, confirm to the user:\n\n```\nCONTEXT SAVED\n════════════════════════════════════════\nTitle:    {title}\nBranch:   {branch}\nFile:     {path to saved file}\nModified: {N} files\nDuration: {duration or \"unknown\"}\n════════════════════════════════════════\n\nRestore later with \u002Fcontext-restore.\n```\n\n---\n\n## List flow\n\n### Step 1: Gather saved contexts\n\n```bash\neval \"$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-slug\" 2>\u002Fdev\u002Fnull)\" && mkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\"\nCHECKPOINT_DIR=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fprojects\u002F$SLUG\u002Fcheckpoints\"\nif [ -d \"$CHECKPOINT_DIR\" ]; then\n  echo \"CHECKPOINT_DIR=$CHECKPOINT_DIR\"\n  # Use find + sort instead of ls -1t: filename YYYYMMDD-HHMMSS prefix is the\n  # canonical order (stable across copies\u002Frsync; mtime is not), and empty-result\n  # behavior is clean (no files → no output, no \"lists cwd\" fallback).\n  find \"$CHECKPOINT_DIR\" -maxdepth 1 -name \"*.md\" -type f 2>\u002Fdev\u002Fnull | sort -r\nelse\n  echo \"NO_CHECKPOINTS\"\nfi\n```\n\n### Step 2: Display table\n\n**Default behavior:** Show saved contexts for the **current branch** only.\n\nIf the user passes `--all` (e.g., `\u002Fcontext-save list --all`), show contexts\nfrom **all branches**.\n\nRead the frontmatter of each file to extract `status`, `branch`, and\n`timestamp`. Parse the title from the filename (the part after the timestamp).\n\nPresent as a table:\n\n```\nSAVED CONTEXTS ({branch} branch)\n════════════════════════════════════════\n#  Date        Title                    Status\n─  ──────────  ───────────────────────  ───────────\n1  2026-04-18  auth-refactor            in-progress\n2  2026-04-17  api-pagination           completed\n3  2026-04-15  db-migration-setup       in-progress\n════════════════════════════════════════\n```\n\nIf `--all` is used, add a Branch column:\n\n```\nSAVED CONTEXTS (all branches)\n════════════════════════════════════════\n#  Date        Title                    Branch              Status\n─  ──────────  ───────────────────────  ──────────────────  ───────────\n1  2026-04-18  auth-refactor            feat\u002Fauth           in-progress\n2  2026-04-17  api-pagination           main                completed\n3  2026-04-15  db-migration-setup       feat\u002Fdb-migration   in-progress\n════════════════════════════════════════\n```\n\nIf there are no saved contexts, tell the user: \"No saved contexts yet. Run\n`\u002Fcontext-save` to save your current working state.\"\n\n---\n\n## Important Rules\n\n- **Never modify code.** This skill only reads state and writes the context file.\n- **Always include the branch name** in frontmatter — critical for cross-branch\n  `\u002Fcontext-restore`.\n- **Always stamp the project identity** with `vibe-slug --stamp-checkpoint`, run\n  from inside the project — never hand-write `remote:` or `project_root:`.\n- **Saved files are append-only.** Never overwrite or delete existing files. Each\n  save creates a new file.\n- **Infer, don't interrogate.** Use git state and conversation context to fill in\n  the file. Only use AskUserQuestion if the title genuinely cannot be inferred.\n- **This is a vibestack skill, not a Claude Code built-in.** When the user types\n  `\u002Fcontext-save`, invoke this skill via the Skill tool. The old `\u002Fcheckpoint`\n  name collided with Claude Code's native `\u002Frewind` alias — the rename fixed that.\n- **Automatic snapshots are not a save.** In Claude Code a PreCompact hook writes\n  a git-state snapshot to `~\u002F.vibestack\u002Fprojects\u002F\u003Cslug>\u002Fcompact-snapshots\u002F`\n  before every compaction. It holds git state and the transcript path only,\n  never decisions, so `\u002Fcontext-save` stays the way to record decisions. Other\n  runtimes have no compaction hook in this pack.\n\n---\n\nRun this step before finishing. A saved context file is read once, by whoever\nrestores it; a learning outlives it and surfaces in every later session's\npreamble. If the session genuinely surfaced none, say \"no durable learnings this\nsession\" rather than inventing one.\n\n{{include lib\u002Fsnippets\u002Fcapture-learnings.md}}\n",{"name":5,"triggers":44,"description":47,"allowed-tools":48},[25,45,46,20],"save state","save my work","Save working context (git state, decisions, remaining work) so a later session can pick up where you left off.\n",[35,49,50,51,52,53],"Read","Write","Glob","Grep","AskUserQuestion","main","777ec643a83c17a0955856b2eb7f596601709fda","skills\u002Fcontext-save",0,"https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack","https:\u002F\u002Fgithub.com\u002Ftimurgaleev","https:\u002F\u002Ftgaleev.com\u002F","Forward Deployed Engineer \u002F\r\nAWS Community Builder \u002F Cloud Architect ","2026-11-11 04:50:32",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add timurgaleev\u002Fvibestack --skill context-save",{"tool":69,"command":70},"bunx","bunx skills add timurgaleev\u002Fvibestack --skill context-save",{"tool":72,"command":73},"pnpm","pnpm dlx skills add timurgaleev\u002Fvibestack --skill context-save","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Fskills\u002Fcontext-save\u002FSKILL.md",true,[],[78,84,90,96,102,108],{"skillNo":79,"name":80,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":39},"01M71GVHCCSQCCPVM8XPSPTA73","docs","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F15-backtick-info-string\u002Fskills\u002Fdocs\u002FSKILL.md",[],[80],{"skillNo":85,"name":86,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":39},"01M71GVFT1S5MRNM0AYRT2E6VQ","fences","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F14-indented-tilde-fence\u002Fskills\u002Ffences\u002FSKILL.md",[],[86],{"skillNo":91,"name":92,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":39},"01M71GVEYB54K1S83FGRNKN8CF","dirty","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F10-check-with-drift\u002Fskills\u002Fdirty\u002FSKILL.md",[],[92],{"skillNo":97,"name":98,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":101,"publishedAt":39},"01M71GVDX9PMND1337C4388DK4","clean","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F09-check-no-drift\u002Fskills\u002Fclean\u002FSKILL.md",[],[98],{"skillNo":103,"name":104,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":107,"publishedAt":39},"01M71GVC3VM66F1ZQT2G8JXDR0","bare","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F08-no-frontmatter\u002Fskills\u002Fbare\u002FSKILL.md",[],[104],{"skillNo":109,"name":110,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":39},"01M71GV9T8DAYZT0PX52QX0TE1","idem","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F07-idempotent-rerender\u002Fskills\u002Fidem\u002FSKILL.md",[],[110]]