<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Elvis Mørales Fdz</title>
    <description>The latest articles on DEV Community by Elvis Mørales Fdz (@n3rdh4ck3r).</description>
    <link>https://dev.to/n3rdh4ck3r</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F87602%2F20a6c8ee-f4b0-4d57-87b4-1a52511f23d4.jpeg</url>
      <title>DEV Community: Elvis Mørales Fdz</title>
      <link>https://dev.to/n3rdh4ck3r</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/n3rdh4ck3r"/>
    <language>en</language>
    <item>
      <title>How to give Claude Code persistent memory with a self-hosted mem0 MCP server</title>
      <dc:creator>Elvis Mørales Fdz</dc:creator>
      <pubDate>Thu, 19 Feb 2026 01:06:11 +0000</pubDate>
      <link>https://dev.to/n3rdh4ck3r/how-to-give-claude-code-persistent-memory-with-a-self-hosted-mem0-mcp-server-h68</link>
      <guid>https://dev.to/n3rdh4ck3r/how-to-give-claude-code-persistent-memory-with-a-self-hosted-mem0-mcp-server-h68</guid>
      <description>&lt;p&gt;Last week I spent two hours with Claude Code debugging a token refresh race condition. I traced it through the auth middleware, tested four approaches, and finally found that the session timeout window overlaps with the token refresh cycle on my setup. Three-line fix. The next day, a similar auth timing issue appeared in a different service. Claude suggested some of the exact approaches we'd already tried and rejected the day before.&lt;/p&gt;

&lt;p&gt;That's the kind of knowledge that falls through the cracks between &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; sessions. Yes, &lt;code&gt;CLAUDE.md&lt;/code&gt; stores static rules and Auto Memory saves compressed summaries. But neither captures the full diagnostic path, which approaches you tried, why three of them failed, and the specific conditions that made the fourth one work. That detail disappears when the session ends.&lt;/p&gt;

&lt;p&gt;I went looking for MCP memory servers and other solutions that could fill that gap. Most either depended on running in the cloud, gave me too little control over the local setup, or required adding a separate API key for their internal LLM operations. Claude Code already authenticates through an OAuth Access Token (OAT), and the SDK supports it, so adding another key felt redundant and came with extra API costs.&lt;/p&gt;

&lt;p&gt;During that search I came across &lt;a href="https://github.com/mem0ai/mem0" rel="noopener noreferrer"&gt;mem0&lt;/a&gt;. I went through their documentation, tried the &lt;a href="https://docs.mem0.ai/integrations/openclaw" rel="noopener noreferrer"&gt;OpenClaw plugin&lt;/a&gt; to see how the library handles memory extraction and semantic search, and liked the approach. I patched it to reuse Claude Code's existing OAT token instead of requiring a separate key and &lt;a href="https://github.com/mem0ai/mem0/pull/4035" rel="noopener noreferrer"&gt;submitted the change upstream&lt;/a&gt;. Their official &lt;a href="https://docs.mem0.ai/platform/features/mcp-integration" rel="noopener noreferrer"&gt;MCP integration server&lt;/a&gt; is cloud-only though, so I built &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted" rel="noopener noreferrer"&gt;mem0-mcp-selfhosted&lt;/a&gt;, a local version backed by infrastructure I can fully control.&lt;/p&gt;

&lt;p&gt;The stack runs on &lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;Qdrant&lt;/a&gt; for vector storage, &lt;a href="https://ollama.ai/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; for local embeddings, and optional &lt;a href="https://neo4j.com/" rel="noopener noreferrer"&gt;Neo4j&lt;/a&gt; for a knowledge graph that I added later. I also set it up to route different operations to the best LLM for each task. It provides eleven tools for your Claude Code instance to manage long-term memory operations, and your memories data never leaves your machine.&lt;/p&gt;

&lt;p&gt;This article covers how this MCP server works, how to set it up in about 15 minutes, and how to get Claude using memory automatically without you triggering it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Claude Code's built-in memory falls short for accumulated knowledge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Claude Code remember between sessions?
&lt;/h3&gt;

&lt;p&gt;Partially. Claude Code has three persistence mechanisms that carry context forward: &lt;code&gt;CLAUDE.md&lt;/code&gt; files you write yourself, Auto Memory where Claude saves notes about your project patterns and preferences, and Session Memory that extracts summaries from past conversations. All three load at session start, and they cover a lot of ground.&lt;/p&gt;

&lt;p&gt;Static rules, project conventions, and compressed summaries of past work carry forward just fine. If you told Claude to use PostgreSQL last week, it might remember it.&lt;/p&gt;

&lt;p&gt;What doesn't carry forward is the detailed reasoning behind your decisions. When you spend an afternoon choosing between Redis and database-backed sessions, weighing operational complexity and infrastructure costs, and ultimately picking database sessions because your traffic doesn't justify a separate Redis instance yet, that full reasoning chain gets compressed into a one-line summary at best. The next session, Claude might suggest Redis for caching and you have to walk through the tradeoff analysis again.&lt;/p&gt;

&lt;p&gt;Three categories of knowledge get lost or compressed beyond usefulness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision reasoning.&lt;/strong&gt; Not &lt;em&gt;what&lt;/em&gt; you decided, but &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;under what conditions&lt;/em&gt;. "We chose in-memory caching over Redis because at current scale it's premature optimization. Revisit at 10k rps." Auto Memory might note the decision, but the conditional logic that makes it useful, the part about when to revisit, gets lost in compression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging insights.&lt;/strong&gt; "The flaky test failures on CI were caused by state leakage between test groups, not async issues. We proved this by isolating test groups last Tuesday." Session Memory might summarize "fixed flaky tests" but not the three-hour diagnostic path that saves you from repeating the same investigation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-project patterns.&lt;/strong&gt; You build JWT middleware on Project A. Two weeks later, Project B needs authentication. Auto Memory and Session Memory are project-scoped, and while a global &lt;code&gt;CLAUDE.md&lt;/code&gt; can carry some context across repos, it's a static file, not a searchable knowledge base. The pattern exists in a different repo, but Claude has no way to find it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The built-in memory helps, but it has structural limits
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; works well for project rules. Auto Memory adds automatic note-taking, which is a real improvement over manual curation alone. I use both, and I recommend them.&lt;/p&gt;

