/mf:dump — session → project memory
Write the current session's non-derivable state to the project's auto-memory directory so a future session can resume cleanly. Idempotent: can run mid-session, at a natural checkpoint, or at end-of-session.
Important
- Never proliferate files. Update existing memory first; create new files only when a topic genuinely deserves its own dossier.
- Only log non-derivable signal. Facts recoverable from
git log, current code, orAGENTS.md/PROJECT.mddo not belong in memory. - SOUL.md and the user-global AGENTS.md are sacred. Propose edits, never apply silently, and only when the insight is genuinely general. The user-global AGENTS.md lives at
~/.mindfunnel/AGENTS.md(reached via~/.claude/CLAUDE.md); the per-project./AGENTS.mdis a small project-scoped stub owned by the project — don't treat them as the same file. - Convert every "today" / "tomorrow" to an absolute date before writing. Run
date -Iif uncertain. - Append atomic assertions to the ledger, don't narrate them. Claims, decisions, and learnings that carry a trust level and provenance go to
ledger.jsonl(Step 5b); the narrative stays in Markdown. Never double-log one as the other — cross-reference.
Instructions
Step 1: Locate the memory directory
Claude Code's auto-memory system lives at ~/.claude/projects/<slug>/memory/ where <slug> is the project's absolute path with every / replaced by -.
bash -c 'echo ~/.claude/projects/$(echo "$PWD" | sed "s|/|-|g")/memory'
The directory is usually already created by Claude Code. If not, create it before writing.
Step 2: Verify the project is primed
Confirm AGENTS.md and PROJECT.md exist in the project root (these are set up by /mf:prime; under 0.3.0+ they're real committed files, under older versions they may be symlinks — either counts). If either is missing:
- Flag it and offer to run
/mf:primefrom the project root. - Do not run
/mf:primesilently — pre-existing files with the same name matter. - Proceed with the dump anyway, noting the priming gap in the final report.
Step 3: Survey existing memory
Read <memory_dir>/MEMORY.md (the index) and the most recently modified files:
ls -lt <memory_dir>/*.md 2>/dev/null | head -10
Decide for each signal you want to log: does it belong in an existing file (preferred) or a new file (rare)?
Step 4: Extract signal from the conversation
Identify, in priority order:
- Results + numbers — experiment outcomes, benchmarks, sweep tables. Always keep the actual numbers, never just "it worked".
- Decisions + rationale — especially tradeoffs. The why is more durable than the what.
- Load-bearing code changes — structural shifts, new entry points, architectural moves. Not trivial edits.
- Open threads — pending experiments, unresolved questions, "run this next" commands.
- Surprises and corrections — failed hypotheses, midcourse reversals, negative results.
Skip anything derivable from git log, the current code, or the primed config files.
Step 5: Write using the auto-memory type taxonomy
Every memory file has YAML frontmatter with name, description, type. The four types:
project— ongoing work state, results, decisions, deadlines, pending experiments. High churn.feedback— behavioural guidance (both corrections and validated choices). Each entry: rule + Why: + How to apply:. Moderate churn.user— durable facts about the user's role, expertise, responsibilities. Low churn.reference— pointers to external systems (issue trackers, experiment trackers, dashboards, buckets). Low churn.
Filename convention: <type>_<topic>.md (e.g. project_state.md, results_full_sweep.md, feedback_offline_vs_online.md, reference_wandb.md).
Step 5b: Append atomic entries to the ledger
Alongside the narrative Markdown, append atomic claims / decisions / learnings to the append-only ledger. This is where trust and provenance live, so a future session can tell a measured result from an inferred guess — and check whether it has since gone stale.
The full schema, trust ladder, and semantics are in references/ledger.md — read it if you have not this session. In short, each line is one JSON object:
{
"id": "<unique>",
"ts": "<ISO-8601 UTC>",
"kind": "claim|decision|learning",
"status": "guaranteed|observed|given|user-inferred|agent-inferred|opinion",
"text": "<one sentence>",
"sources": ["<path>", "<path@sha>", "<run-id>"],
"supersedes": "<id?>",
"key": "<optional>"
}
Rules:
- Append only. Never rewrite or delete a line. To revise, append a new entry whose
supersedesnames the oldid. - Pick the honest trust rung.
guaranteed>observed>given>user-inferred>agent-inferred;opinionfor a taste call with no truth claim. Do not inflate an inference toobserved. - Record provenance. Put the grounding paths (commit-pinned as
path@<sha>when the claim is tied to specific code), run-ids, or URLs insources. Omit for a bare preference. - Ledger-worthy only. One-sentence assertions that carry trust or provenance — a benchmark number, a settled decision, a durable gotcha. Prose state stays in Markdown; do not double-log.
Append with a shell heredoc (the memory dir is the same <slug> path as the Markdown files; timestamp via date -u +%Y-%m-%dT%H:%M:%SZ):
LEDGER=~/.claude/projects/$(echo "$PWD" | sed "s|/|-|g")/memory/ledger.jsonl
cat >> "$LEDGER" <<'JSON'
{"id":"20260101-1","ts":"2026-01-01T00:00:00Z","kind":"claim","status":"observed","text":"...","sources":["..."]}
JSON
If there are no atomic assertions worth pinning this dump, skip — the ledger is not a log of everything.
Step 6: Refresh the index
Update <memory_dir>/MEMORY.md with one line per entry:
- [Title](file.md) — one-line hook, under ~150 characters.
MEMORY.md has no frontmatter — it's an index, not a memory. For any file you updated or created, re-word its hook if the content shifted substantively.
Step 7: Cross-check, then write
Before writing: for any file you're about to modify, read it first to preserve load-bearing context. Duplication is a smell — if the same fact appears in two files, pick one canonical home and cross-reference.
Step 8: (Rare) Propose user-global SOUL.md / AGENTS.md / USER.md edits
If the session surfaced a general guideline or preference worth propagating to every future session on any project, propose an edit to one of the user-global files:
~/.mindfunnel/SOUL.md— user traits, collaboration style, communication preferences.~/.mindfunnel/AGENTS.md— general, agent-neutral engineering guidelines. This is the maintainer's user-global AGENTS.md, auto-loaded via~/.claude/CLAUDE.mdand~/.codex/instructions.md. It is not the per-project./AGENTS.md(which is a small project-scoped stub owned by the project).~/.mindfunnel/USER.md— per-machine user preferences: shell, Python defaults, formatter paths, multi-agent hook bridges.
Guardrails:
- Propose, never apply silently. Show the proposed passage, explain why it's general, wait for explicit approval, then apply.
- Budget: 0 proposals in the common case, 1 every 5–10 dumps at most.
- Three conditions must all hold: genuinely general (applies to any project), stable (not contradicted elsewhere), actionable (a concrete rule, not a vibe).
- Write to
~/.mindfunnel/directly — never to the per-project./AGENTS.mdor to the symlink aliases (~/.claude/CLAUDE.md,~/.codex/instructions.md). The user-global content has one canonical home. - Pick the right file. Agent-neutral engineering style → AGENTS.md. Personal style / who the user is → SOUL.md. Machine-specific tooling → USER.md.
If in doubt, skip. User-global file churn creates noise.
Step 9: Report
End with a concise summary, ≤ 15 lines:
Memory dir: <path>
Updated:
- <file> — <one-line reason>
Created:
- <file> — <one-line reason>
Index (MEMORY.md): refreshed | unchanged
Ledger (ledger.jsonl): +N entries | unchanged
Proposed SOUL.md / AGENTS.md / USER.md edits: none | <one-line summary, pending approval>
If nothing was worth logging, say "no new signal; memory is current" and do nothing.
Examples
Example 1: Mid-sweep checkpoint after a production run
User says: "Log everything, the sweep results just came in."
Actions:
- Compute memory dir via the sed snippet; confirm
MEMORY.mdexists; read it. - Read the most recent
project_state.mdandresults_*.mdfiles. - From the conversation, extract: sweep numbers (per-seed, aggregate), the decision made ("v3 recipe wins cleanly"), any flagged concerns.
- Update
project_state.mdwith the new "where we are + next action". - Create
results_<experiment>_<date>.mdif the sweep is a major dossier; otherwise append to an existing results file. - Refresh
MEMORY.mdone-liner for each touched file. - No SOUL.md / AGENTS.md / USER.md proposals.
Result: One report block listing what was updated, memory ready for the next session.
Example 2: End-of-session cleanup with no new findings
User says: "Dump before I close."
Actions:
- Scan the conversation for signal. Finds: only tool invocations and small Q&A, no new results or decisions.
- Skip the dump entirely.
- Report: "no new signal since the last dump; memory is current."
Example 3: General guideline surfaces, worth a user-global AGENTS.md proposal
User says: "Log everything. That lesson about always verifying memory claims before citing them is something I want to keep."
Actions:
- Update
project_state.mdand anyresults_*.mdas usual. - Draft a one-paragraph addition to
~/.mindfunnel/AGENTS.mdunder "Handling Existing Code" or "Autonomy and Asking". - Show the proposed diff to the user.
- Wait for approval. Do not apply.
- On approval: apply the edit, confirm, and note it in the dump report.
Troubleshooting
Error: Memory directory path seems wrong
Symptom: Files land at an unexpected location, or Claude Code complains about an unknown memory dir.
Cause: The slug transformation doesn't match Claude Code's internal convention on this host.
Solution: Check with ls ~/.claude/projects/ — the current project's dir should appear. If absent, Claude Code hasn't indexed this project yet; create the dir manually with mkdir -p ~/.claude/projects/<slug>/memory and Claude Code will adopt it.
Error: Conflicting facts between memory files
Symptom: Two memory files disagree on a number or decision.
Cause: A previous dump duplicated content instead of cross-referencing.
Solution: Pick the newer or more specific statement as canonical. Edit the other file to cross-reference the canonical one (See [results_foo.md](results_foo.md) for current numbers.). Note the consolidation in the final dump report.
Error: Memory churn — dumping too often with too little signal
Symptom: git log of the memory dir shows many small updates, many of them trivial.
Cause: The empty-dump guard is being skipped.
Solution: Skip the dump when the conversation contains only tool noise / small Q&A. Say "no new signal; memory is current" and do nothing. Memory is not a commit log.
Error: Proposed a SOUL.md / AGENTS.md / USER.md edit that was rejected
Symptom: The user said "no" to a proposed general-guideline edit.
Cause: The insight wasn't actually general, or was contradicted by other contexts.
Solution: Accept the rejection, do not re-propose in the same session, and move the insight into a project-level feedback_*.md instead if it's still useful at the project scope.
Anti-patterns
- Don't dump verbatim tool output — summarise signal, cite key numbers only.
- Don't log bug-fix recipes — the fix is in the code, its context is in the commit. Log why the bug existed if non-obvious.
- Don't overwrite existing content without reading first.
- Don't propose SOUL.md / AGENTS.md / USER.md edits routinely. Once every few dumps at most, or if really needed.
- Don't create a new file when an existing one can absorb the update.
- Don't list every tool call you made — memory is for signal, not process.
- Don't re-run experiments or verify against current code — that's spinup's job. Dump is mostly write.
- Don't include ephemeral task details (current conversation turn, in-progress tool output) — those live in the conversation.
- Don't create TODO lists in memory. Pending actions belong in
project_state.mdunder a "Next actions" section, tied to a concrete command or decision.