Chapter 6. Durable Claude Code Memory: What to Write Down and What to Refuse

Write down what changed how the next session must behave and cannot be re-derived from a repo or a live surface. Refuse current state, secrets, self-promoted policy, and undated claims. Durable memory here lives in three homes: a file-per-fact directory, a Google Drive vault, and an Obsidian repo.

A session dies at the end of its thread. The estate does not. I run multiple agent sessions at once, across two computers, against about 50 repos in ~/code, and the machine I am typing on is not the authoritative computer for the Suede repos. Whatever a session learned about a gotcha, a fix, or a decision evaporates unless something writes it down where the next session will look.

The trap is that written memory fails in a worse way than no memory. A blank slate asks questions. A stale note answers them wrong, with confidence. So the memory system starts from a demotion: memory ranks last, below every layer that can be checked live, and it stays useful because it knows its place.

Which layer is authoritative for which claim

Each layer of the estate is authoritative for one kind of claim.

Layer Authoritative for
Git repos Code
Live URLs and APIs Deployed behavior
The current terminal This session, right now
Memory: vault, notes, handoffs Orientation and continuity

The bootstrap instructions state it as policy: the vault is context, not source truth. Current repo files, live services, and current terminal output override old handoffs. The vault is never the source of truth for active code, build artifacts, databases, caches, node_modules, or current deployment state.

This is the same rule that governs deploy verification elsewhere in this book: evidence must come from the layer that owns the claim. A file tree is not the deployed surface; you curl production. A handoff that says the deploy is green tells you the deploy was green when someone wrote the sentence. If the claim matters now, you re-derive it now, from the repo, the URL, or the terminal. Memory tells you where to point the check. It does not substitute for running it.

The three places durable memory lives

Durable memory in this estate has three homes, and they hold different material.

One file per fact, with MEMORY.md as the index

At /Users/jasoncolapietro/.claude/projects/-Users-jasoncolapietro/memory/ sits a directory of markdown files, one file per durable fact, with MEMORY.md on top as an index: one line per file. The filename prefix carries the kind. feedback_ files hold corrections that must change behavior, like feedback_this_machine_is_stale_mirror.md and feedback_suede_app_parallel_sessions.md. reference_ files hold standing facts about the estate, like reference_memory_vault.md. project_ files hold per-product state. Each file records dates as absolutes and carries provenance, including the origin session id, so a claim can be traced to the session that produced it and to that session’s other output.

One file per fact is the load-bearing choice. The index line gives a session the shape of everything known in a single read; the file behind the line holds the detail, the dates, and the evidence. When a fact changes, one file changes. When two facts conflict, both files survive and the conflict stays visible instead of being merged away by whoever wrote last.

The Codex Claude Memory Vault on Google Drive

The Codex Claude Memory Vault lives on Google Drive at /Users/jasoncolapietro/Library/CloudStorage/GoogleDrive-jasoncola1@gmail.com/My Drive/Codex Claude Memory Vault/. It is the shared memory spine across all the agents and both computers: handoffs, decisions, maps, and startup instructions, in numbered directories. A fresh session on Suede work reads 00_START_HERE/00_START_HERE.md, then the vault AGENTS.md, then 06_agents/Agent_Update_Protocol.md, then the relevant project note under 03_projects/, then the newest relevant handoff under 05_handoffs/, then any linked decisions under 04_decisions/. That order runs from orientation toward specifics, and everything it loads is subject to the hierarchy above.

The vault also holds archives, and this is where it earns its disk space. Before the 2026-07-17 prune of my GitHub profile repo, the full pre-prune state (commit 7f79396 plus every intermediate published state) went into the vault at 03_projects/GitHub Profile Archive/2026-07-17/ as three git-archive ZIPs and a full git bundle, SHA-256 checked and git bundle verify checked. “Nothing was destroyed” is a claim, and claims need receipts; hash-verified archives are what make an aggressive prune reversible instead of brave.

The Obsidian vault at ~/code/Suede-Vault

