Track open-loop ideas, deferred questions, diverging threads — no loss to context compaction or session end. Three on-demand commands (resume, archive, summary) plus behavioral parking rule that writes session-open-*.md memory files as items arise.
NOT for: general persistent notes or diary entries (use .notes/ directly); managing task lists (use TaskCreate/TaskUpdate tools).
</objective> <inputs>- $ARGUMENTS: required. Three modes:
resume(alias:pending) — list all opensession-open-*.mdmemory files for this project, grouped by age; items ≥ 14 days get⚠ staleprefix; items ≥ 30 days deleted silently before listingarchive <partial-text>— fuzzy-match parked item by name or content, delete memory file, append audit entry to.claude/logs/session-archive.jsonlsummary— compact session digest: completed tasks, parked items, recent git commits since session start; follows output-routing rule (≤10 lines → terminal; longer →.temp/output-session-summary-<date>.md)
- Memory dir: resolved via
resolve_memory_dir.py(canonical; see snippet below) - Canonical MEMORY_DIR snippet (use in every bash block that needs the path):
MEMORY_DIR=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/foundry}/bin/resolve_memory_dir.py" 2>/dev/null) - File pattern:
session-open-*.md - Resolution log:
.claude/logs/session-archive.jsonl - Stale threshold: 14 days (add
⚠ staleprefix when listing) - Delete threshold: 30 days (silently remove before listing)
- Max open items: 10 (surface list and ask to archive before parking new ones)
Task hygiene:
# audit-skip: resilience-replication
_FS=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/foundry}/bin/resolve_shared_path.py" foundry skills/_shared 2>/dev/null || echo "plugins/foundry/skills/_shared") # timeout: 5000
Read $_FS/task-hygiene.md — follow task hygiene protocol.
Step 0: Validate and dispatch mode
Extract first word of $ARGUMENTS as MODE.
If MODE matches:
resumeorpending→ Mode: resumearchive→ Mode: archivesummary→ Mode: summary
Unsupported flag check — after extracting the mode token, scan $ARGUMENTS for any remaining --<token> patterns. If found: print ! Unknown flag(s): \--<token>`. Supported modes: resume, archive, summary.then invokeAskUserQuestion` — (a) Abort (stop, re-invoke correctly) · (b) Continue ignoring (skip unknown flags, proceed with recognized mode).
Otherwise (empty, unrecognized, misspelled): use AskUserQuestion:
"Which session mode did you want?" Options: (a)
resume— list all open parked items, (b)archive <name>— close a parked item by name, (c)summary— compact digest of this session's work
Step 1 / Mode: resume (list pending items)
Substep 1a: Resolve the memory directory
Derive MEMORY_DIR using the canonical snippet defined in <constants> above. Run that snippet here; do not duplicate it. echo "$MEMORY_DIR" to surface the resolved path.
Substep 1b: Age-out expired items (≥ 30 days) silently
# MEMORY_DIR derived in Substep 1a — reuse that value
# Log files before deleting so removals are auditable
find "$MEMORY_DIR" -name "session-open-*.md" -mtime +30 2>/dev/null | while IFS= read -r f; do
echo "Removing aged file: $f"
rm "$f"
done # timeout: 5000
echo "cleanup done"
Substep 1c: Collect remaining items and compute age
Primary source (current): Read .claude/state/session-context.md if it exists. Extract all bullets under ## Parked items section — each is a current parked item. Use item's Raised: date for age computation.
Legacy source (backwards-compat): List session-open-*.md files via Bash (Glob with absolute paths outside project root may return empty on restricted installs — Bash ls is the reliable fallback):
ls "$MEMORY_DIR"/session-open-*.md 2>/dev/null # timeout: 5000
For each file path returned, read with Read tool to extract name and description frontmatter fields and item body. Show legacy items alongside current items in output. If ls returns no files, skip — no legacy items.
Compute age in days per file using session_age_files.py (cross-platform; output is <age>\t<path> per line): <!-- file: session_age_files.py — consumers: foundry:session Substep 1c -->
# MEMORY_DIR derived in Substep 1a — reuse that value
python "${CLAUDE_PLUGIN_ROOT:-plugins/foundry}/bin/session_age_files.py" "$MEMORY_DIR" # timeout: 5000
Substep 1d: Render grouped list
Group by age bucket:
- This session — files modified today (age = 0)
- Earlier (
<date>) — files modified on prior dates, grouped by modification date
Apply ⚠ stale prefix to items with age ≥ 14 days.
Print in this format:
## Session Pending — <today's date>
### This session
- [ ] <item name> — <description>
### Earlier (<YYYY-MM-DD>)
- [ ] ⚠ stale — <item name> — <description>
→ /session archive <slug> to close an item
→ /session summary for a full session digest
If no files exist, print: No pending session items.
End resume mode output with a ## Confidence block per quality-gates.md — score based on: memory sources resolved without error, age computation succeeded, legacy file enumeration returned a result (even empty).
Step 2 / Mode: archive (close a parked item)
Substep 2a: Locate memory directory and list candidates
Derive MEMORY_DIR using canonical snippet from <constants>. Candidates come from two sources:
- Current: bullets under
## Parked itemsin.claude/state/session-context.md(if exists) - Legacy: Glob tool with pattern
session-open-*.mdin MEMORY_DIR
Combine both into a single candidate list for fuzzy matching in Substep 2b.
Substep 2b: Fuzzy-match the target item
Extract <partial-text> from $ARGUMENTS (everything after archive ).
Search candidates from Substep 2a. For session-open-*.md files: Grep with partial text, match against file basenames. For session-context.md bullets: match <partial-text> against the slug or summary text. Select best match — if ambiguous (2+ equally close matches), list them and ask user to disambiguate before proceeding.
Track match source:
# Set these from the match result:
MATCHED_SOURCE="file" # "file" for session-open-*.md, "context" for session-context.md
MATCHED_FILE="<full path>" # only when MATCHED_SOURCE="file"
MATCHED_SLUG="<slug>" # the item's short slug (from bullet or filename)
ITEM_NAME="<name>" # name from frontmatter or slug
Substep 2c: Remove the matched item
If MATCHED_SOURCE="file" (legacy session-open-*.md):
rm "$MATCHED_FILE" # timeout: 5000
echo "deleted"
If MATCHED_SOURCE="context" (bullet in session-context.md):
Use Edit tool to remove the matched bullet line from .claude/state/session-context.md. Remove only the bullet matching MATCHED_SLUG — leave other bullets unchanged.
Substep 2d: Append audit entry to resolution log
Ensure log directory exists:
mkdir -p .claude/logs # timeout: 5000
Append one-line JSON entry atomically with bash redirection, using ITEM_NAME resolved in Substep 2b. Entry format: {"ts":"<ISO8601-UTC>","item":"<name>","action":"archived"}
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
printf '{"ts":"%s","item":"%s","action":"archived"}\n' "$TS" "$ITEM_NAME" >> .claude/logs/session-archive.jsonl # timeout: 5000
Substep 2e: Confirm to user
Print: Archived: $ITEM_NAME (substituting the value resolved in Substep 2b) — one line, terminal only.
End with ## Confidence block per quality-gates.md — score based on match quality (did fuzzy-match find right item; was archive entry written cleanly).
Step 3 / Mode: summary (session digest)
Substep 3a: Collect completed tasks
Call TaskList (or use TaskCreate/TaskUpdate context) to get ta