Listen to today's AI briefing

Daily podcast — 5 min, AI-narrated summary of top stories

Build a Self-Improving Memory Layer for Claude Code with Hooks and RAG
AI ResearchScore: 88

Build a Self-Improving Memory Layer for Claude Code with Hooks and RAG

Implement automatic hooks to capture Claude Code's work into a ChromaDB vector store and a CLAUDE.md file, creating a persistent, searchable memory for your project.

GAla Smith & AI Research Desk·1h ago·4 min read·10 views·AI-Generated
Share:
Source: dev.tovia devto_claudecode, reddit_claudeMulti-Source

The Technique: Automatic Knowledge Capture with Hooks

The core innovation is using Claude Code's hook system to intercept events and automatically log them to a persistent knowledge base. This solves the "stateless AI" problem where every session starts fresh, forcing you to re-debug the same issues.

The author built a three-layer system:

  1. ChromaDB Vector Store: For semantic search across captured errors, fixes, and learnings.
  2. Graph Memory: To track relationships (e.g., Error → occurred_in → File).
  3. CLAUDE.md File: A living project file updated after each session.

The magic is in the automation. You don't manually type /learn. Scripts watch Claude Code's activity and save the important bits.

Why It Works: Turning Ephemeral Sessions into Lasting Knowledge

Claude Code is powerful but forgetful. Its context is limited to the current session. This system externalizes that context into a searchable format. When you ask, "Have we seen this auth error before?" the RAG system can find the exact fix from two weeks ago.

The three-layer approach is key:

  • ChromaDB finds semantically similar issues, even if the phrasing differs.
  • Graph Memory answers relational questions like "What files are most error-prone?"
  • CLAUDE.md gives Claude immediate, high-priority context at the start of every new session, loaded automatically.

How To Apply It: Start with a Simple Hook

You don't need to build the full three-layer system immediately. Start by automating your CLAUDE.md file. Here’s a basic session_summary.py hook you can adapt:

# ~/.config/claude-code/hooks/session_summary.py
import json
from datetime import datetime

def on_stop(session_history, project_root):
    """Hook that runs when a Claude Code session ends."""
    claude_md_path = project_root / "CLAUDE.md"
    
    # Extract the last few messages to summarize the session
    recent_activity = session_history[-5:]  # Get last 5 messages
    
    summary = """## Session Summary - {date}

### What We Did
{activity_summary}

### Key Learnings / Pitfalls
- Add key insights here from the session.
""".format(
        date=datetime.now().strftime("%Y-%m-%d"),
        activity_summary='\n'.join([f"- {msg['role']}: {msg['content'][:100]}..." for msg in recent_activity])
    )
    
    # Append to CLAUDE.md
    with open(claude_md_path, 'a') as f:
        f.write(f"\n\n{summary}")
    
    print(f"[Hook] Session summary appended to {claude_md_path}")

To use this:

  1. Save the script to your Claude Code hooks directory.
  2. Ensure CLAUDE.md exists in your project root.
  3. Every time you end a session (Ctrl+D or type /exit), the hook will fire and append a summary.

For the next level, implement an error-capturing hook using the PostToolUse event. The source provides a blueprint:

# capture_failure.py (PostToolUse hook)
def capture_failure(tool_result):
    if tool_result.exit_code != 0:  # Check if a shell command failed
        error = tool_result.output[:500]  # Get error snippet
        # Log to a simple JSON file for now
        log_entry = {
            "timestamp": datetime.now().isoformat(),
            "command": tool_result.command,
            "error": error,
            "file": tool_result.file
        }
        with open("debug_log.json", "a") as f:
            f.write(json.dumps(log_entry) + "\n")

This creates a searchable log of every failed command. You can later upgrade this to write to a local ChromaDB instance.

Integrating with MCP for a Smoother Workflow

Once you have data being captured, you can serve it back to Claude Code using the Model Context Protocol (MCP). Claude Code has native MCP support, mentioned in 34 prior sources. You can write a simple MCP server that:

  1. Reads your debug_log.json or ChromaDB.
  2. Exposes a tool like search_past_errors(query).
  3. Lets Claude query past failures directly within the chat.

A basic MCP server skeleton:

# mcp_memory_server.py
from mcp.server import Server, NotificationOptions
import mcp.server.stdio
import json

server = Server("claude-memory")

@server.list_tools()
async def handle_list_tools():
    return [{
        "name": "search_past_errors",
        "description": "Search through previously captured error logs.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"}
            }
        }
    }]

@server.call_tool()
async def handle_call_tool(name, arguments):
    if name == "search_past_errors":
        query = arguments.get("query", "")
        # Simple grep-style search for now
        results = []
        try:
            with open("debug_log.json", "r") as f:
                for line in f:
                    if query.lower() in line.lower():
                        results.append(json.loads(line))
        except FileNotFoundError:
            pass
        return {
            "content": [{
                "type": "text",
                "text": json.dumps(results[:5], indent=2)  # Return top 5 matches
            }]
        }

# Run the server
if __name__ == "__main__":
    mcp.server.stdio.run(server)

Add this server to your Claude Code config (claude.toml):

[mcp_servers.memory]
command = "python"
args = ["/path/to/mcp_memory_server.py"]

Now, in any session, you can ask Claude: "Use the search_past_errors tool to see if we've hit a 'JWT expired' error before."

The Payoff: From Reactive to Proactive Debugging

The end goal is to have your CLAUDE.md file automatically prepopulated with a "Known Pitfalls" section. When you start a new session on a project, Claude immediately knows:

  • "In auth.ts, we often get JWT expiration errors; the fix is usually X."
  • "The build fails if you don't run generate-types first."
  • "The deployment succeeded when we used strategy Y."

This transforms Claude Code from a brilliant but amnesiac assistant into a seasoned team member who remembers your project's entire history.

Following this story?

Get a weekly digest with AI predictions, trends, and analysis — free.

AI Analysis

Claude Code users should immediately start by **implementing the session summary hook**. This is low-effort, high-reward. It automates the maintenance of your `CLAUDE.md` file, which is the single most effective tool for providing Claude with project context. Stop manually curating this file; make your workflow create it. Next, **add the failure-capturing hook**. This turns every `exit_code != 0` from a wasted moment into a logged data point. Store these in a simple JSON file. The immediate benefit is you can `grep` this file yourself when an error looks familiar. The long-term benefit is you have the raw data to later feed into a vector database. Finally, **consider your MCP strategy**. The Model Context Protocol is Claude Code's superpower for integration. Instead of building a monolithic RAG system, start by building a simple MCP server that reads your JSON log. This lets you and Claude query past errors interactively. This incremental approach aligns with the tool's design philosophy, where MCP servers (mentioned in 34 sources) are the preferred way to extend functionality.

Mentioned in this article

Enjoyed this article?
Share:

Related Articles

More in AI Research

View all