DEV Community

Cover image for Why AI Coding Agents Keep Redoing Each Other's Work: Markdown Memory vs Real Memory in Cursor and Claude Code
iCe Gaming
iCe Gaming

Posted on

Why AI Coding Agents Keep Redoing Each Other's Work: Markdown Memory vs Real Memory in Cursor and Claude Code

On Thursday my agent spent forty minutes fixing a bug my teammate's agent had already fixed on Monday.
Both agents had "memory". Neither of them had a clue.

TL;DR

  • Markdown decisions in git, an always loaded index, vector search and good commit messages are a real memory layer. For one person on a small repo, they work.
  • On a team with several agents, they recall what someone wrote down. They don't know what actually happened: failed attempts, stale decisions, what another agent did this morning.
  • That gap is the difference between Alexa and ChatGPT. One answers from a list. The other understands the conversation.
  • Below: the DIY setup I keep seeing, six places it breaks, a comparison table, and what a memory layer needs to fix it.

The DIY setup I keep seeing

Every few weeks I talk to a team that has built its own agent memory. It's usually smart, and it usually looks something like this:

  • A CLAUDE.md or AGENTS.md at the root, always loaded into context.
  • A decisions/ folder with one markdown file per decision, plus an index.md the agent reads first.
  • Vector search over those files, so the agent can pull "relevant" notes.
  • A rule that the why of every change goes into the commit message.
  • Sometimes more: an orchestrator that runs agents in tmux sessions, a per developer Docker image, a little MCP mailbox so agents can message each other, a work board with advisory locks so two agents don't grab the same task.

I respect this a lot. It's real engineering, and it shows the team gets the problem: an agent without memory is a very fast intern with amnesia.

But when I look closely, almost every one of these setups is the same thing underneath. It's a notebook the agent can read. And a notebook only knows what somebody remembered to write in it.

Here's the framing that finally made it click for me.

Alexa vs ChatGPT

Split screen: on the left a voice speaker answering from pinned notes, on the right an AI connected to code, commits, timelines, teammates and failed attempts

Ask Alexa "what's on my shopping list?" and you get exactly what you added. Nothing more. If you forgot to add milk, Alexa doesn't know you're out of milk.

Ask ChatGPT a question in the middle of a long conversation and it answers from everything that happened: what you tried, what you rejected, what you said three turns ago that contradicts what you're saying now.

DIY markdown memory is Alexa. It recalls the list.

What teams actually need from agent memory is closer to ChatGPT: something that knows why a fix landed where it did, what was tried first, and what a teammate's agent already did this week.

A notebook remembers what you wrote. A memory remembers what happened.

Where markdown memory works fine (honestly)

I want to be fair here, because this isn't a "your setup is bad" post.

Markdown in git is a perfectly reasonable place to start if:

  • You're solo. You are the only writer, so the notes match your head.
  • The repo is small. The whole decision log fits in context, so retrieval barely matters.
  • Decisions change rarely. A note written in March is still true in October.
  • You use one agent. There is no "other agent" whose work you need to know about.

In that world, an AGENTS.md with your conventions plus a handful of decision files gets you a long way. Keep it. Version it. It's cheap and it's yours.

The problems start when any of those four conditions stop being true. On a team running Cursor, Claude Code and Codex in parallel, usually all four go at once.

Six places DIY agent memory breaks

1. Failed attempts are never recorded

This is the big one, and it's the scene from the top of the post.

Monday: Alice's agent hits a flaky test in the payment webhook. It tries a retry wrapper (makes it worse), then a longer timeout (hides it), then finds the real cause: the test fixture shares a database connection across workers. It fixes the fixture. The commit says fix: isolate webhook fixture connection.

Thursday: Bob's agent sees a different flaky test in the same area. It searches the decision log. Nothing about webhooks. It reads the commit history and finds Alice's message, but the message doesn't say "and by the way, retries and timeouts are traps here". So Bob's agent tries a retry wrapper. Then a longer timeout.