&lt;p&gt;But they share three structural limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No search.&lt;/strong&gt; Everything loads at session start regardless of relevance. At 200+ entries, you're burning context tokens on information Claude doesn't need for this particular task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summaries, not reasoning.&lt;/strong&gt; Auto Memory and Session Memory compress multi-hour sessions into short notes. The compression loses the detail that matters most, which approaches failed and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mostly project-scoped.&lt;/strong&gt; Auto Memory is strictly per-project. A global &lt;code&gt;CLAUDE.md&lt;/code&gt; can carry rules across repos, but it's a flat file you maintain by hand, not a searchable store of accumulated knowledge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the gap Claude Code persistent memory with semantic search fills. Ask "what went wrong with Redis last month?" and get back the full reasoning: "rejected Redis for session storage because the operational overhead wasn't justified at our traffic levels. Switched to database-backed sessions. Revisit if we hit 10k concurrent users." The words don't match at all, but the meaning does.&lt;/p&gt;




&lt;h2&gt;
  
  
  What mem0 gives Claude Code: persistent memory with semantic search
&lt;/h2&gt;

&lt;p&gt;This MCP server for Claude Code uses &lt;a href="https://github.com/mem0ai/mem0" rel="noopener noreferrer"&gt;mem0ai&lt;/a&gt; as a library and exposes 11 MCP tools that Claude Code calls directly.&lt;/p&gt;

&lt;p&gt;Here's what it looks like in practice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Session 1&lt;/strong&gt; -- debugging a test suite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Remember: flaky test failures in CI were caused by state leakage between
  test groups, not async timing. Fixed by resetting database between groups.
  Took 3 hours to isolate. Don't chase the async red herring again.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Session 2&lt;/strong&gt; -- two weeks later, different project, tests start flaking:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Search my memories for flaky test debugging
-&amp;gt; "flaky test failures in CI were caused by state leakage between test
   groups, not async timing. Fixed by resetting database between groups."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Claude retrieves the debugging insight and skips the three-hour investigation. It starts with the proven fix.&lt;/p&gt;

&lt;p&gt;The difference from a flat file: &lt;strong&gt;semantic vector search&lt;/strong&gt;. "Flaky test debugging" matches "state leakage between test groups" even with completely different wording. The server embeds memories using Ollama's &lt;code&gt;bge-m3&lt;/code&gt; model and stores them in Qdrant for approximate nearest neighbor search. Claude finds memories by meaning, not keywords.&lt;/p&gt;
&lt;h3&gt;
  
  
  The 11 tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add_memory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Store text or conversations. The LLM extracts key facts automatically.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_memories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Semantic vector search with filters, threshold, and reranking.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_memories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Browse and filter stored memories (non-search).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_memory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch a single memory by UUID.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;update_memory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace memory text. Re-embeds and re-indexes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delete_memory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a single memory.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delete_all_memories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Safe bulk delete (never nukes your collection).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_entities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List which users/agents/runs have stored memories.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delete_entities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cascade-delete an entity and all its memories.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_graph&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search Neo4j entities by substring (optional).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get all relationships for a specific entity (optional).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last two require Neo4j, which is entirely optional. You get full Claude Code persistent memory with the first nine tools and nothing but Qdrant + Ollama running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the full source and documentation at the &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted" rel="noopener noreferrer"&gt;mem0-mcp-selfhosted GitHub repo&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  How the MCP server delivers Claude Code persistent memory
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claude Code &amp;lt;-- stdio --&amp;gt; FastMCP Server
                            |-- auth.py          &amp;lt;- OAT token auto-discovery
                            |-- config.py        &amp;lt;- Env vars -&amp;gt; config
                            |-- helpers.py       &amp;lt;- Error handling, safe bulk-delete
                            |-- graph_tools.py   &amp;lt;- Direct Neo4j Cypher queries
                            '-- server.py        &amp;lt;- 11 MCP tools + prompt
                                  |
                                  |-- mem0ai Memory class
                                  |     |-- Vector: LLM fact extraction -&amp;gt; Ollama embed -&amp;gt; Qdrant
                                  |     '-- Graph: LLM entity extraction -&amp;gt; Neo4j (optional)
                                  |
                                  '-- Infrastructure
                                        |-- Qdrant     &amp;lt;- Vector store
                                        |-- Ollama     &amp;lt;- Embeddings (local)
                                        '-- Neo4j      &amp;lt;- Knowledge graph (optional)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The server is 7 modules, each with a specific responsibility. &lt;a href="https://github.com/modelcontextprotocol/python-sdk" rel="noopener noreferrer"&gt;FastMCP&lt;/a&gt; handles the MCP protocol layer. The &lt;code&gt;mem0ai&lt;/code&gt; library handles memory operations. Everything else is configuration, auth, and safety wrappers. Each Claude Code session connects via stdio, so the memory tools are available the moment you start working.&lt;/p&gt;
&lt;h3&gt;
  
  
  The vector memory path
&lt;/h3&gt;

&lt;p&gt;When Claude calls &lt;code&gt;add_memory&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The text goes to Anthropic's API for fact extraction (using your Claude subscription)&lt;/li&gt;
&lt;li&gt;The extracted facts get embedded locally via Ollama (&lt;code&gt;bge-m3&lt;/code&gt;, 1024 dimensions)&lt;/li&gt;
&lt;li&gt;The embedding vectors get stored in Qdrant&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When Claude calls &lt;code&gt;search_memories&lt;/code&gt;, Ollama embeds the query and Qdrant finds the nearest vectors by cosine similarity. The whole pipeline runs in 2-5 seconds.&lt;/p&gt;
&lt;h3&gt;
  
  
  Zero-config auth with OAT auto-discovery