The third home is an Obsidian vault at ~/code/Suede-Vault, remote https://github.com/JasonColapietro/suede-vault-backup.git. When I say “second brain,” “Obsidian,” or “SoT,” all three resolve to this one repo. Its structure runs 00-Inbox/ through _archive/, with 04-Memory/ holding a mirror of the agent memory, 05-Sessions/ holding dated session recaps, and a hand-maintained Index.md on top as the map. Session updates go in a dated file under 05-Sessions/ and get linked from Index.md. On this machine there is no vault-save tooling installed; writes go through Write and Edit plus git add, commit, push, like any other repo.

Calling it the source of truth deserves a caveat the hierarchy already implies: it is the source of truth for the company’s thinking, brand material, and session record. Code, deployments, and live behavior still answer to their own layers.

What earns a file in memory

A fact earns a file when it changed how the next session must behave and cannot be re-derived from any repo or live surface. The memory directory is full of this. Google Drive lazy-loads subdirectories, so a broad scan misses the vault until something addresses the literal path: learned 2026-05-24, when find -maxdepth 3 reported the vault absent while it sat there the whole time. A concurrent session’s branch switch wipes uncommitted edits in a shared checkout: learned 2026-06-10, two edits in, everything gone. cp -Rc clones a node_modules through APFS clonefile() with df staying flat within 0.1GB across a 3.1GB, 1173-entry tree: measured 2026-07-22, during a disk crunch. None of these facts live in any repo. Each cost real time to discover once, and would cost the same again in any session that starts blank.

The entry that captures such a fact has a shape: what happened, with an absolute date; what fixed it; and where the evidence lives. Absolute dates are not pedantry. A note reading “last week” is meaningless to the session that opens it three weeks later, and worse than meaningless to the one that opens it in six months.

Handoff files: naming and required fields

After meaningful work, a handoff goes into 05_handoffs/. The generic naming is YYYY-MM-DD-agent-short-task.md; two agent lineages write into the same directory, so each narrows the pattern to stay distinguishable. Claude handoffs are named YYYY-MM-DD-claude-suede-<short-task>.md, with no -handoff suffix. Codex handoffs are named YYYY-MM-DD-codex-<short-task>-handoff.md. The filename alone tells you which agent wrote it and when, before you open it. When the convention was recorded on 2026-05-24, two prior Claude entries already followed it.

A handoff must contain: target repo or folder, branch and remote, files changed, commands run, verification result, current status, blockers and caveats, and the exact next step. Each field answers a question the next session will otherwise burn time on. Repo, branch, and remote answer “where was this, and on what base,” which matters on a machine where checkouts drift behind GitHub the moment the other computer pushes. Files changed and commands run make the work reproducible and auditable. Verification result draws the line between what was proven and what was assumed; a handoff that says “shipped” without saying how that was checked is a claim, not a record. Blockers and caveats keep the next session from re-discovering the wall I already hit. The exact next step is what separates a handoff from a diary entry: the reader should be able to act within a minute of finishing it.

Writing the handoff is itself an operation with a failure path. Verify before writing: ls the 05_handoffs/ path. If it succeeds, write to the vault. If it returns ENOENT, try once more, because Drive may need the poke to materialize the directory, and then drop to the fallback at /Users/jasoncolapietro/Dropbox/My Mac (Jasons-MBP.hsd1.fl.comcast.net)/Downloads/. Handoffs written to the fallback are meant to be synced into the vault when it returns. The procedure exists because a handoff that fails to write is a session’s worth of context lost without a trace, and the loss is invisible until someone goes looking for a file that was never created.

Two ways a Drive-hosted vault fails to read

The vault sits on a network filesystem with two distinct failure modes, and confusing them wastes time in both directions.

The first is the lazy-load. Subdirectories do not materialize to broad scans until addressed. The fix is to stop searching and start addressing:

ls "$VAULT"   # the literal path, before concluding anything is missing

Absence from a scan is not evidence of absence. That rule looks obvious now; before 2026-05-24 it would have looked like paranoia.

