Give Claude Code Permanent Memory

Stop repeating yourself every conversation. This guide sets up two memory layers — Mem0 for semantic client context and Neon Postgres for timestamped event recall — so Claude remembers everything, forever.

Two Memory Layers, One Brain

You'll install two complementary memory systems that give Claude Code persistent, cross-conversation context about your clients, decisions, and operations.

Mem0 — Semantic Memory

Stores facts, preferences, and decisions per client. "Solar on Steroids uses Instantly for cold email." Searchable via natural language. Auto-injected when you mention a client.

$0/mo (free tier)

Neon Postgres — Event Memory

Timestamped event log: meetings, blockers, deliveries, tool changes. Query in natural language — "What happened with TMH last week?" Returns structured timeline data.

$0/mo (free tier)

Auto-Injection Hook

A Claude Code hook that fires on every prompt. Detects client names and automatically pulls relevant memories into context — no manual fetching needed.

included

What You Need Before Starting

Everything runs on free tiers. The only cost is the Claude Code subscription you already have.

Tool Purpose Cost Time to Set Up
Claude Code (CLI) The AI coding agent that will use the memory $20/mo (Max plan) Already installed
Mem0 Account Semantic memory storage & retrieval API Free tier 2 minutes
Neon Postgres Serverless Postgres for event memory table Free tier (0.5 GB) 3 minutes
Python 3.9+ Runs the memory scripts and hooks Free Already installed (macOS)
pip packages mem0ai, psycopg2-binary, requests Free 30 seconds
$0
Monthly Cost
~15m
Total Setup Time
2
API Keys Needed

The Before & After

Every time Claude asks "which email platform does this client use?" — that's a memory failure. Here's what changes when you give it persistent recall:

Task Without Memory With Memory Time Saved
Client context re-briefing 5-10 min per session 0 min (auto-injected) ~40 min/day
Remembering tech stack decisions Search Slack/Notion manually Instant recall ~15 min/task
CRM/pipeline status checks Copy-paste from 3 tools Natural language query ~20 min/day
Onboarding a new client Write full brief from scratch Add 5 memories, done ~30 min/client
Recalling meeting decisions Re-watch recording or notes "What did we decide with TMH?" ~10 min/meeting
Writing client-specific content Re-read brand docs every time Style auto-loaded ~15 min/piece
Debugging past implementations Search git log + Slack "How did we fix the ENF scraper?" ~20 min/bug
Handoff between sessions Write TASKS.json manually Context persists automatically ~10 min/session
Tracking client preferences Scattered across docs Single source of truth ~5 min/lookup
Generating operations reports Aggregate from 5 sources Query memory + sheet data ~25 min/report
2-3 hrs
Saved Per Day
50+ hrs
Saved Per Month
15 min
One-Time Setup

Conservative math: If you manage 5+ clients or run 8+ Claude sessions per day, the compounding effect is dramatic. Memory doesn't just save time — it eliminates the quality loss from re-explaining context.

Copy, Paste, Done

Open Claude Code in your project directory, paste this prompt, and let it build everything. The prompt instructs Claude to create the mem0 skill, Neon memory table, hooks, and MCP configuration.

Paste into Claude Code
I want you to set up a complete AI memory system for my Claude Code environment. This includes two layers:

## Layer 1: Mem0 (Semantic Client Memory)

Create a skill at `.claude/skills/mem0/` with:
- A `SKILL.md` that documents all commands (search, add, update, delete, list, entity, history)
- A Python CLI wrapper at `scripts/mem0_client.py` that wraps the Mem0 API
- A fetch script at `scripts/mem0_fetch.sh` for formatted markdown output
- Entity scoping: `user_id` = client slug, `agent_id` = my agency name

I'll provide my Mem0 API key when you ask for it.

## Layer 2: Neon Postgres (Event Memory)

Set up a Neon Postgres database with a `memory_events` table:
- Columns: id (serial), client_slug (text), event_type (text), content (text), tags (text[]), created_at (timestamptz)
- Create a query interface that accepts natural language questions and converts them to SQL
- Set this up as an MCP server so Claude can query it directly

I'll provide my Neon connection string when you ask for it.

## Layer 3: Auto-Injection Hook

Create a Claude Code hook at `.claude/hooks/on_client_context.py` that:
- Fires on every user prompt (UserPromptSubmit)
- Detects known client names/slugs in the prompt
- Automatically fetches relevant mem0 memories and injects them as context
- Maintains a LEGACY_ENTITY_MAP for clients with non-standard mem0 entity names

## Requirements
- Python 3.9 compatible (use Optional[] not | None, List[] not list[])
- Install required pip packages: mem0ai, psycopg2-binary, requests
- Add the hook to `.claude/settings.json` under hooks
- Test each component after creation
- Show me the final working state of each piece

Start by asking me for my Mem0 API key and Neon connection string, then build everything.

What happens next: Claude will ask for your Mem0 API key and Neon connection string, then build the entire system, test it, and show you the working output. Takes about 10-15 minutes of Claude working autonomously.