&lt;/h3&gt;

&lt;p&gt;Most memory MCP servers require separate API key configurations. This one reads your existing OAT (OAuth Access Token) directly from &lt;code&gt;~/.claude/.credentials.json&lt;/code&gt;. No configuration needed, and your persistent memory setup works the moment you connect.&lt;/p&gt;

&lt;p&gt;The server uses a 3-tier fallback chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;MEM0_ANTHROPIC_TOKEN&lt;/code&gt; env var (explicit override)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.claude/.credentials.json&lt;/code&gt; (auto-discovery, zero config)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt; env var (standard API key)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It detects whether the token is an OAT (&lt;code&gt;sk-ant-oat...&lt;/code&gt;) or an API key (&lt;code&gt;sk-ant-api...&lt;/code&gt;) and configures the SDK accordingly. OAT tokens use your existing Claude subscription. No separate billing, no additional API key to manage.&lt;/p&gt;


&lt;h2&gt;
  
  
  Setting up Claude Code persistent memory in 15 minutes
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Two services running locally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;Qdrant&lt;/a&gt;&lt;/strong&gt; -- self-hosted vector database (one Docker command)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://ollama.ai/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/strong&gt; -- local embeddings (native install or Docker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; with an active subscription.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: start the infrastructure
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start Qdrant&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 6333:6333 &lt;span class="nt"&gt;-p&lt;/span&gt; 6334:6334 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; qdrant_storage:/qdrant/storage &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; qdrant qdrant/qdrant

&lt;span class="c"&gt;# Start Ollama (skip if already installed natively)&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 11434:11434 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; ollama:/root/.ollama &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; ollama ollama/ollama

&lt;span class="c"&gt;# Pull the embedding model&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;ollama ollama pull bge-m3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If Ollama is already running natively on your machine, skip the Docker container and run &lt;code&gt;ollama pull bge-m3&lt;/code&gt; directly. That's it for infrastructure. Your self-hosted AI memory backend is ready for Claude Code to connect. See the &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted#readme" rel="noopener noreferrer"&gt;full configuration guide&lt;/a&gt; for all available environment variables.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: add the MCP server to Claude Code
&lt;/h3&gt;

&lt;p&gt;One command, available across all your projects:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--scope&lt;/span&gt; user &lt;span class="nt"&gt;--transport&lt;/span&gt; stdio mem0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_QDRANT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:6333 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_EMBED_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:11434 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_EMBED_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bge-m3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_EMBED_DIMS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1024 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_USER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-user-id &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--&lt;/span&gt; uvx &lt;span class="nt"&gt;--from&lt;/span&gt; git+https://github.com/elvismdev/mem0-mcp-selfhosted.git mem0-mcp-selfhosted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;uvx&lt;/code&gt; downloads, installs, and runs the server in an isolated environment. No manual &lt;code&gt;pip install&lt;/code&gt;, no virtual env, no dependency conflicts.&lt;/p&gt;

&lt;p&gt;Or add it to a single project with &lt;code&gt;.mcp.json&lt;/code&gt; in the project root:&lt;/p&gt;

&lt;p&gt;
  .mcp.json for project-scoped setup
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mem0"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"--from"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git+https://github.com/elvismdev/mem0-mcp-selfhosted.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mem0-mcp-selfhosted"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MEM0_QDRANT_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:6333"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MEM0_EMBED_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:11434"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MEM0_EMBED_MODEL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bge-m3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MEM0_EMBED_DIMS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1024"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MEM0_USER_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-user-id"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: make it automatic with CLAUDE.md
&lt;/h3&gt;

&lt;p&gt;Add this to &lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt; (global) so Claude uses memory without you asking:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## MCP Servers&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**mem0**&lt;/span&gt;: Persistent memory across sessions. At the start of each session,
  &lt;span class="sb"&gt;`search_memories`&lt;/span&gt; for relevant context before asking the user to re-explain
  anything. Use &lt;span class="sb"&gt;`add_memory`&lt;/span&gt; whenever you discover project architecture, coding
  conventions, debugging insights, key decisions, or user preferences. Use
  &lt;span class="sb"&gt;`update_memory`&lt;/span&gt; when prior context changes. When in doubt, save it -- future
  sessions benefit from over-remembering.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With this, Claude proactively searches memory at session start and saves things it learns as it goes. You stop re-explaining. Sessions build on each other. Your Claude Code memory across sessions is now fully automatic.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: try it
&lt;/h3&gt;

&lt;p&gt;Restart Claude Code, then:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Search my memories for authentication decisions
&amp;gt; Remember that we rejected Redis for caching because connection pooling
  caused issues at our scale. Revisit at 10k concurrent users.
&amp;gt; Show me all entities in my memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;That's it.&lt;/strong&gt; Qdrant stores your vectors, Ollama generates embeddings locally, and Claude Code now has persistent memory across every session and project.&lt;/p&gt;


&lt;h2&gt;
  
  
  Optional: add a knowledge graph with Neo4j
&lt;/h2&gt;

&lt;p&gt;Vector search handles the core memory use case. If you want structured entity relationships on top, Neo4j adds a second dimension.&lt;/p&gt;

&lt;p&gt;When you store "I prefer TypeScript with strict mode," the graph layer extracts entities and relationships:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user -&amp;gt; PREFERS -&amp;gt; TypeScript
user -&amp;gt; PREFERS -&amp;gt; strict_mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can then ask "what does this user prefer?" and traverse the graph for structured answers rather than relying on text similarity alone.&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick setup
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 7687:7687 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;NEO4J_AUTH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;neo4j/mem0graph neo4j:5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add to your MCP config:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MEM0_ENABLE_GRAPH=true
MEM0_NEO4J_URL=bolt://127.0.0.1:7687
MEM0_NEO4J_PASSWORD=mem0graph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  The quota cost and how to avoid it
&lt;/h3&gt;

