Preserve
Preserve the current session's context into the three-file system so the next session can start cold. Run this at the end of a session, before /clear.
Scaffold check
![ -f state.md ] && [ -f decisions.md ] && echo "SCAFFOLD_OK" || echo "SCAFFOLD_MISSING: run the scaffold skill first"
If the output above says SCAFFOLD_MISSING, stop immediately and tell the user to run the scaffold skill. Do not continue.
Session changes
Files changed this session:
!git diff --stat
!git diff --cached --stat
Changed file list:
!git diff --name-only
!git diff --cached --name-only
Untracked files (won't appear in the diffs above):
!git ls-files --others --exclude-standard 2>/dev/null | grep . || echo "(none)"
Recent commits:
!git log --oneline -10 2>/dev/null | grep . || echo "(no commits)"
Last commit that touched state.md (the staleness anchor):
!git log -1 --format="%h %ad %s" --date=short -- state.md 2>/dev/null | grep . || echo "(state.md has never been committed — use the recent commits above instead)"
Commits made since state.md was last committed (work already committed this session — the diff above won't show it):
!git log -1 --format=%H..HEAD -- state.md 2>/dev/null | git rev-list --stdin --oneline 2>/dev/null | grep . || echo "(none)"
Rules
Don't ask questions — just do it. Derive everything from the session's conversation, the injected git diff above, and the current state of the three files. Present the result for review when done. The commit offer in rule 11 is the single deliberate exception.
Require the tracked scaffold files. If the scaffold check above says SCAFFOLD_MISSING, stop and tell the user to run the scaffold skill first. Do not create state.md or decisions.md. A missing scratch.md is fine — it's gitignored, so it won't exist after a fresh clone; the wipe step recreates it.
Read before writing. Before touching anything, read the current state.md, decisions.md, and scratch.md (if it exists) so you know what's already there.
Use the injected context. The git output above (uncommitted diff, untracked files, and commits since the last preserve) was injected at skill load time. Combine it with the conversation history — don't rely on either source alone; the diff misses work already committed this session, and the commit list covers it. The diff also never shows untracked files, so treat every path in the untracked list as new work from this session and account for it in state.md. Do not re-run git unless the injected output is empty.
Be concrete, not reflective. Every section in state.md should contain specific file paths, function names, error messages, or next steps. Never write vague summaries like "made good progress" or "things are working well."
Decisions have a threshold. Only append to decisions.md if a decision meets at least two of these criteria:
- Closes a door — choosing A over B, and going back would cost real time
- Future-you would ask "why did we do it this way?" and the answer isn't obvious from the code
- Something was explicitly rejected
- Changes the project's direction or constraints
If nothing qualifies, don't append anything. Don't log variable naming, formatting, or anything reversible in five minutes.
Every new decision is **Status:** active. It's the first field line of the entry. An existing entry with no Status line is active — do not backfill it.
decisions.md is append-only, with one exception: the Status line. Add new entries after the last existing entry. Never remove, reword, or reorder an existing entry. If a decision made this session directly reverses an earlier entry, change that entry's Status from active to superseded — that one line, nothing else — and say which entry you flipped and why. Merely revisiting or extending a decision is not a reversal.
Harvest scratch.md before wiping it. Read it and move anything still relevant into the matching existing state.md section — open questions and next actions into "Next session should start with", gotchas into "Landmines", unfinished threads into "What's broken / in-progress". Do not add a new section for them. Then list for the user, explicitly, every scratch note you discarded, so nothing disappears silently.
Wipe scratch.md clean. Only after the harvest. Replace its contents with just the header comment and heading — nothing else. Create it if it doesn't exist.
Present the result. After writing all three files, show the user what was written to state.md, what was appended to decisions.md (if anything), any Status flip, and the discarded scratch notes — so they can correct it before the session ends.
Offer to commit. After presenting, ask once: commit state.md and decisions.md? A single yes/no — do not negotiate the message or stage anything else. On yes, git add state.md decisions.md and commit with a short lowercase-style message like Preserve session state. On no, say nothing further. This is the only question this skill asks; the offer is what makes committing the user's call.
Templates
state.md — full replacement
<!-- Context bridge between sessions. Replace the contents of this file before ending a session so the next one can pick up without re-reading the entire codebase. -->
# State
## Where we ended
[What was the last thing being worked on. File paths, function names, specific context.]
## What's working
[Features, systems, or components confirmed working this session.]
## What's broken / in-progress
[Anything left incomplete, failing, or partially implemented. Include error messages if relevant.]
## Decided this session
[Quick summary of decisions made — details go in decisions.md.]
## Next session should start with
[The first concrete action for next session. Not a wish list — the single most important next step, then supporting items.]
## Landmines
[Gotchas, surprising behavior, things that look wrong but are intentional, or things that look right but are broken.]
decisions.md — append only
### YYYY-MM-DD — [Decision title]
**Status:** active
**Why:** [Rationale — what drove the decision]
**Rejected:** [What was considered and passed over, and why]
scratch.md — wiped
<!-- Ephemeral working notes. Ideas, open questions, tangents during a session. Gitignored and wiped between sessions. -->
# Scratch
Execution order
- Check that
state.md and decisions.md exist in the project root — if either is missing, tell the user to run the scaffold skill and stop
- Read current contents of
state.md, decisions.md, and scratch.md (if it exists)
- Decide which
scratch.md notes are still relevant and which section of state.md each belongs in
- Overwrite
state.md with filled-in template using the injected git context (diff, untracked files, plus commits), conversation history, and the harvested scratch notes
- Review session for decisions that meet the threshold — append to
decisions.md with **Status:** active if any qualify, skip if none do
- If a new decision directly reverses an earlier entry, flip that entry's Status line to
superseded
- Wipe
scratch.md back to its empty template (create it if missing)
- Show the user what was written to
state.md, what was appended to decisions.md, any Status flip, and every discarded scratch note
- Offer once to commit
state.md and decisions.md; commit only on yes
1---2name: preserve3description: End-of-session context preservation that updates state.md, appends decisions to decisions.md, and wipes scratch.md. Use when wrapping up a session, before /clear, or when the user says they're done for now.4---56# Preserve78Preserve the current session's context into the three-file system so the next session can start cold. Run this at the end of a session, before `/clear`.910## Scaffold check1112!`[ -f state.md ] && [ -f decisions.md ] && echo "SCAFFOLD_OK" || echo "SCAFFOLD_MISSING: run the scaffold skill first"`1314**If the output above says SCAFFOLD_MISSING, stop immediately and tell the user to run the scaffold skill. Do not continue.**1516## Session changes1718Files changed this session:19!`git diff --stat`20!`git diff --cached --stat`2122Changed file list:23!`git diff --name-only`24!`git diff --cached --name-only`2526Untracked files (won't appear in the diffs above):27!`git ls-files --others --exclude-standard 2>/dev/null | grep . || echo "(none)"`2829Recent commits:3031!`git log --oneline -10 2>/dev/null | grep . || echo "(no commits)"`3233Last commit that touched `state.md` (the staleness anchor):3435!`git log -1 --format="%h %ad %s" --date=short -- state.md 2>/dev/null | grep . || echo "(state.md has never been committed — use the recent commits above instead)"`3637Commits made since `state.md` was last committed (work already committed this session — the diff above won't show it):3839!`git log -1 --format=%H..HEAD -- state.md 2>/dev/null | git rev-list --stdin --oneline 2>/dev/null | grep . || echo "(none)"`4041## Rules42430. **Don't ask questions — just do it.** Derive everything from the session's conversation, the injected git diff above, and the current state of the three files. Present the result for review when done. The commit offer in rule 11 is the single deliberate exception.44451. **Require the tracked scaffold files.** If the scaffold check above says `SCAFFOLD_MISSING`, stop and tell the user to run the scaffold skill first. Do not create `state.md` or `decisions.md`. A missing `scratch.md` is fine — it's gitignored, so it won't exist after a fresh clone; the wipe step recreates it.46472. **Read before writing.** Before touching anything, read the current `state.md`, `decisions.md`, and `scratch.md` (if it exists) so you know what's already there.48493. **Use the injected context.** The git output above (uncommitted diff, untracked files, and commits since the last preserve) was injected at skill load time. Combine it with the conversation history — don't rely on either source alone; the diff misses work already committed this session, and the commit list covers it. The diff also never shows untracked files, so treat every path in the untracked list as new work from this session and account for it in `state.md`. Do not re-run git unless the injected output is empty.50514. **Be concrete, not reflective.** Every section in `state.md` should contain specific file paths, function names, error messages, or next steps. Never write vague summaries like "made good progress" or "things are working well."52535. **Decisions have a threshold.** Only append to `decisions.md` if a decision meets at least two of these criteria:54 - Closes a door — choosing A over B, and going back would cost real time55 - Future-you would ask "why did we do it this way?" and the answer isn't obvious from the code56 - Something was explicitly rejected57 - Changes the project's direction or constraints5859 If nothing qualifies, don't append anything. Don't log variable naming, formatting, or anything reversible in five minutes.60616. **Every new decision is `**Status:** active`.** It's the first field line of the entry. An existing entry with no Status line is active — do not backfill it.62637. **`decisions.md` is append-only, with one exception: the Status line.** Add new entries after the last existing entry. Never remove, reword, or reorder an existing entry. If a decision made this session *directly reverses* an earlier entry, change that entry's Status from `active` to `superseded` — that one line, nothing else — and say which entry you flipped and why. Merely revisiting or extending a decision is not a reversal.64658. **Harvest `scratch.md` before wiping it.** Read it and move anything still relevant into the matching existing `state.md` section — open questions and next actions into "Next session should start with", gotchas into "Landmines", unfinished threads into "What's broken / in-progress". Do not add a new section for them. Then list for the user, explicitly, every scratch note you discarded, so nothing disappears silently.66679. **Wipe scratch.md clean.** Only after the harvest. Replace its contents with just the header comment and heading — nothing else. Create it if it doesn't exist.686910. **Present the result.** After writing all three files, show the user what was written to `state.md`, what was appended to `decisions.md` (if anything), any Status flip, and the discarded scratch notes — so they can correct it before the session ends.707111. **Offer to commit.** After presenting, ask once: commit `state.md` and `decisions.md`? A single yes/no — do not negotiate the message or stage anything else. On yes, `git add state.md decisions.md` and commit with a short lowercase-style message like `Preserve session state`. On no, say nothing further. This is the only question this skill asks; the offer is what makes committing the user's call.7273## Templates7475### `state.md` — full replacement7677```markdown78<!-- Context bridge between sessions. Replace the contents of this file before ending a session so the next one can pick up without re-reading the entire codebase. -->7980# State8182## Where we ended83[What was the last thing being worked on. File paths, function names, specific context.]8485## What's working86[Features, systems, or components confirmed working this session.]8788## What's broken / in-progress89[Anything left incomplete, failing, or partially implemented. Include error messages if relevant.]9091## Decided this session92[Quick summary of decisions made — details go in decisions.md.]9394## Next session should start with95[The first concrete action for next session. Not a wish list — the single most important next step, then supporting items.]9697## Landmines98[Gotchas, surprising behavior, things that look wrong but are intentional, or things that look right but are broken.]99```100101### `decisions.md` — append only102103```markdown104### YYYY-MM-DD — [Decision title]105**Status:** active106**Why:** [Rationale — what drove the decision]107**Rejected:** [What was considered and passed over, and why]108```109110### `scratch.md` — wiped111112```markdown113<!-- Ephemeral working notes. Ideas, open questions, tangents during a session. Gitignored and wiped between sessions. -->114115# Scratch116```117118## Execution order1191201. Check that `state.md` and `decisions.md` exist in the project root — if either is missing, tell the user to run the scaffold skill and stop1212. Read current contents of `state.md`, `decisions.md`, and `scratch.md` (if it exists)1223. Decide which `scratch.md` notes are still relevant and which section of `state.md` each belongs in1234. Overwrite `state.md` with filled-in template using the injected git context (diff, untracked files, plus commits), conversation history, and the harvested scratch notes1245. Review session for decisions that meet the threshold — append to `decisions.md` with `**Status:** active` if any qualify, skip if none do1256. If a new decision directly reverses an earlier entry, flip that entry's Status line to `superseded`1267. Wipe `scratch.md` back to its empty template (create it if missing)1278. Show the user what was written to `state.md`, what was appended to `decisions.md`, any Status flip, and every discarded scratch note1289. Offer once to commit `state.md` and `decisions.md`; commit only on yes