Session memory management 🦆📼. Context hygiene, persistent memory, session state handoff.
Purpose
Two-tier memory management for active sessions.
- Tier 1 (persistent):
CONTEXT.mdin cwd. Long-term, repo-tracked. 7 fixed sections, deterministic merge. - Tier 2 (working):
.duck-tape/<session_id>.state.md. Short-term, not committed. Agent State schema. Staging input for CONTEXT.md merge.
Preserve fidelity, keep interruption low.
{{include: skill-snippets/philosophy-guardrails.md}} {{include: skill-snippets/clarify-first-preflight.md}}
Skill-specific delta:
- Persistent artifact safety: CONTEXT.md is long-lived and likely committed. Redaction is non-negotiable before any write.
- Session state safety:
.duck-tape/<id>.state.mdis workspace-local but may be read by next agent. Redaction applies. - Rotation cap: max 10 state files in
.duck-tape/. Eviction precedence: auto dropped first, then recovered, then manual. - Pre-compact marker (
.duck-tape/.last-compact) is harness-written, non-semantic. No approval required for marker write.
Activation
State-only (default): write session state file. Signals: /duck-tape, "save session state", "checkpoint session".
Merge (CONTEXT.md): write state file plus merge into CONTEXT.md. Signals: "compact session", "update CONTEXT.md", "persist memory", /duck-tape merge.
Resume: detect compaction and reload checkpoint. Signals: /duck-tape resume, "resume session". Read-only when manual checkpoint exists. If only auto-checkpoint or no state file, invokes LLM-assisted recovery that writes -recovered.state.md (approval required).
Method
1. Redact incoming content
Scan session content for secrets/PII: API keys, passwords, tokens, connection strings, env var values, personally identifiable information. On detection: reject flagged content, report findings, ask user to redact source or confirm mask-in-place (<REDACTED>). If a write would contain raw secrets, reject it; write masked content only after user confirmation. Applies to both tiers.
2. Write session state file
Write .duck-tape/<session_id>.state.md using Agent State schema. Session ID format: <YYYY-MM-DD-HHMM>. Full schema in references/STATE_SCHEMA.md. Output format in references/OUTPUT_SCHEMA.md. Sample in examples/STATE.md. Auto-create .duck-tape/.gitignore with * content if missing.
Session ID handling:
- Default: auto-generate
<YYYY-MM-DD-HHMM>silently for/duck-tapeand/duck-tape merge. - Ask for session ID only when user explicitly requests a custom ID.
- If custom ID is provided and invalid, ask one corrective question with required format, then continue.
Apply rotation cap: max 10 state files. Eviction precedence: auto dropped first (oldest auto), then recovered, then manual.
Report state file path: .duck-tape/<session_id>.state.md — user can use this to reload session state later.
3. Merge into CONTEXT.md (conditional)
Run only on merge signals. Skip for state-only mode.
Bootstrap (CONTEXT.md missing): create CONTEXT.md with translated content from state file using rigid map in references/STATE_SCHEMA.md. Empty sections get scaffold from examples/bootstrap-CONTEXT.md. Generate TOC under title from the 8 section headers. Output format in references/OUTPUT_SCHEMA.md. Sample in examples/CONTEXT.md. If Goals or Conventions entries are missing, leave them empty; do not infer.
Merge (CONTEXT.md exists): translate from session state file using rigid map. Summarize translated content to persistent-context granularity (decision-level, not commit-level) before applying per-section merge rules. Refresh TOC only if the set of ## section headings changes. Per-section merge rules in references/SCHEMA.md. Summary:
- Goals/Decisions/Conventions/Glossary: dedupe by key, supersede on conflict, append new
- Deferred-Debt: append-only with status markers
- Open-Questions: append new, dedupe by text
- Notes: timestamped append-only, no rewrite.
- Re-derivation + Suggested Skills: state-file-local, not translated to CONTEXT.md
- Position.Current + Position.Done: state-file-local, not translated. Next agent reads state file on resume.
Emit changelog per references/OUTPUT_SCHEMA.md. Sample in examples/CHANGELOG.md:
Added: <section> <key>Superseded: <section> <key> (<old> -> <new>)Dropped: <section> <key> (<reason>)
Drops require explicit reason. No silent removal.
4. Execution approval
{{include: policy-snippets/mutating-action-gate.md}}
Preflight per operation:
State-only:
- Target files:
.duck-tape/<id>.state.md,.duck-tape/.gitignore(if missing) - Expected: write state file with Agent State schema
- Verification: re-read state file, confirm Agent State sections present
Merge:
- Target files:
.duck-tape/<id>.state.md,.duck-tape/.gitignore(if missing),CONTEXT.md - Expected: write state file, merge translated state into CONTEXT.md per schema rules
- Verification: re-read both files, confirm changelog matches CONTEXT.md diff
Harness integration
Pre-compact trigger writes .duck-tape/.last-compact marker and .duck-tape/<id>-auto.state.md state file before context compaction. State file is auto-extracted from session transcript (Claude Code, Copilot) or fetched via SDK (opencode). Trigger runs as shell script or plugin outside LLM context.
Marker format: <timestamp> | cwd: <path> | latest-state: <file> | transcript: <path>. The transcript field records the source transcript path (Claude Code, Copilot) or opencode snapshot path (<id>-transcript.json). Absent in older markers written before Angle B.
State file (<id>-auto.state.md) contains auto-extracted Approved Workflow, Position (tool calls + last assistant text), and Decision Log (pattern-matched, deduped, last 10). Low-fidelity recovery fallback. Pattern matching catches explicit decisions (APPROVED/DECIDED/CHOSE) but misses implicit ones. Manual /duck-tape checkpoint produces higher-fidelity state. /duck-tape resume with LLM-assisted recovery (Angle B) produces -recovered.state.md with semantic decision extraction, between auto and manual in fidelity.
Trigger falls back to marker-only on failure: jq missing (bash), transcript missing, format unknown, nothing extracted, SDK error (opencode). pre-compact.sh/.ps1 retained as marker-only fallback scripts.
Resume from compaction: see ## Resume below. Triggered by /duck-tape resume, not automatic.
Guided install: see ## Init section below. See references/HOOKS_GUIDE.md for manual install and troubleshooting.
Portability: trigger behavior identical across all three harnesses. No threshold detection. No context re-injection. State file + marker.
Resume
/duck-tape resume — detect compaction and reload checkpoint.
- Check
.duck-tape/.last-compact. If missing, no compaction occurred. Report "no compaction marker found" and stop. - Compare marker timestamp to session start time. If marker older than session start, note "no compaction in this session — marker from a previous session"; the checkpoint is the cross-session handoff point, so continue to step 3 and reload it.
- Read marker fields:
cwd,latest-state,transcript(transcript path or opencode snapshot path; absent in older markers). - Select state file by precedence: manual > recovered > auto.
a. If a manual checkpoint (no suffix) exists and is newer than the newest auto-checkpoint, use manual. Report position from it. Skip to step 6.
b. If only an auto-checkpoint (
-autosuffix) exists or no state file exists at all, invoke LLM-assisted recovery (step 5). - LLM-assisted recovery (Angle B). Produces a higher-fidelity state file than the auto-checkpoint by semantic synthesis from transcript content.
- Transcript path: marker
transcriptfield if present. If absent, no recovery possible; report "compaction occurred but no transcript path in marker" and suggest running/duck-tapeto checkpoint fresh. - Run
hooks/extract-raw.sh <transcript_path>(bash) orhooks/extract-raw.ps1 <transcript_path>(PowerShell on Windows) to get raw material. Script outputs structured markdown: user prompts, tool calls, last 10 assistant messages, potential decisions (pattern-filtered, deduped), failed tool results, session metadata. - Read raw material output.
- Synthesize Agent State file from raw material. Extract decisions semantically (not pattern-matched like Angle A): "we're going with option 2 because X" is a decision even without the keyword. Extract position (current/done/remaining) from assistant messages and tool calls. Extract established facts from tool results and user confirmations.
- Write state file as
.duck-tape/<YYYY-MM-DD-HHMM>-recovered.state.md. - Rotation:
-recoveredfiles share the 10-file cap with manual and auto. Precedence on eviction: auto dropped first, then recovered, then manual. - Report position from new file.
- Transcript path: marker
- Read
CONTEXT.mdif it exists. - Report: compaction timestamp, session state position (Current/Done/Remaining), and any CONTEXT.md decisions relevant to current work.
- State file writes (step 5 only) require approval. Read-only resume (steps 1-4, 6-7) does not write.
If no state file exists and no transcript path in marker, report "compaction occurred but no recoverable state" and suggest running /duck-tape to checkpoint fresh.
Init
/duck-tape init — guided hook install. Opt-in.
- Ask user which harness: opencode, Claude Code, or Copilot.
- Based on choice, identify the correct hook config snippet:
- opencode:
hooks/opencode.plugin.js - Claude Code (unix):
hooks/claude-code.hooks.json - Claude Code (Windows):
hooks/claude-code.hooks.windows.json - Copilot:
hooks/copilot.hooks.json
- opencode:
- Show user the target install path for their harness:
- opencode:
.opencode/plugins/duck-tape.js - Claude Code: merge into repo-local
.claude/settings.local.json(recommended) or.claude/settings.jsonunderhookskey - Copilot:
.github/hooks/duck-tape.json
- opencode:
- Ask user if they want the skill to write the file or show the snippet for manual placement.
- If write: confirm target path with user (approval required, file creation). Write file. Report success.
- If show: print snippet and placement instructions. Point to
references/HOOKS_GUIDE.mdfor troubleshooting. - Confirm
hooks/extract-state.sh(unix) orhooks/extract-state.ps1(Windows) is in project. For opencode, no shell script needed (plugin fetches via SDK). Also confirmhooks/extract-raw.sh/.ps1exists for LLM-assisted recovery on/duck-tape resume.
Preflight:
- Target file: harness-specific config path (max 1 file)
- Expected: write hook config snippet to harness install path
- Verification: re-read written file, confirm valid JSON or JS syntax
Prune
/duck-tape prune — manual. Targets Notes section only.
- List Notes entries with timestamps.
- User picks entries to cull.
- Write culled file. Report what removed.
Preflight:
- Target file:
CONTEXT.md(Notes section only) - Expected: remove user-selected Notes entries, fixed-schema sections untouched
- Verification: re-read CONTEXT.md, confirm only Notes changed, confirm selected entries removed
If pruning, do not touch fixed-schema sections.
Migrate
/duck-tape migrate — restructures existing CONTEXT.md into schema. Classifies freeform content into sections, appends missing headers, leaves unmatched content above schema.
- Read existing CONTEXT.md.
- Identify which of 7 schema sections exist, which are missing.
- Parse freeform content (blocks not under a schema
##header). - Classify each freeform block into nearest schema section:
- Goals: optimization targets, priorities, north-star statements
- Decisions: approved/rejected choices, rationale, dated decisions
- Conventions: naming rules, file layout, style, tooling choices
- Glossary: term definitions, domain vocabulary, acronym expansions
- Deferred-Debt: TODO/FIXME/HACK entries, deferred work
- Open-Questions: unresolved questions, pending clarifications
- Open-Questions: unresolved questions, pending clarifications
- Notes: everything else, freeform observations
- Propose restructure to user. Show mapping: existing block -> target section. Flag low-confidence placements. Leave unmatched blocks listed above schema.
- Get approval. Execute restructure. Generate TOC under title from the 8 section headers. Report what moved, what stayed above schema.
Preflight:
- Target file:
CONTEXT.md - Expected: classify freeform content into schema sections, append missing headers, preserve unmatched content above schema
- Verification: re-read CONTEXT.md, confirm all 7 headers present, confirm all original content accounted for (moved or left above schema)
Boundaries
- Default mode is state-only. CONTEXT.md is written only on merge signals.
- Write only
CONTEXT.md,.duck-tape/<id>.state.md,.duck-tape/<id>-recovered.state.md,.duck-tape/<id>-transcript.json,.duck-tape/.gitignore,.duck-tape/.last-compactmarker. - Respect existing CONTEXT.md structure. If file lacks schema sections, prompt user to migrate before first merge.
- If bootstrap lacks Goals or Conventions entries, add them only from explicit user decisions; do not infer.
- If a Note needs changing at write time, append — do not fuzzy-rewrite.
- If an entry is dropped, record the reason in the changelog; do not drop silently.