&lt;p&gt;Each &lt;code&gt;add_memory&lt;/code&gt; with graph enabled triggers 3 additional LLM calls: entity extraction, relationship generation, and contradiction resolution. That's a real quota cost on your Claude subscription.&lt;/p&gt;

&lt;p&gt;To protect your quota, route graph operations to a cheaper model:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Quality&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ollama (Qwen3:14b)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;0.971 tool-calling F1&lt;/td&gt;
&lt;td&gt;~7-8GB VRAM (Q4_K_M)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Flash Lite&lt;/td&gt;
&lt;td&gt;Near-free&lt;/td&gt;
&lt;td&gt;85.4% entity extraction&lt;/td&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemini_split&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gemini + Claude&lt;/td&gt;
&lt;td&gt;Best combined accuracy&lt;/td&gt;
&lt;td&gt;85.4% extraction + 100% contradiction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With the Ollama path, the entire graph pipeline runs locally. Zero cloud dependency.&lt;/p&gt;

&lt;p&gt;
  Environment variables for each graph provider
  &lt;br&gt;
&lt;strong&gt;Ollama (free, local):&lt;/strong&gt;&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MEM0_GRAPH_LLM_PROVIDER=ollama
MEM0_GRAPH_LLM_MODEL=qwen3:14b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Gemini (near-free):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MEM0_GRAPH_LLM_PROVIDER=gemini
GOOGLE_API_KEY=your-google-api-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Split-model (best accuracy):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MEM0_GRAPH_LLM_PROVIDER=gemini_split
GOOGLE_API_KEY=your-google-api-key
MEM0_GRAPH_CONTRADICTION_LLM_PROVIDER=anthropic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;Neo4j is entirely optional. You get useful self-hosted AI memory with Qdrant and Ollama alone. See the &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted#readme" rel="noopener noreferrer"&gt;project README&lt;/a&gt; for the complete list of environment variables.&lt;/p&gt;


&lt;h2&gt;
  
  
  How self-hosted mem0 compares to other Claude Code persistent memory solutions
&lt;/h2&gt;

&lt;p&gt;Developers I talked to on Reddit had an interesting setup: an Obsidian vault connected to Claude via MCP, with all their chat logs and notes organized by project. When they needed context, they tell Claude to load a specific project folder. It works, but every load pulled in full transcripts, and as their vault grew, the context cost grew linearly with it.&lt;/p&gt;

&lt;p&gt;One of the developers posted a good question: "Isn't this setup I have the same as what you built?" Not quite. The retrieval model is fundamentally different.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Search&lt;/th&gt;
&lt;th&gt;Storage&lt;/th&gt;
&lt;th&gt;Curation&lt;/th&gt;
&lt;th&gt;Cross-project&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CLAUDE.md + Auto Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (loads all)&lt;/td&gt;
&lt;td&gt;Markdown files&lt;/td&gt;
&lt;td&gt;Mixed (manual + auto)&lt;/td&gt;
&lt;td&gt;Per-project (global option)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mem0-mcp-selfhosted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Semantic vector&lt;/td&gt;
&lt;td&gt;Qdrant vectors&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graphiti (Zep)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hybrid graph + vector&lt;/td&gt;
&lt;td&gt;Graph DB (required)&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;td&gt;Depends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Obsidian + MCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keyword or semantic&lt;/td&gt;
&lt;td&gt;Vault files&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Per-vault&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  When each approach fits
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CLAUDE.md + Auto Memory&lt;/strong&gt; is perfect for small projects with manageable context. Zero setup, immediate value, and Auto Memory adds automatic note-taking on top. I let Claude Code do its thing and use both alongside mem0, and they complement each other well.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CLAUDE.md&lt;/code&gt; tells Claude Code how to use memory tools. mem0 handles the semantic storage and retrieval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mem0-mcp-selfhosted&lt;/strong&gt; makes sense when you need LLM long-term memory that works across multiple projects, accumulating knowledge over weeks, or when your preferences have outgrown what a flat file handles gracefully. Semantic search is the differentiator at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/getzep/graphiti" rel="noopener noreferrer"&gt;Graphiti&lt;/a&gt;&lt;/strong&gt; is worth evaluating if structured temporal relationships are your primary need. It's graph-first, meaning a graph database is required, not optional. Neo4j is the primary backend, with FalkorDB, Kuzu, and Amazon Neptune also supported. It offers bi-temporal tracking that mem0 doesn't, recording both when a fact became true and when the system learned it. The infrastructure is heavier, and depending on your LLM provider you may need separate API keys for LLM and embedding operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Obsidian + MCP&lt;/strong&gt; works well if you're already an Obsidian power user who wants visual browsing and manual editing of notes. Basic implementations use keyword search over vault files, though some servers like obsidian-mcp-tools add semantic search via the Smart Connections plugin. All implementations store full documents rather than distilled facts, so context costs scale with vault size.&lt;/p&gt;


&lt;h2&gt;
  
  
  Get started and let me know how it goes
&lt;/h2&gt;