Two robot agents at separate desks, fixing the identical bug days apart, with an ignored sticky note on the floor between them

Nobody writes down the three things that didn't work. Commit messages describe the diff that shipped, not the dead ends. Decision files describe the decision, not the forty minutes before it. And the dead ends are exactly what the next agent needs.

2. Nobody writes the why (consistently)

"Put the why in the commit message" is a great rule. It holds for about two weeks.

Then there's a hotfix at 23:00, an agent squash merges a branch with a generated summary, someone rebases. The why is now spread across a PR thread, a chat message and somebody's memory. The agent can only read the parts that made it into git, and those are the parts least likely to contain reasoning.

Any memory that depends on humans remembering to write things down will decay at the speed of the busiest week.

3. Notes go stale and nothing notices

decisions/0007-use-redis-for-queue.md was true in spring. In summer the team moved the queue to Postgres. Somebody updated the code. Nobody updated 0007.

Now the always loaded index still points at it, vector search happily returns it (it is very relevant to "how does our queue work?"), and the agent confidently writes Redis code. Markdown files have no concept of "this used to be true". There is no expiry, no "superseded by", unless a human adds it by hand.

4. Contradictions pile up silently

Related but worse: two files that both look current.

AGENTS.md says "never use ORMs in the reporting service". A decision file from a later sprint says "use the shared ORM layer everywhere for consistency". Both get loaded. The agent picks one, or worse, blends them. Nothing in a folder of markdown will flag that these two disagree.

5. Retrieval by keyword is not retrieval by meaning

Even with vector search on top, the DIY version usually indexes your notes, not the work. If the decision file says "connection pooling" and the developer asks "why does the worker hang after deploy?", you're hoping the embedding gap closes on its own.

And because the index is the always loaded file, it grows. Teams either let it bloat (eating context on every prompt) or prune it (and lose things). Neither is retrieval. It's a table of contents.

6. Context doesn't cross agents or teammates

This is the part the fancy DIY setups try hardest to solve, with mailboxes and work boards and locks. Those coordinate who is doing what right now. That's useful. But coordination is not memory.

When Carol's Codex session finishes tomorrow, what does it leave behind for Alice's Cursor session next week? Usually: a commit, maybe a markdown note if the agent was told to write one. The session's actual context (what it read, what it ruled out, what it learned about this part of the codebase) is gone the moment the terminal closes.

The comparison

Diagram: DIY markdown memory on the left, where agents read repo files and failed attempts and stale notes never make it in; Palace on the right, where Cursor, Claude Code and Codex share hooks, hybrid search, a knowledge graph and a team server

DIY markdown memory in git A real memory layer (Palace)
What gets stored What someone chose to write down Verbatim chunks of code, notes, session diaries and facts as work happens
Failed attempts Almost never A stop hook asks the agent to write a diary entry, dead ends included
When recall happens When the agent reads the index or decides to search Automatically, via hooks at session start, on each prompt, and while the agent reads files
Search Grep, or vector search over your notes Hybrid BM25 plus cosine over local embeddings, with intent detection
"This used to be true" Only if a human edits the file Time stamped facts that can be marked no longer true
Contradictions Silent A tool to find stale or contradictory facts
Provenance You trust the file Each hit cites wing, room, source file, drawer and score
Across tools Separate files per tool (CLAUDE.md, AGENTS.md, rules) One memory over MCP for Cursor, Claude Code, Codex and other MCP clients
Across teammates Only via git, after a merge Shared Palace Server, so one agent's memory is recallable by another's
Best fit Solo dev, small repo, one agent Teams, multiple agents, long lived codebases

What a memory layer actually needs

