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.
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.
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.
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 |
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 |
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.
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