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 missingAbsence 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 backoffMy 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.