&lt;p&gt;Here's what we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code's built-in memory captures rules and summaries, but not detailed reasoning chains. Claude Code persistent memory with semantic search requires an external tool.&lt;/li&gt;
&lt;li&gt;mem0-mcp-selfhosted gives Claude Code 11 memory tools backed by self-hosted Qdrant + Ollama.&lt;/li&gt;
&lt;li&gt;Semantic vector search finds memories by meaning, not keywords.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;CLAUDE.md&lt;/code&gt; integration makes memory usage automatic. No manual triggering needed.&lt;/li&gt;
&lt;li&gt;Neo4j adds structured entity relationships, but it's entirely optional.&lt;/li&gt;
&lt;li&gt;Zero-config auth reads your existing OAT token. No API key setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The setup takes about 15 minutes: two Docker containers, one &lt;code&gt;claude mcp add&lt;/code&gt; command, and a &lt;code&gt;CLAUDE.md&lt;/code&gt; snippet. After that, Claude Code persistent memory builds up knowledge over time across all your projects.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--scope&lt;/span&gt; user &lt;span class="nt"&gt;--transport&lt;/span&gt; stdio mem0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_QDRANT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:6333 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_EMBED_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:11434 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_EMBED_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bge-m3 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_EMBED_DIMS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1024 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MEM0_USER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-user-id &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--&lt;/span&gt; uvx &lt;span class="nt"&gt;--from&lt;/span&gt; git+https://github.com/elvismdev/mem0-mcp-selfhosted.git mem0-mcp-selfhosted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Full source code, documentation, and issue tracker for this self-hosted MCP memory server &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted" rel="noopener noreferrer"&gt;mem0-mcp-selfhosted are on GitHub&lt;/a&gt;. If you're interested in more Claude Code tooling, check out my &lt;a href="https://dev.to/n3rdh4ck3r/claude-code-skill-for-wordpress-performance-reviews-1560"&gt;WordPress performance review skill&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd love to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does Claude use memory proactively with the &lt;code&gt;CLAUDE.md&lt;/code&gt; setup in your experience?&lt;/li&gt;
&lt;li&gt;What would you want Claude to remember that it currently forgets?&lt;/li&gt;
&lt;li&gt;How's the setup experience? Too many pieces or manageable?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install it, search for something, and &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; or drop a comment if the results surprise you.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/elvismdev" rel="noopener noreferrer"&gt;
        elvismdev
      &lt;/a&gt; / &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted" rel="noopener noreferrer"&gt;
        mem0-mcp-selfhosted
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Self-hosted mem0 MCP server for Claude Code. Run a complete memory server against self-hosted Qdrant + Neo4j + Ollama while using Claude as the main LLM.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;mem0-mcp-selfhosted&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://glama.ai/mcp/servers/elvismdev/mem0-mcp-selfhosted" rel="nofollow noopener noreferrer"&gt;&lt;img width="380" height="200" src="https://camo.githubusercontent.com/c196d458e8be0a95160c100ec5d130cf5778d5bf43fd00871ad8c1228fe5be97/68747470733a2f2f676c616d612e61692f6d63702f736572766572732f656c7669736d6465762f6d656d302d6d63702d73656c66686f737465642f62616467653f763d31" alt="mem0-mcp-selfhosted MCP server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Self-hosted &lt;a href="https://github.com/mem0ai/mem0" rel="noopener noreferrer"&gt;mem0&lt;/a&gt; MCP server for Claude Code. Run a complete memory server against self-hosted Qdrant + Neo4j + Ollama, with your choice of Anthropic (Claude) or Ollama as the main LLM.&lt;/p&gt;

&lt;p&gt;Uses the &lt;code&gt;mem0ai&lt;/code&gt; package directly as a library, supports both Claude's OAT token and fully local Ollama setups, and exposes 11 MCP tools for full memory management.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Prerequisites&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;Qdrant&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Vector memory storage and search&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;Ollama&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Embedding generation (&lt;code&gt;bge-m3&lt;/code&gt;) and optionally local LLM&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;Neo4j 5+&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Knowledge graph (entity relationships)&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;Google API Key&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Required only for &lt;code&gt;gemini&lt;/code&gt;/&lt;code&gt;gemini_split&lt;/code&gt; graph providers&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Python &amp;gt;= 3.10 and &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="nofollow noopener noreferrer"&gt;uv&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Authentication:&lt;/strong&gt; The default setup uses Claude (Anthropic) as the LLM for fact extraction. No API key needed, the server automatically uses your Claude Code session token. For fully local setups, set &lt;code&gt;MEM0_PROVIDER=ollama&lt;/code&gt;. See &lt;a href="https://github.com/elvismdev/mem0-mcp-selfhosted#authentication" rel="noopener noreferrer"&gt;Authentication&lt;/a&gt; for advanced options.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Default (Anthropic)&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;Add the…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/elvismdev/mem0-mcp-selfhosted" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;





</description>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Claude Code Skill for WordPress Performance Reviews</title>
      <dc:creator>Elvis Mørales Fdz</dc:creator>
      <pubDate>Sat, 29 Nov 2025 03:42:16 +0000</pubDate>
      <link>https://dev.to/n3rdh4ck3r/claude-code-skill-for-wordpress-performance-reviews-1560</link>
      <guid>https://dev.to/n3rdh4ck3r/claude-code-skill-for-wordpress-performance-reviews-1560</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i1dhqn298bqc25meo7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5i1dhqn298bqc25meo7z.png" alt="Critical Issues &amp;amp; Warnings Flagged" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if you could get a performance code review from someone who's seen WordPress sites fail under load and remembers all the patterns that caused it?&lt;/p&gt;

&lt;p&gt;That's what this Claude Code skill does. It knows 50+ anti-patterns that cause WordPress performance problems, and it flags them with severity levels, line numbers, and explanations of what actually happens when they run in production.&lt;/p&gt;

&lt;p&gt;I built it because I kept seeing the same issues over and over. A site works fine in development, handles QA traffic without problems, then gets on the news and falls over within an hour. The code wasn't "wrong", it just had patterns that don't survive real traffic. Unbounded database queries. Cache bypass. N+1 problems. Accidental self-DDoS from polling. These things are invisible until they're not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; This Claude Code skill performs AI-powered WordPress code review that catches performance anti-patterns static analysis can't see. It understands context across files, knows platform-specific fixes for &lt;a href="https://wpvip.com/" rel="noopener noreferrer"&gt;WordPress VIP&lt;/a&gt;, &lt;a href="https://wpengine.com/" rel="noopener noreferrer"&gt;WP Engine&lt;/a&gt;, and shared hosting, and explains why patterns fail under load - not just that they violate a rule.&lt;/p&gt;




&lt;h2&gt;
  
  
  What WordPress Performance Issues It Catches
&lt;/h2&gt;

