Session Stash
You make in-flight agent sessions portable across harnesses, context windows, and time. A stash captures a session as an encrypted-by-default, git-versioned folder in the project at docs/session-stash/<name>/ (unencrypted only with explicit operator opt-out, confirmed before commit). A pop is the opposite: any agent — in any harness — enters the stash folder and its own AGENTS.md tells it how to resume.
The invariants (MUST NOT violate)
- Consumptive pops — popping consumes the stash: it is logically destroyed (leaves the active index, like
git stash drop) but never physically deleted. The folder moves to consumed/ and stays readable so the resuming agent can keep referencing its contents. A stash can be popped into only one session.
- Encrypted by default; plaintext only with operator sign-off — transcripts are untrustworthy by default. The encrypted-at-rest path is the protocol default. An unencrypted stash is allowed only when the operator explicitly opts out of encryption, and an unencrypted stash MUST NOT be committed until the operator confirms it is intended and secret-free. Only the stash's
AGENTS.md is ever scrubbed-plaintext by default.
- Light resume is context-only — the disclosure stack is summarized context; all state (patch, file map, git tag) lives in sidecars the resuming agent pulls on demand.
- Operator-initiated — you stash only when the operator asks. Never auto-stash.
- Fail loud — if a stash is missing, unreadable, un-decryptable, or its AGENTS.md violates the scrubbing contract, STOP and tell the operator. Never silently degrade, coerce, or fall back. Never commit an unencrypted stash without explicit operator confirmation.
When the operator says "stash this session"
- Check for an encryption key FIRST — before creating anything, check whether a per-project age key is retrievable (from
settings.yaml confirmation, your knowledge of the operator's secrets management, or the secret manager).
- Key exists → proceed to step 1; encryption stays the default path.
- No key exists or none is retrievable → STOP and ask the operator NOW, before building the stash: "no age key is available for this project — an unencrypted stash would put the full transcript, patch, and refs in the repo as plaintext." Include a risk-exposure review of what this session's stash would contain: scan your session history for secrets-looking material (API keys, tokens, credentials in tool output, private hostnames/paths, identity-revealing content) and report what would sit plaintext if committed. The operator then chooses: set up a key (encrypt), or proceed unencrypted (which still requires the operator's explicit confirm-before-commit gate in step 7). Never skip this prompt, never infer the answer from silence, and never start capturing the stash before it is resolved.
- Create the folder at
docs/session-stash/YYYY-MM-DD_HH-MM-<slug>/ (slug = 2-5 word topic).
- Build the file map — review your own session history (transcript/tool calls). Identify every file the session touched, read, wrote, or referenced. Do NOT use mtime heuristics (parallel agents share the filespace). Write
file-map.md (a sidecar).
- Capture the state sidecars:
git-tag.txt — the commit the session is anchored to (git rev-parse HEAD).
patch.diff — git diff filtered to the file map only (session-relevant uncommitted work, NOT all uncommitted work).
refs/ — reference files (images, logs, artifacts) the session produced or dropped.
- Capture the normalized transcript as
transcript.md (full session) — harness-agnostic markdown: the story of the session with messages, tool calls, results, decisions. See references/transcript-format.md.
- Write the disclosure stack —
resume.md (context-only, summarized) plus tiered summary files per references/disclosure-tiers.md. The stack summarizes, never includes verbatim secrets.
- Write the stash AGENTS.md — plaintext, scrubbed per
references/scrubbing-contract.md. It is the router: it maps context-window tiers to files/line-ranges and tells the resuming agent where the key is.
- Encrypt everything except AGENTS.md (default path) — age-encrypt
resume.md, transcript.md, file-map.md, git-tag.txt, patch.diff, and refs/ using the project's per-project age key. Confirm key retrieval with the operator on first use per key (see Key retrieval).
- Unencrypted path — if the operator explicitly opts out of encryption (decided at step 0 or later: "stash it unencrypted" / "don't encrypt this one"), skip step 7 but do NOT commit yet. First: (a) scrub
resume.md, transcript.md, and refs/ against the scrubbing contract — the same MUST NOT rules apply to any file that will sit plaintext in the repo; (b) ask the operator to confirm: "this stash will be committed unencrypted — confirm it contains no secrets and that's intended." If the operator confirms, mark the stash mode: unencrypted in the index and settings (see references/encryption-and-keys.md); if the operator cannot confirm, STOP — encrypt or drop the stash, never commit an unconfirmed plaintext stash.
- Update the index and settings — add the stash to
docs/session-stash/README.md (index) and ensure docs/session-stash/settings.yaml records the mode (encrypted or unencrypted), plus the public key + confirmed retrieval source when encrypted.
- Commit the stash folder to the project repo.
When the operator says "pop session @docs/session-stash//"
The pop is not in the skill — it's the stash folder's own AGENTS.md doing the work. The skill's job is to ensure that AGENTS.md is correct and complete so any harness can self-orient. When you or another agent pop:
- Read the stash's
AGENTS.md first — it routes what to load for your context window.
- Pull sidecars (patch, file map, git tag) only as needed.
- Decrypt transcript/resume with the referenced key (only for encrypted stashes — unencrypted stashes read directly).
- Resume.
- Consume the stash — once resumed, move the folder from
docs/session-stash/<name>/ to docs/session-stash/consumed/<name>/, drop it from the active index (README.md), and write a consumed.md tombstone inside it recording the pop date and the resumed session's outcome. This is a move, never an rm — the folder stays readable so you (or a future operator) can reference its contents after popping. A pop is single-use: the same stash cannot be popped into two sessions.
Key retrieval
- Use what you know of the user's secrets management first; confirm that choice with the operator on first use per key.
- Remember the confirmed source in
docs/session-stash/settings.yaml (plaintext, scrubbed — public key + confirmed source only). Subsequent pops for the same key reuse it without re-confirmation.
- If you cannot determine retrieval, or confirmation is wrong, STOP and fail loudly. Never guess silently.
Conversion
When the operator says "convert stash to ...", the stash closes:
- → sashay — read the stash, write a fresh plan under
docs/plans/ (judgment, not template), then archive the stash to docs/session-stash/backlog/ with a cross-reference. The plan becomes the source of truth.
- → musing — distill the stash's outcome into a musing under
docs/musings/, then archive the stash.
- → Jira (or other external tracker) — summarize into a ticket, then archive the stash.
Conversion always closes the stash: it moves to backlog/ (archive, never delete).
Off-ramp
When the active stash count exceeds a threshold (default 8, configurable in settings.yaml), surface to the operator the option to move some stashes to backlog/. Never move stashes without operator approval.
Reference documents
references/scrubbing-contract.md — what the stash AGENTS.md may/may not contain; the plaintext-safe contract.
references/disclosure-tiers.md — the progressive-disclosure stack and per-window line routing.
references/transcript-format.md — the normalized, harness-agnostic transcript schema.
references/encryption-and-keys.md — age encryption, per-project keys, retrieval confirmation.
references/index-and-settings.md — index README + settings.yaml schema.
1---2name: session-stash3description: Stash and pop portable agent sessions. A session stash is a durable, git-versioned capture of an in-flight session (normalized transcript + session-relevant uncommitted work + reference files) stored at `docs/session-stash/<name>/`. Stash an active session to resume it later in a different harness (Claude, opencode), a different context window, or a fresh model. Pop a stash to have the resuming agent self-orient from the stash folder's own AGENTS.md. Convert a stash to a sashay, musing, or Jira ticket. Use when the operator says "stash this session", "pop session @docs/session-stash/...", "resume the stashed session", or "convert stash to ...". Do NOT use for in-session compression or for sessions you intend to resume in the same harness the same way.4license: MIT5---67# Session Stash89You make in-flight agent sessions portable across harnesses, context windows, and time. A **stash** captures a session as an encrypted-by-default, git-versioned folder in the project at `docs/session-stash/<name>/` (unencrypted only with explicit operator opt-out, confirmed before commit). A **pop** is the opposite: any agent — in any harness — enters the stash folder and its own AGENTS.md tells it how to resume.1011## The invariants (MUST NOT violate)12131. **Consumptive pops** — popping consumes the stash: it is logically destroyed (leaves the active index, like `git stash drop`) but **never physically deleted**. The folder moves to `consumed/` and stays readable so the resuming agent can keep referencing its contents. A stash can be popped into only one session.142. **Encrypted by default; plaintext only with operator sign-off** — transcripts are untrustworthy by default. The encrypted-at-rest path is the protocol default. An unencrypted stash is allowed only when the operator explicitly opts out of encryption, and an unencrypted stash MUST NOT be committed until the operator confirms it is intended and secret-free. Only the stash's `AGENTS.md` is ever scrubbed-plaintext by default.153. **Light resume is context-only** — the disclosure stack is summarized context; all state (patch, file map, git tag) lives in sidecars the resuming agent pulls on demand.164. **Operator-initiated** — you stash only when the operator asks. Never auto-stash.175. **Fail loud** — if a stash is missing, unreadable, un-decryptable, or its AGENTS.md violates the scrubbing contract, STOP and tell the operator. Never silently degrade, coerce, or fall back. Never commit an unencrypted stash without explicit operator confirmation.1819## When the operator says "stash this session"20210. **Check for an encryption key FIRST** — before creating anything, check whether a per-project age key is retrievable (from `settings.yaml` confirmation, your knowledge of the operator's secrets management, or the secret manager). 22 - **Key exists** → proceed to step 1; encryption stays the default path.23 - **No key exists or none is retrievable** → STOP and ask the operator NOW, before building the stash: "no age key is available for this project — an unencrypted stash would put the full transcript, patch, and refs in the repo as plaintext." Include a **risk-exposure review** of what this session's stash would contain: scan your session history for secrets-looking material (API keys, tokens, credentials in tool output, private hostnames/paths, identity-revealing content) and report what would sit plaintext if committed. The operator then chooses: set up a key (encrypt), or proceed unencrypted (which still requires the operator's explicit confirm-before-commit gate in step 7). Never skip this prompt, never infer the answer from silence, and never start capturing the stash before it is resolved.241. **Create the folder** at `docs/session-stash/YYYY-MM-DD_HH-MM-<slug>/` (slug = 2-5 word topic).252. **Build the file map** — review your own session history (transcript/tool calls). Identify every file the session touched, read, wrote, or referenced. Do NOT use mtime heuristics (parallel agents share the filespace). Write `file-map.md` (a sidecar).263. **Capture the state sidecars**:27 - `git-tag.txt` — the commit the session is anchored to (`git rev-parse HEAD`).28 - `patch.diff` — `git diff` filtered to the file map only (session-relevant uncommitted work, NOT all uncommitted work).29 - `refs/` — reference files (images, logs, artifacts) the session produced or dropped.304. **Capture the normalized transcript** as `transcript.md` (full session) — harness-agnostic markdown: the story of the session with messages, tool calls, results, decisions. See `references/transcript-format.md`.315. **Write the disclosure stack** — `resume.md` (context-only, summarized) plus tiered summary files per `references/disclosure-tiers.md`. The stack summarizes, never includes verbatim secrets.326. **Write the stash AGENTS.md** — plaintext, scrubbed per `references/scrubbing-contract.md`. It is the router: it maps context-window tiers to files/line-ranges and tells the resuming agent where the key is.337. **Encrypt everything except AGENTS.md (default path)** — age-encrypt `resume.md`, `transcript.md`, `file-map.md`, `git-tag.txt`, `patch.diff`, and `refs/` using the project's per-project age key. Confirm key retrieval with the operator on first use per key (see Key retrieval).34 - **Unencrypted path** — if the operator explicitly opts out of encryption (decided at step 0 or later: "stash it unencrypted" / "don't encrypt this one"), skip step 7 but do NOT commit yet. First: (a) scrub `resume.md`, `transcript.md`, and `refs/` against the scrubbing contract — the same MUST NOT rules apply to any file that will sit plaintext in the repo; (b) ask the operator to confirm: "this stash will be committed unencrypted — confirm it contains no secrets and that's intended." If the operator confirms, mark the stash `mode: unencrypted` in the index and settings (see `references/encryption-and-keys.md`); if the operator cannot confirm, STOP — encrypt or drop the stash, never commit an unconfirmed plaintext stash.358. **Update the index and settings** — add the stash to `docs/session-stash/README.md` (index) and ensure `docs/session-stash/settings.yaml` records the mode (`encrypted` or `unencrypted`), plus the public key + confirmed retrieval source when encrypted.369. **Commit** the stash folder to the project repo.3738## When the operator says "pop session @docs/session-stash/<name>/"3940The pop is **not in the skill** — it's the stash folder's own AGENTS.md doing the work. The skill's job is to ensure that AGENTS.md is correct and complete so any harness can self-orient. When you or another agent pop:41421. Read the stash's `AGENTS.md` first — it routes what to load for your context window.432. Pull sidecars (patch, file map, git tag) only as needed.443. Decrypt transcript/resume with the referenced key (only for encrypted stashes — unencrypted stashes read directly).454. Resume.465. **Consume the stash** — once resumed, move the folder from `docs/session-stash/<name>/` to `docs/session-stash/consumed/<name>/`, drop it from the active index (`README.md`), and write a `consumed.md` tombstone inside it recording the pop date and the resumed session's outcome. This is a **move, never an `rm`** — the folder stays readable so you (or a future operator) can reference its contents after popping. A pop is single-use: the same stash cannot be popped into two sessions.4748## Key retrieval4950- Use what you know of the user's secrets management first; **confirm that choice with the operator** on first use per key.51- Remember the confirmed source in `docs/session-stash/settings.yaml` (plaintext, scrubbed — public key + confirmed source only). Subsequent pops for the same key reuse it without re-confirmation.52- If you cannot determine retrieval, or confirmation is wrong, STOP and fail loudly. Never guess silently.5354## Conversion5556When the operator says "convert stash to ...", the stash closes:5758- **→ sashay** — read the stash, write a fresh plan under `docs/plans/` (judgment, not template), then archive the stash to `docs/session-stash/backlog/` with a cross-reference. The plan becomes the source of truth.59- **→ musing** — distill the stash's outcome into a musing under `docs/musings/`, then archive the stash.60- **→ Jira** (or other external tracker) — summarize into a ticket, then archive the stash.6162Conversion always closes the stash: it moves to `backlog/` (archive, never delete).6364## Off-ramp6566When the active stash count exceeds a threshold (default 8, configurable in `settings.yaml`), surface to the operator the option to move some stashes to `backlog/`. Never move stashes without operator approval.6768## Reference documents6970- `references/scrubbing-contract.md` — what the stash AGENTS.md may/may not contain; the plaintext-safe contract.71- `references/disclosure-tiers.md` — the progressive-disclosure stack and per-window line routing.72- `references/transcript-format.md` — the normalized, harness-agnostic transcript schema.73- `references/encryption-and-keys.md` — age encryption, per-project keys, retrieval confirmation.74- `references/index-and-settings.md` — index README + settings.yaml schema.