The second surfaced on 2026-06-08 and looks nothing like the first. Directory listings work, because metadata is cached on disk, while file content reads time out with Operation timed out or ETIMEDOUT, because the FUSE mount cannot hydrate bytes without the Drive daemon running. The filesystem is half-alive: structure present, contents unreachable. Network health proves nothing here; ping resolving google does not mean the daemon is up. The check and the fix:

pgrep -f "Google Drive"      # empty means the daemon is down
open -a "Google Drive"       # then wait ~15s and retry reads with backoff

My own notes on this are not clean, and I keep the mess on purpose. The index line for the memory-vault file says reads and writes were verified working without the Drive app installed. The body of the same file says content reads time out when the app or daemon is not running. The distinction may be app-not-installed versus daemon-not-running, but the two statements sit unreconciled in the sources, and the memory records that they sit unreconciled. Resolving a contradiction by guess would convert two honest observations into one confident error.

How memory goes stale without erroring

On 2026-07-23 an audit found the Suede-Vault describing a setup that no longer exists. Two of its own files, 04-Memory/claude-memory/obsidian_vault.md and vault_save_infrastructure.md, still documented the older arrangement: ~/Documents/Suede-Vault, a Suede-AI org remote, and vault-save tooling. A session on 2026-07-05 had superseded all of that on this machine, and nobody updated the two files. The source of truth documented itself wrong for eighteen days.

The same audit found worse. The vault’s mirror of the agent memory, 04-Memory/claude-memory/MEMORY.md, had not refreshed since 2026-07-13, because its source script targets a different machine’s home path: -Users-jason, not -Users-jasoncolapietro. The mirror sat ten days stale and raised zero errors. A mirror wired to a hardcoded path does not fail on the second machine; it succeeds at doing nothing. The global instructions carry a portability clause for exactly this split (/Users/jason on one computer, /Users/jasoncolapietro on this one), and the mirror script ignored it. Multi-machine paths are a failure surface, not a detail, and the failures they produce are the silent kind that only an audit catches.

Both findings feed the same conclusion the hierarchy already encodes. Memory is an artifact like any other artifact. It drifts, it contradicts itself, and it lies by omission, and the only defense is that nothing downstream treats it as more than orientation.

What to refuse

The refusals matter as much as the writes, because everything saved becomes something a future session might trust.

Refuse current state. Anything an authoritative layer owns (code, build artifacts, databases, caches, node_modules, deployment status) does not get copied into memory, because the copy starts aging the moment it lands. Save the pointer and the check instead: which repo, which URL, which command proves the claim.

Refuse secrets. The value of a credential does not enter memory, a handoff, or a commit, in any form. The estate’s own tooling encodes this: the clockout helper pushes all repos but refuses, by design, to auto-commit dirty ones, because uncommitted work may contain secrets or WIP. The memory about frontend/.env.local in Suede-AI-App is the model: it records that the file exists, is gitignored, is required for dev, and must be hand-copied into each new worktree. Existence and location are durable facts. Contents are not memory’s business.

Refuse self-promoted policy. Durable project decisions go under 04_decisions/ only when I confirm they are stable rules. An agent may record what happened on its own authority; it may not promote its own conclusion into standing policy. Without that gate, every session’s working theory would calcify into a rule the next session obeys, and the decisions directory would fill with policies nobody decided.

Refuse undated and unverified claims. Entries get absolute dates, and a status without the method that checked it is an assumption. If the write cannot say how the claim was verified, the claim goes in labeled as unchecked or it does not go in.

The cold-start test

The test of all of this is a cold start. A fresh session, on either machine, reads the bootstrap chain: 00_START_HERE, the vault AGENTS.md, the update protocol, the project note, the newest handoff, the linked decisions. Minutes later it knows the repo, the branch the last session left, what was verified, what blocked, and the exact next step. Then it opens a terminal, fetches, checks the live URL, and lets the present overrule anything that disagreed. Memory got it to the right question fast. The current state of the world answers it.