{"slug": "inverting-claude-code", "title": "Inverting Claude Code", "summary": "A user running Claude Code inside an Obsidian vault reveals that Anthropic's memory system, designed as a cache for code repositories, fails as a persistent boot sector for personal notes, causing behavioral regressions when memory lines exceed the 200-line load limit. The user implemented a hook to block memory writes after the model repeatedly logged corrective feedback without preventing rule violations, such as intermittently using em dashes despite a stored rule against them.", "body_md": "# Inverting Claude Code\n\nI asked Claude Code to remind me about something the next day. One line, a throwaway request. The model reached for its memory system and started to write a new memory file plus an index entry, and a hook I keep on memory writes blocked it. The reminder ended up on my Kanban board instead, where it belongs. That beat is the whole architecture in miniature: the model wanted to append, the guard asked whether the fact deserved to exist as memory, and the answer was no.\n\nWhy there is a hook standing between an AI assistant and its own memory takes some explanation.\n\nClaude Code is a coding agent. You open it in a git repository, it reads the code, it does the work, and its auto-memory is scoped to that repository. The documentation’s examples of what belongs in memory are things like build commands, code style preferences, debugging insights, “the API tests require a local Redis instance.” Every one of them shares a property that does all the work in the design: it can be rediscovered from the code repository.\n\nThis is why the memory system’s one safeguard is so thin: at session start, Claude Code loads the first 200 lines or the first 25 KB of the memory index file, MEMORY.md, whichever comes first, and silently drops the rest. There is no write cap. Nothing stops the file from growing; growth just stops mattering, because line 201 never gets loaded. Under the intended use this is defensible. If a fact falls off the end, the model re-derives a build command once and writes it down again. Memory is a cache over facts the repository can regenerate. The repo carries its own continuity, and this memory file is just convenience residue.\n\nBut I run it backwards. One working directory, session after session, and the directory is not a codebase; it’s an Obsidian vault. Notes, decision records, audit logs, interaction rules, custom tool evolution, a Kanban board. The vault is the repo-for-a-life. Obsidian is the human interface, Claude Code is the resident process inside it, and memory holds exactly the things no fresh session can re-derive from the filesystem: who I am, the standing rules for how the agent should behave, and the security walls around things that must never be publicly connected to each other.\n\nUnder its intended use, a never-loaded memory line is a cache miss. Under my setup it’s a behavioral regression with consequences. Nothing visibly breaks at line 201; the agent just wakes up one morning not knowing a rule it knew yesterday, and I find out only when the rule gets broken.\n\nEvery wall I hit making this work traces back to one mismatch: cache semantics applied to what I was treating as a boot sector.\n\nAppend pressure showed itself first. Anthropic’s stock memory instructions tell the model to write a memory file and add an index line every time it judges something worth saving, and there is no triage step, no moment where anything asks whether a fact is durable or a one-shot errand. It tries to write universal rules for minor corrections, or one-off instructions. In a code repository that is survivable; the pool of memory-worthy facts is bounded by the codebase. When the agent is a persistent assistant, every task looks “ongoing” and everything looks memory-worthy. Each append is reasonable in isolation but the overall failure is cumulative.\n\nMy index grew monotonically, and most of the damn thing was correctives: feedback memories logged after the model broke a rule. Which would be fine if writing the memory prevented the next failure. It doesn’t. A memory is the weakest form of enforcement there is, a note the model reads at session start and may or may not obey. I don’t use em dashes in my writing; I told the model I didn’t like them, it agreed, it wrote the rule to memory, and it kept producing them all over the place, anyway. Not every time. Intermittently, which is worse. What fixed it was a hook that strips them mechanically, and the memory became decoration.\n\nSo in late May I adopted a triage policy for every correction. If the rule is deterministic (a forbidden string, a command shape, a protected path, a required pre-step), build a hook and skip the memory. If it needs judgment (tone, prose voice, design taste, when to ask), memory is the right place; that is the core of it. And if the action is irreversible (delete, overwrite, commit, send), a hard gate, never a reminder alone. The default is to build the guard. That one pass shrank the index from about 25 KB to 18.6 KB, but the size was the lesser win. The point was decoupling memory growth from failure count. A guard removes a failure class whether or not the model is having a good day.\n\nAs an analog in the real world, I saw this in a past team I managed. Every Scrum sprint, things that didn’t work well turned into corrective “team agreements.” On the surface these seemed like a good idea, until I read the team agreements document. It was huge! There was no way each of those could be followed for every task a programmer was doing. It required a serious revisit to not bog down the team with 300-odd directives, much like in [RoboCop 2](https://en.wikipedia.org/wiki/RoboCop_2).\n\nIn my new guard model, triage bounded the growth, but the ceiling it was protecting against didn’t move. 200 lines or 25 KB is a hard, system-enforced load boundary, straight from Anthropic’s official docs, and if you exceed it there is nothing but silence. So the index got partitioned. What loads every session is now a pinned floor: identity, the standing behavioral rules, the security walls, and a compact registry of trigger phrases, 77 lines and 8 KB after the aggressive audit and split, kept deliberately small and stable. Everything else was demoted to an on-demand file consulted when a task calls for it. And then I put a hard block on the write path: any edit that would push the index past the cap gets hard rejected.\n\nI had declined that block ten days earlier as too blunt. Then the bloat reflex fired twice in one day, with the soft warning sitting right there in the model’s context. Come on. The reminder-only guard went into the trash and the hard block shipped.\n\nThe most pressing problem had nothing to do with MEMORY.md’s file size. Clearing a session wipes episodic memory, the arc of the work: which threads were open, what was decided yesterday and why. It was like I was dealing with an Alzheimer’s intern. The facts survive in the index; the thread is just gone, and every fresh session opened requiring an extensive re-briefing. Growing the index was blocked by the cap, and would have been wrong anyway. Identity and rules belong always-loaded. “This write-up started on Tuesday” does not.\n\nSo episodic memory became its own thing. A local SQLite store holds episodic, project, and interest memories, never loaded wholesale. A session-start hook queries it and injects a small salience-ranked working set into each new session, which matters twice over: a hook fires deterministically instead of depending on model initiative, and its output rides outside the memory cap, so continuity never competes with the rules for budget. And a nightly job consolidates: it merges duplicates, decays what stopped mattering, promotes what came up again, and snapshots before it acts so it can be rolled back when it does something dumb. It runs while I sleep. I called it the dream, because that’s what it is; the day’s episodes get replayed and the useful ones get kept, much like how our brains work.\n\nHere is the part that prompted this essay. On July 10 I went through Anthropic’s current docs, and their product team is moving toward this setup faster than I expected.\n\nThe official memory documentation now states that memory is “context, not enforced configuration,” and directs anyone with a rule that must hold to a PreToolUse hook. That is the position the em-dash fiasco forced on me, now printed as official guidance. Anthropic’s Managed Agents platform ships memory stores with the governance my hand-rolled setup already has: immutable versioning with an audit trail, redaction of historical versions, per-store caps, read-only mounts for shared reference stores. And they now ship [Dreams](https://platform.claude.com/docs/en/managed-agents/dreams) ([archived](https://perma.cc/CKG6-N67B)), a research-preview API being offered to enterprise customers: an asynchronous job that reads a memory store plus up to 100 past session transcripts and produces a new, reorganized store, duplicates merged, contradictions resolved in favor of the latest value, with the input left untouched so the output can be reviewed or discarded. The same design as the thing running on my Mac at night. Down to the name.\n\nI don’t think anyone at Anthropic looked at a hobbyist’s vault. Two builders hitting the same design without contact means the constraints did the designing: given an agent that accumulates memory for months, offline consolidation with a reviewable output is where you end up. Judging what to keep at write time means trusting the model in the moment it writes, with nobody checking. Consolidating later, the way a dream does, produces a rewritten store you can read and reject before it replaces the old one. That is the same reasoning that put my consolidation at night instead of in the session.\n\nWhat Anthropic still has not shipped, anywhere, is the hook that stands between my assistant and its own memory. Nothing in the product or the platform does write-time triage; nothing asks at save time whether a fact deserves to be memory at all. The GitHub issues requesting automatic pruning and layered memory ([#37102](https://github.com/anthropics/claude-code/issues/37102), [#27298](https://github.com/anthropics/claude-code/issues/27298), [#34776](https://github.com/anthropics/claude-code/issues/34776)) never drew maintainer commitment, and a housekeeping bot has since closed all three as “not planned.” And the governance that did ship is enterprise-side only. Persistent-assistant memory is a Managed Agents platform feature; an individual running Claude Code at home still gets the 200-line cache and hand-editing as the documented remedy.\n\nPast Claude Code, I’d generalize it this way: any always-loaded file that a model can append to drifts toward a junk drawer. The model isn’t bad at deciding what matters. Every append looks reasonable at the moment of writing, and the failure comes to light when viewed in aggregate, where no single decision can see it. So build the defense where no single decision can dodge it: a cap enforced on the write path, curation that runs on a schedule rather than on remembering, and a bare-minimum floor for things that must not decay.\n\nAnd if you take a tool and invert its intended use, expect to build the missing governance parts yourself. The vendor’s assumptions sit deeper than the feature list; you’ll find them one behavioral regression at a time. Budget for it, keep notes, and expect the vendor to ship your workarounds as features about a quarter after you write them.\n\nMeanwhile my setup just runs. The floor stays small, the guard keeps saying no to bloat, and the dream sorts every day out while I sleep.", "url": "https://wpnews.pro/news/inverting-claude-code", "canonical_source": "https://caffeinatedcode.com/posts/inverting-claude-code/", "published_at": "2026-07-11 00:00:00+00:00", "updated_at": "2026-07-22 17:12:19.746372+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "large-language-models"], "entities": ["Claude Code", "Anthropic", "Obsidian"], "alternates": {"html": "https://wpnews.pro/news/inverting-claude-code", "markdown": "https://wpnews.pro/news/inverting-claude-code.md", "text": "https://wpnews.pro/news/inverting-claude-code.txt", "jsonld": "https://wpnews.pro/news/inverting-claude-code.jsonld"}}