If you want to build this yourself (and some of you will, which is great), here's the checklist I'd use. It's the list I ended up with after watching DIY setups break:

  1. Capture without discipline. The agent should write a session note when it did real work, without a human remembering to ask. Dead ends included.
  2. Recall without asking. Relevant memory should show up before the agent answers, not only when it thinks to search.
  3. Facts with time. "We use X" needs a "since" and a way to say "not anymore".
  4. Conflict detection. Something has to notice that two things you believe disagree.
  5. Hybrid retrieval with sources. Keyword and meaning together, and every answer says where it came from so you can check it.
  6. One store, many agents. Cursor, Claude Code and Codex should read and write the same memory, over a standard protocol, without copying files around.
  7. Shared across the team, on your own infra. Memory that lives on one laptop dies on one laptop.

Coordination tells agents who's working on what. Memory tells them what already happened. You need both.

How Palace does it

Full disclosure: I build Palace, so this is the part where I show what I did with that checklist. Everything below is in the open source core, palace-rs, unless I say it's the team server.

Install (macOS Apple Silicon or Linux via Homebrew; the README has a script for Windows too):

brew tap AncientiCe/palace && brew install palace
palace install   # connects every supported agent on this machine
palace doctor    # checks every client is wired up
palace init ~/my-project --yes --auto-mine
Enter fullscreen mode Exit fullscreen mode

It's one binary and one local SQLite file, with local embeddings and no API keys. Then, mapped to the list above:

  • Capture. A stop hook notices when a session did real work but saved nothing, and asks the agent to write a diary entry and record decisions before it finishes. That's where "tried retries, tried timeouts, real cause was the shared fixture" ends up.
  • Recall. Hooks inject memory at session start (your standing rules, recent diary entries for this project from any agent, top drawers), on prompt submit (search with your actual question), and while the agent greps and reads files.
  • Facts with time. A knowledge graph of time stamped facts, like my_api → uses_queue → Postgres, with palace_kg_invalidate to mark a fact as no longer true and palace_kg_timeline to see the order things changed.
  • Conflicts. palace_conflicts finds stale or contradictory facts.
  • Retrieval. BM25 plus cosine similarity over local embeddings, with query intent classification (decision, how to, preference and so on). Results carry score provenance and the source they came from.
  • Many agents. It's an MCP server, so Cursor, Claude Code, Codex, Claude Desktop and other MCP clients share the same memory.

For teams, there's Palace Server, the commercial self hosted edition. Each developer points their local CLI at it and nothing else in their agent config changes:

palace remote set --endpoint https://palace.yourco.com
palace remote on
palace remote test
Enter fullscreen mode Exit fullscreen mode

It runs on your infrastructure (Docker Compose or a single binary, Postgres with pgvector, embeddings computed locally), so your project's memory doesn't leave your network. When Alice's agent files something, Bob's agent can recall it.

Back to Thursday: with shared memory, Bob's agent starts the session, gets Alice's diary entry from Monday injected for that project, and the first thing it reads is "retries and timeouts hide this; check fixture connection sharing." Forty minutes becomes four.

The honest bottom line

DIY markdown memory isn't wrong. It's a good first step, and the teams who build it are usually the ones who understand agents best.

But it's a notebook. It recalls what you wrote down, when you remembered to write it, until it goes stale. That's Alexa.

A team with several agents needs memory that captures the work as it happens, notices when facts change, and carries context from one teammate's agent to another's. That's ChatGPT.

There's one stat I keep coming back to: in the 2025 Stack Overflow Developer Survey, the top frustration with AI tools, cited by 66% of developers, was "AI solutions that are almost right, but not quite" (source). A lot of "almost right" is an agent that is missing context someone already had.

If you want to try the solo version, it takes a couple of minutes: brew tap AncientiCe/palace && brew install palace, then palace install. The repo is github.com/AncientiCe/palace-rs, and a star helps more than you'd think.


Your turn: what's the worst "my agent redid something we already solved" moment you've had? And if you've built your own memory setup, what's the one thing it still doesn't catch? I read every comment.

Top comments (1)

Collapse
 
maxmartella profile image
Massimiliano Martella •

That Thursday example is interesting... if the monday fix was already in git (and also the commit message had the why) the other agent had something to read and still ... spent forty minutes. If it only existed inside the first agent’s session... then the markdown layer never saw it. which one was it?