Step-by-Step Instructions

If the one-prompt approach doesn't work perfectly, or you want to understand each piece, follow these steps.

Create Your Mem0 Account

Go to app.mem0.ai and sign up. Navigate to Settings → API Keys and create a new key. Save it somewhere safe — you'll need it in step 3.

Create Your Neon Database

Go to console.neon.tech and create a free project. Copy the connection string (starts with postgresql://). Then run this SQL in the Neon SQL Editor:

CREATE TABLE IF NOT EXISTS memory_events (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  client_id TEXT NOT NULL,
  content TEXT NOT NULL,
  tags TEXT[] NOT NULL DEFAULT '{}',
  datetime_created TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_memory_events_client ON memory_events(client_id);
CREATE INDEX idx_memory_events_datetime ON memory_events(datetime_created);
CREATE INDEX idx_memory_events_tags ON memory_events USING GIN(tags);

Install Python Dependencies

Run this in your terminal:

pip install mem0ai psycopg2-binary requests

Create the Mem0 Skill

Ask Claude Code to create the skill structure:

Create a mem0 skill at .claude/skills/mem0/ with:
- SKILL.md documenting all commands
- scripts/mem0_client.py wrapping the Mem0 API (search, add, update, delete, list)
- scripts/mem0_fetch.sh for formatted output
- Use MEM0_API_KEY from my .env file
- Entity scoping: user_id = client slug, agent_id = "my-agency"

Set Up the Neon MCP Server

Create an MCP server configuration that lets Claude query your Neon database. Add this to your Claude Code MCP settings:

Set up an MCP server for my Neon Postgres database.
Connection string: [YOUR_NEON_CONNECTION_STRING]
It should expose a "query" tool that accepts natural language
questions about the memory_events table and converts them to SQL.
Add it to my Claude Code MCP server configuration.

Create the Auto-Injection Hook

This hook automatically pulls client context into every conversation:

Create a UserPromptSubmit hook at .claude/hooks/on_client_context.py that:
1. Reads the user's prompt from stdin (JSON payload)
2. Checks if any known client slug appears in the prompt text
3. If found, calls mem0_client.py search with a broad query
4. Prints the results as a [mem0 context: slug] block to stdout
5. Register it in .claude/settings.json under hooks.UserPromptSubmit

Add Your API Keys

Add these to your project's .env file:

MEM0_API_KEY=your_mem0_api_key_here
NEON_DATABASE_URL=postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb

Test Everything

Verify each component works:

# Test mem0
python3 .claude/skills/mem0/scripts/mem0_client.py add \
  --user-id test_client --content "Test memory entry"

python3 .claude/skills/mem0/scripts/mem0_client.py search \
  --user-id test_client --query "test" --top-k 3

# Test Neon (in Claude Code)
# Ask: "What events are stored for test_client?"

# Test hook (mention a client in your next prompt)
# You should see [mem0 context: ...] auto-injected

Common Issues & Fixes

"ModuleNotFoundError: No module named 'mem0'"

The pip install went to a different Python than Claude Code uses. Fix:

python3 -m pip install mem0ai psycopg2-binary requests

If that doesn't work, check which Python Claude Code runs:

which python3
# Then install to THAT specific python:
/usr/local/bin/python3 -m pip install mem0ai

Hook doesn't fire / no mem0 context injected

Check that the hook is registered in .claude/settings.json:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "type": "command",
        "command": "python3 .claude/hooks/on_client_context.py"
      }
    ]
  }
}

Also verify the hook script is executable and handles stdin correctly. Test it directly:

echo '{"prompt":"Tell me about test_client"}' | python3 .claude/hooks/on_client_context.py

Neon connection refused / SSL error

Neon requires SSL. Make sure your connection string includes ?sslmode=require:

postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require

If you're on a corporate network, check that port 5432 isn't blocked by a firewall.

Mem0 search returns empty results

Mem0 uses semantic search, not keyword matching. Try broader queries:

Instead of: "CPA target"
Try: "What are their advertising goals and budgets?"

Also check you're using the correct user_id. If you created the entity with a different name, both the slug and the original name should be tried:

# Try both:
python3 .claude/skills/mem0/scripts/mem0_client.py search \
  --user-id my_client --query "everything about this client"

python3 .claude/skills/mem0/scripts/mem0_client.py list \
  --user-id my_client --limit 50

MCP server not showing in Claude Code

After adding the MCP server config, restart Claude Code completely (not just a new conversation). Check the MCP server is running:

# In Claude Code, type:
/mcp

# You should see your memory server listed
# If not, check .claude/settings.json for correct MCP config

Python 3.9 compatibility errors

If you see errors about type hints, the scripts might be using Python 3.10+ syntax. Fix by replacing:

# Change this (3.10+):
def func(name: str | None = None) -> list[str]:

# To this (3.9 compatible):
from typing import Optional, List
def func(name: Optional[str] = None) -> List[str]:

Built by Icarus Growth — AI operations consulting for agencies & service businesses