&lt;p&gt;The obvious stuff is here, &lt;code&gt;posts_per_page =&amp;gt; -1&lt;/code&gt;, &lt;code&gt;query_posts()&lt;/code&gt;, &lt;code&gt;session_start()&lt;/code&gt; on the frontend. If you've worked on WordPress at any scale, you know these. But the skill also catches the patterns that look fine until they aren't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database writes on page loads.&lt;/strong&gt; This one looks harmless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'wp_head'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;update_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'page_views'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'page_views'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's just incrementing a counter, right? But &lt;code&gt;update_option&lt;/code&gt; is an &lt;code&gt;INSERT&lt;/code&gt; or &lt;code&gt;UPDATE&lt;/code&gt; query. Every visitor triggers a database write. At 1,000 visitors per hour, that's 1,000 write queries competing for row locks on &lt;code&gt;wp_options&lt;/code&gt;. Your database CPU spikes, other queries queue up, page loads slow down, and eventually things start timing out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic transient keys.&lt;/strong&gt; This pattern creates rows in &lt;code&gt;wp_options&lt;/code&gt; for every user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;set_transient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s2"&gt;"user_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_cart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$cart_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;HOUR_IN_SECONDS&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Syntactically fine. Functionally fine for a few hundred users. At 10,000 users, you have 20,000 rows in &lt;code&gt;wp_options&lt;/code&gt; - WordPress stores the value and the timeout in separate rows. I've seen this pattern bloat &lt;code&gt;wp_options&lt;/code&gt; to 40GB. The fix is to use &lt;code&gt;wp_cache_set()&lt;/code&gt; instead, which uses object cache and doesn't touch the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Polling patterns.&lt;/strong&gt; Someone adds a "live updates" feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/wp-json/myapp/v1/updates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every browser tab polls your server every 5 seconds. With 100 concurrent users, that's 100 requests every 5 seconds - 20 per second hitting your origin. These requests can't be cached because they're checking for "new" data. You've accidentally DDoS'd yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cron jobs that never stop multiplying.&lt;/strong&gt; This is subtle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;register_activation_hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;wp_schedule_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'hourly'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my_plugin_sync'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time the plugin is activated, it schedules a new cron job. Deactivate and reactivate a few times during debugging, and you've got 5 instances of &lt;code&gt;my_plugin_sync&lt;/code&gt; running every hour. The fix is checking &lt;code&gt;wp_next_scheduled()&lt;/code&gt; first - but if you don't know to look for it, you won't.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbsqzrhub3j867arbcqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbsqzrhub3j867arbcqg.png" alt="Performance review summary showing component breakdown, risk assessment, and priority fixes" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Output summary from reviewing a WooCommerce site with custom plugins&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How a Claude Code Skill Compares to Static Analysis Tools
&lt;/h2&gt;

&lt;p&gt;I still run PHPCS with &lt;a href="https://github.com/WordPress/WordPress-Coding-Standards" rel="noopener noreferrer"&gt;WordPress Coding Standards&lt;/a&gt; in my workflow - it's integrated with VS Code via this &lt;a href="https://marketplace.visualstudio.com/items?itemName=wongjn.php-sniffer" rel="noopener noreferrer"&gt;PHP Sniffer extension&lt;/a&gt; and catches real issues on every save. Tools like &lt;a href="https://phpstan.org/" rel="noopener noreferrer"&gt;PHPStan&lt;/a&gt; and &lt;a href="https://psalm.dev/" rel="noopener noreferrer"&gt;Psalm&lt;/a&gt; in some projects also add type checking and can catch bugs before runtime.&lt;/p&gt;

&lt;p&gt;But static analysis has limits. It can tell you "&lt;em&gt;this line violates rule X&lt;/em&gt;" but not "&lt;em&gt;this pattern across your codebase will cause problems under specific conditions.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use static analysis:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforcing coding standards on every save&lt;/li&gt;
&lt;li&gt;Type checking and catching null reference errors&lt;/li&gt;
&lt;li&gt;CI/CD pipeline checks for syntax and style&lt;/li&gt;
&lt;li&gt;Catching obvious mistakes before code review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use AI-powered code reviews:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finding performance issues that span multiple files&lt;/li&gt;
&lt;li&gt;Understanding WordPress-specific runtime behavior&lt;/li&gt;
&lt;li&gt;Getting context-aware recommendations for your hosting platform&lt;/li&gt;
&lt;li&gt;Catching patterns that are syntactically valid but semantically problematic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The best approach (if they're already part of your workflow):&lt;/strong&gt; Use both. Run PHPCS and PHPStan in your IDE and CI pipeline. Then use this Claude Code skill for deeper WordPress performance analysis before major releases or when debugging production issues.&lt;/p&gt;

&lt;p&gt;Here's an example of something static analysis can't catch. This code silently turns into an unbounded query when it fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_post_id_from_external_api&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Returns false on timeout or 404&lt;/span&gt;
&lt;span class="nv"&gt;$query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WP_Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'p'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;intval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$post_id&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;get_post_id_from_external_api()&lt;/code&gt; returns false, &lt;code&gt;intval(false)&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;. And in &lt;code&gt;WP_Query&lt;/code&gt;, &lt;code&gt;'p' =&amp;gt; 0&lt;/code&gt; doesn't mean "get post with ID 0" - it means "don't filter by post ID." If there's no &lt;code&gt;posts_per_page&lt;/code&gt; set, you've just queried every post in the database.&lt;/p&gt;

&lt;p&gt;Static analysis can't catch this. It sees a valid function call with a valid argument type. It doesn't know that &lt;code&gt;$post_id&lt;/code&gt; might be falsy, and it doesn't know the WordPress-specific behavior of &lt;code&gt;'p' =&amp;gt; 0&lt;/code&gt;. The skill can reason about this and flag it: "You're passing a potentially falsy value through &lt;code&gt;intval()&lt;/code&gt; into a post ID argument - validate before querying."&lt;/p&gt;

&lt;p&gt;Another example: &lt;code&gt;session_start()&lt;/code&gt; in a single plugin makes your entire site uncacheable. Page caching serves identical HTML to everyone. PHP sessions create per-visitor state - incompatible by design. One line in one plugin you installed last year can be the reason your page cache hit rate is 0% and you're wondering why Cloudflare isn't helping.&lt;/p&gt;

&lt;p&gt;Static analysis sees &lt;code&gt;session_start()&lt;/code&gt; and might flag it generically. But it doesn't understand the site-wide caching implications. The skill explains: "&lt;em&gt;This bypasses all page caching. Every request hits PHP. Check if this plugin actually needs sessions on the frontend, or if it can be limited to logged-in users.&lt;/em&gt;"&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding N+1 Database Queries Across Files
&lt;/h2&gt;

&lt;p&gt;This one is hard to spot in manual code review and very challenging for file-by-file static analysis to catch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In archive.php&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;have_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;the_post&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="nv"&gt;$author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_extended_author_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;get_the_author_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'ID'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="c1"&gt;// render post...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In functions.php&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get_extended_author_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$user_id&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_user_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user_id&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Database query&lt;/span&gt;
 &lt;span class="nv"&gt;$meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_user_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$user_id&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Another query if not primed&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'meta'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$meta&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop runs 10 times. Each iteration calls &lt;code&gt;get_extended_author_data()&lt;/code&gt;, which runs 2 queries. That's 20 database queries where there should be 2 - one to get all the users, one to get all the meta.&lt;/p&gt;

&lt;p&gt;When you're looking at &lt;code&gt;archive.php&lt;/code&gt;, you see a function call. When you're looking at &lt;code&gt;functions.php&lt;/code&gt;, you see a function that does a couple of queries. Neither file is "wrong" in isolation. The problem is the interaction between them.&lt;/p&gt;

&lt;p&gt;One fix could be to prime the caches before the loop - and the skill can suggest the best approach for your specific case depending on the context it learns from your codebase as a whole:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prime author cache before the loop&lt;/span&gt;
&lt;span class="nv"&gt;$author_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wp_list_pluck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$wp_query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'post_author'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;cache_users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$author_ids&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Single query loads all authors&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;have_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;the_post&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="nv"&gt;$author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_extended_author_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;get_the_author_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'ID'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="c1"&gt;// Now uses cached data - no additional queries&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill sees across files. It understands that calling a function with database queries inside a WordPress loop is a red flag pattern, regardless of where that function is defined.&lt;/p&gt;




&lt;h2&gt;
  
  
  WooCommerce Performance Anti-Patterns
&lt;/h2&gt;

&lt;p&gt;WooCommerce sites face unique WordPress performance challenges. The skill catches several WooCommerce-specific issues that can tank your store's performance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cart fragment AJAX overhead.&lt;/strong&gt; In older WooCommerce versions (pre-7.8), the cart fragments script ran on every page load - even pages with no cart widget. While &lt;a href="https://developer.woocommerce.com/2023/06/16/best-practices-for-the-use-of-the-cart-fragments-api/" rel="noopener noreferrer"&gt;WooCommerce 7.8+ improved this behavior&lt;/a&gt;, many stores still have legacy code or third-party plugins that explicitly enqueue the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Legacy pattern that can still cause unnecessary AJAX on every page&lt;/span&gt;
&lt;span class="nf"&gt;wp_enqueue_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'wc-cart-fragments'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill flags when cart fragments are being loaded unnecessarily and suggests limiting them to pages that actually display cart data, or reviewing whether your theme/plugins truly need real-time cart updates on every page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Order queries without limits.&lt;/strong&gt; This pattern appears in admin dashboards and reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wc_get_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;'date_created'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'&amp;gt;'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;strtotime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'-30 days'&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks reasonable - get last 30 days of orders. But stores with high volume can have 10,000+ orders in 30 days. Without a &lt;code&gt;'limit'&lt;/code&gt; parameter, you're loading them all into memory. The skill recommends adding pagination or using &lt;code&gt;'limit' =&amp;gt; 100&lt;/code&gt; with proper iteration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Product query loops in templates.&lt;/strong&gt; Custom product displays often trigger extra queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In a custom template&lt;/span&gt;
&lt;span class="nv"&gt;$related&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wc_get_related_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$related&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$related_id&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nv"&gt;$related_product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wc_get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$related_id&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Query per product&lt;/span&gt;
 &lt;span class="c1"&gt;// display...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill suggests using &lt;code&gt;wc_get_products()&lt;/code&gt; with the IDs to batch-load products in a single query.&lt;/p&gt;




&lt;h2&gt;
  
  
  Platform-Specific WordPress Performance Advice
&lt;/h2&gt;

&lt;p&gt;The right fix for your identified issues can also depend on where your production code runs. The Claude Code skill adapts and suggests its recommendations based on your hosting environment - if it's able to identify it from what it learns from your codebase. It can also suggest how different alternative approaches exist in WordPress-specific hosting platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On &lt;a href="https://wpvip.com/" rel="noopener noreferrer"&gt;WordPress VIP&lt;/a&gt;&lt;/strong&gt;, there are platform-specific functions that handle caching for you. Instead of &lt;code&gt;url_to_postid()&lt;/code&gt; - which does an expensive lookup on every call - you use &lt;code&gt;wpcom_vip_url_to_postid()&lt;/code&gt;, which caches the result. For external HTTP calls, &lt;code&gt;vip_safe_wp_remote_get()&lt;/code&gt; adds circuit-breaker logic that fails gracefully after repeated timeouts. The skill knows these alternatives exist and recommends them when it identifies VIP-specific patterns in your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On managed hosts like &lt;a href="https://wpengine.com/" rel="noopener noreferrer"&gt;WP Engine&lt;/a&gt; or &lt;a href="https://pantheon.io/" rel="noopener noreferrer"&gt;Pantheon&lt;/a&gt;&lt;/strong&gt;, you usually have Redis or Memcached available. Transients use the object cache instead of the database, so the dynamic transient key problem I mentioned earlier is less severe (though still not ideal). &lt;a href="https://querymonitor.com/" rel="noopener noreferrer"&gt;Query Monitor&lt;/a&gt; is typically available for profiling slow queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On shared hosting&lt;/strong&gt;, there's often no persistent object cache at all. Transients fall back to &lt;code&gt;wp_options&lt;/code&gt;. That 20,000-row bloat is very real. You also can't rely on server-level cron, so &lt;code&gt;DISABLE_WP_CRON&lt;/code&gt; may not be an option. The skill can flag these patterns more aggressively when it identifies, or you mention in your prompts, that you're not on a platform with object cache.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Results from WordPress Code Reviews
&lt;/h2&gt;

&lt;p&gt;To give you a sense of what the skill finds in practice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On a 50-file custom theme:&lt;/strong&gt; The skill identified 12 performance issues in about 30 seconds. The most critical was an N+1 query pattern in the archive template that was causing 47 database queries per page load instead of 5. After fixing, page generation time dropped from 800ms to 180ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On a commercial Pro WooCommerce plugin:&lt;/strong&gt; Found 4 issues including an unbounded order query in a reporting function and a missing nonce check (security, not performance, but still caught it). The order query was loading 15,000 orders into memory on a client with high volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On a migration from shared hosting to WP Engine:&lt;/strong&gt; The skill identified 6 patterns that would work differently with Redis object cache enabled, including transient usage that was previously falling back to database but would now persist correctly.&lt;/p&gt;

&lt;p&gt;The skill won't catch everything - it's not running your code or profiling actual queries. But it catches patterns that experienced WordPress developers learn to avoid after seeing them cause problems in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Install and Use the WordPress Performance Skill
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;First, add the marketplace to Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add elvismdev/claude-wordpress-skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin &lt;span class="nb"&gt;install &lt;/span&gt;claude-wordpress-skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; After installation, exit Claude Code completely and relaunch it. The skill won't load until you restart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Exit Claude Code (Ctrl+C or type 'exit')&lt;/span&gt;
&lt;span class="c"&gt;# Then relaunch from your project directory&lt;/span&gt;
claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the skill is loaded, you can check your installed plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;strong&gt;claude-wordpress-skills&lt;/strong&gt; listed as installed and enabled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Once installed, ask Claude Code to review your code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Review this plugin for performance issues"&lt;/li&gt;
&lt;li&gt;"Check theme/functions.php before we launch"&lt;/li&gt;
&lt;li&gt;"Audit this PR for WordPress anti-patterns"&lt;/li&gt;
&lt;li&gt;"Look for N+1 queries in this WooCommerce extension"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill activates automatically when you're reviewing WordPress PHP code or mention performance-related terms like "slow," "timeout," or "performance review."&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Skill not activating?&lt;/strong&gt; Make sure you restarted Claude Code after installation. Check that the plugin shows as "enabled" in &lt;code&gt;/plugin&lt;/code&gt; output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting too many warnings?&lt;/strong&gt; The skill errs on the side of caution. You can ask it to focus on critical issues only: "Show me only high-severity performance issues."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need platform-specific advice?&lt;/strong&gt; Tell Claude Code your hosting environment: "We're on WP Engine with Redis" and it will adjust recommendations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get It on GitHub
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/elvismdev/claude-wordpress-skills" rel="noopener noreferrer"&gt;https://github.com/elvismdev/claude-wordpress-skills&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find patterns it misses, false positives it flags, or anti-patterns you've seen in the wild that aren't covered - open an issue or PR. A great goal would be to capture the stuff that experienced WordPress developers know to look for and make it available to everyone doing WordPress code review.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributing
&lt;/h3&gt;

&lt;p&gt;The skill is defined in markdown files that Claude Code reads to understand WordPress performance patterns. To add a new anti-pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repository&lt;/li&gt;
&lt;li&gt;Add the pattern to the relevant category file&lt;/li&gt;
&lt;li&gt;Include: pattern description, code example, severity level, fix recommendation&lt;/li&gt;
&lt;li&gt;Submit a PR with before/after examples&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Some Example Questions That Come to Mind
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I check WordPress plugin performance?
&lt;/h3&gt;

&lt;p&gt;Install the Claude Code WordPress performance skill, navigate to your plugin directory, and ask Claude to "review this plugin for performance issues." It will analyze your PHP files for 50+ anti-patterns including database query issues, caching problems, and code patterns that don't scale. For runtime profiling, combine with &lt;a href="https://querymonitor.com/" rel="noopener noreferrer"&gt;Query Monitor&lt;/a&gt; to see actual query counts and execution times.&lt;/p&gt;

&lt;h3&gt;
  
  
  What causes slow WordPress database queries?
&lt;/h3&gt;

&lt;p&gt;The most common causes are: unbounded queries (&lt;code&gt;posts_per_page =&amp;gt; -1&lt;/code&gt;), N+1 query patterns where loops trigger individual queries instead of batch fetching, missing indexes on custom tables, &lt;code&gt;meta_query&lt;/code&gt; without proper indexes, and autoloaded options in &lt;code&gt;wp_options&lt;/code&gt; that load on every page. The skill catches all of these patterns and explains the specific fix for each.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to find N+1 queries in WordPress?
&lt;/h3&gt;

&lt;p&gt;N+1 queries happen when a loop triggers a database query on each iteration. Look for function calls inside &lt;code&gt;while ( have_posts() )&lt;/code&gt; or &lt;code&gt;foreach&lt;/code&gt; loops that call &lt;code&gt;get_post_meta()&lt;/code&gt;, &lt;code&gt;get_user_by()&lt;/code&gt;, &lt;code&gt;get_the_terms()&lt;/code&gt;, or similar functions. The Claude Code skill specifically identifies these patterns even when the querying function is defined in a different file than the loop.&lt;/p&gt;




&lt;p&gt;What performance issue burned you the worst? I'm especially curious about patterns specific to WooCommerce or multisite - might end up in the next version.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>performance</category>
      <category>ai</category>
      <category>codereview</category>
    </item>
  </channel>
</rss>
