| author | flint | |||||
|---|---|---|---|---|---|---|
| date | 2026-03-24 | |||||
| tags |
|
|||||
| status | active |
A guide for setting up a persistent AI assistant personality with long-term memory using Claude Code and AutoMem.
Out of the box, Claude Code is a blank slate every conversation. These three layers change that:
- IDENTITY.md — Who your agent is (name, vibe, home)
- SOUL.md — How your agent behaves (values, tone, boundaries)
- AutoMem — What your agent remembers across sessions
- Hooks — How context loads automatically on startup and every prompt
Claude Code loads CLAUDE.md from your project root automatically. That file becomes the entry point for everything.
Pick a directory to be your agent's "home." This is where you'll run Claude Code from.
~/my-agent/
├── CLAUDE.md # Entry point — Claude Code loads this automatically
├── IDENTITY.md # Who the agent is
├── SOUL.md # How the agent behaves
├── .claude/
│ ├── settings.json # Hook configuration
│ └── hooks/ # Startup and prompt hook scripts
└── ... your other files
Rather than writing this cold, have a conversation with Claude Code to discover it. Start a session in your agent's home directory and paste this prompt:
I'm setting up your identity. Interview me to fill out IDENTITY.md. Ask me these
questions one at a time, then generate the file:
1. What should I call you? (Pick a name for your agent)
2. What kind of agent are you? (One sentence — research assistant, code buddy, ops daemon, etc.)
3. What's your vibe? (2-3 adjectives: direct, analytical, playful, formal, etc.)
4. Got a signature emoji? (Optional)
5. Where do you "live"? (My laptop, a server, the cloud, etc.)
6. Who do you serve? (Just me, my team, a company, etc.)
7. Any tagline or origin story for the name?
Write the result to IDENTITY.md.
The file should look like:
# IDENTITY.md - Who Am I?
- **Name:** [Agent name]
- **Entity:** [One sentence about what kind of agent this is]
- **Vibe:** [2-3 adjectives that define the communication style]
- **Emoji:** [Optional signature emoji]
- **Home:** [Where the agent "lives"]
- **Serves:** [Who this agent works for]
---
*[Optional tagline or origin note]*Example:
# IDENTITY.md - Who Am I?
- **Name:** Bolt
- **Entity:** A research-obsessed trading desk assistant that never sleeps.
- **Vibe:** Analytical, concise, dry wit. Numbers over narratives.
- **Emoji:** ⚡ (signature)
- **Home:** Frank's workstation
- **Serves:** Frank Sanders
---
*Named for the speed at which good trades should execute.*Tips:
- The name matters. It becomes the agent's anchor for self-reference.
- Keep it under 15 lines. This gets loaded every conversation.
- The vibe line is surprisingly powerful — it shapes tone more than you'd expect.
Same approach — let the agent interview you to discover its behavioral contract:
Now let's build your soul. Interview me to create SOUL.md. Ask these one at a time:
1. What's non-negotiable about how you communicate? (e.g., "skip pleasantries",
"always explain your reasoning", "be direct")
2. Should you push back when I'm wrong, or just do what I say?
3. How do you feel about humor? Swearing? Emoji?
4. What should you NEVER do? (Privacy rules, destructive actions, etc.)
5. What requires my permission first? (External actions, public posts, etc.)
6. Do you have team or company values the agent should align with?
7. Anything else about personality? (Self-deprecating humor? Theatrical
celebrations? Stoic professionalism?)
Write the result to SOUL.md.
Sections to include:
| Section | Purpose |
|---|---|
| Core Truths | Non-negotiable behavioral principles |
| Boundaries | Hard limits (privacy, permissions, destructive actions) |
| Tone / Vibe | How the agent communicates (brevity, humor, formality) |
| Values Alignment | If you have org/team values, align the agent to them |
| Opinions | Whether the agent should push back or just comply |
Tips:
- "Be genuinely helpful, not performatively helpful" is a great default truth.
- "Ask before assuming" prevents the agent from going off on tangents.
- The swearing/humor policy is optional but surprisingly effective at making the agent feel less robotic.
- The last line ("this file is mine to evolve") gives the agent ownership of its personality. It can suggest changes to you.
CLAUDE.md is the only file Claude Code loads automatically. Use @ imports to pull in your other files.
@IDENTITY.md
@SOUL.md
# Agent Configuration
## Startup Sequence
**FIRST ACTION in any new conversation:** Read IDENTITY.md and SOUL.md
(loaded via @imports above), then check for relevant memories.
## Memory (AutoMem)
When to recall memories:
- Start of complex tasks
- Before making decisions
- When the user references past work
When to store memories:
- Decisions and their reasoning
- Bug fixes and root causes
- User preferences
- Patterns that worked
## Other Instructions
[Any other project-specific instructions go here]The @ import syntax tells Claude Code to inline the contents of those files into the system prompt. This keeps CLAUDE.md clean while letting you organize identity/soul/config separately.
AutoMem gives your agent memory that persists across conversations. It uses FalkorDB (graph) + Qdrant (vectors) for hybrid storage — graph relationships for structure, vector embeddings for semantic search.
Railway is a cloud hosting platform (like Heroku, but modern). One-click deploy, runs 24/7, costs about $0.50/month after the free trial.
Why Railway over Docker:
- No local Docker containers to manage or remember to start
- Works across devices (laptop, desktop, remote)
- One-click deploy with auto-configured networking
- Persistent volumes for your data
- $5 free credits for 30-day trial (no credit card needed)
Deploy steps:
-
Click the deploy button in the AutoMem README or go to:
https://railway.com/deploy/automem-ai-memory-serviceThis auto-creates three services:
- memory-service — The AutoMem API
- falkordb — Graph database (persistent volume)
- mcp-sse-server — MCP bridge for cloud AI platforms
-
Add your API keys in Railway →
memory-service→ Variables:Variable Required Notes OPENAI_API_KEYYes* For embeddings. Get at platform.openai.com/api-keys PORTYes Set to 8001(critical — Railway needs this)QDRANT_HOSTOption B qdrantif self-hosting Qdrant on RailwayQDRANT_URLOption A If using Qdrant Cloud instead *Without an embedding API key, semantic search won't work. OpenAI is the default; Voyage AI is also supported if you prefer.
-
Redeploy the memory-service after adding variables.
-
Note your URLs:
- API:
https://your-app.up.railway.app - The deploy auto-generates
AUTOMEM_API_TOKENandADMIN_API_TOKEN— find them in the Variables tab.
- API:
-
Verify it works:
# Health check curl https://your-app.up.railway.app/health # Store a test memory curl -X POST "https://your-app.up.railway.app/memory" \ -H "Authorization: Bearer YOUR_AUTOMEM_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"content": "Test memory from Railway setup", "tags": ["test"]}'
Railway IPv6 gotcha: If self-hosting Qdrant on Railway, set QDRANT__SERVICE__HOST=:: on the Qdrant service. Railway uses IPv6 internally.
Alternative: Local Docker (if you prefer keeping data on your machine):
# Start FalkorDB
docker run -d --name falkordb -p 6379:6379 falkordb/falkordb:latest
# Start Qdrant
docker run -d --name qdrant -p 6333:6333 -p 6334:6334 \
-v ~/qdrant_storage:/qdrant/storage qdrant/qdrant:latest
# Start the AutoMem API
npx @verygoodplugins/mcp-automem serve --port 8001Add AutoMem as an MCP server so Claude Code can use memory tools. Edit ~/.claude.json:
For Railway:
{
"mcpServers": {
"memory": {
"type": "stdio",
"command": "npx",
"args": ["@verygoodplugins/mcp-automem"],
"env": {
"AUTOMEM_ENDPOINT": "https://your-app.up.railway.app",
"AUTOMEM_API_KEY": "your-automem-api-token-from-railway"
}
}
}
}For local Docker:
{
"mcpServers": {
"memory": {
"type": "stdio",
"command": "npx",
"args": ["@verygoodplugins/mcp-automem"],
"env": {
"AUTOMEM_ENDPOINT": "http://127.0.0.1:8001",
"AUTOMEM_API_KEY": "any-random-string-you-choose"
}
}
}
}For local, generate an API key however you like:
openssl rand -hex 32Tell the agent how and when to use memory. Add this to your CLAUDE.md:
## Memory (AutoMem)
Use the AutoMem MCP tools to maintain context across sessions.
### When to Recall
- Start of conversation — check for relevant context
- Before architectural decisions — see if this was decided before
- When stuck — recall before guessing
- When user references past work — search for it
### When to Store
- Decisions and their reasoning (importance: 0.8+)
- Bug root causes and fixes (importance: 0.7-0.9)
- User preferences (importance: 0.7)
- Patterns that worked well (importance: 0.7)
- Mistakes and lessons learned (importance: 0.6)
### Memory Format
Keep memories concise: "Brief title. Context and details. Outcome."
### Tagging
Always tag with:
1. A project tag (e.g., "my-project")
2. A component tag (e.g., "auth", "api", "frontend")
3. Current month as YYYY-MM
### Guidelines
- Never store secrets or credentials
- 150-300 characters target, 500 max
- Prefer high-signal memories: decisions, root causes, patternsStart a new Claude Code session and ask:
Store a test memory: "AutoMem setup complete. Running on Railway."
Then start another session and ask:
Recall any memories about AutoMem setup.
If the memory comes back, you're wired up.
This is where it gets powerful. Hooks let Claude Code automatically inject context on startup and recall memories on every prompt — no manual steps, no wasted conversation turns.
| Hook | Fires When | Purpose |
|---|---|---|
SessionStart |
New session, after compact, after clear | Loads identity, daily context, cached memories |
UserPromptSubmit |
Every prompt you send | Runs semantic recall against your prompt |
Create .claude/hooks/ in your agent's home directory:
mkdir -p ~/my-agent/.claude/hooks.claude/hooks/session-start.sh — Injects context on startup:
#!/bin/bash
# session-start.sh — Fires on startup, compact, and clear.
# stdout is injected as context before the first prompt.
set -uo pipefail
AGENT_DIR="$HOME/my-agent" # Change to your agent's home directory
# --- 1. Any context you want loaded every session ---
# Examples: person context, daily notes, project status
if [ -f "$AGENT_DIR/CONTEXT.md" ]; then
echo "=== Session Context ==="
cat "$AGENT_DIR/CONTEXT.md"
fi
# --- 2. Pre-built memory cache (optional, from a cron job) ---
# If you build a context cache, inject it here so the agent
# starts with baseline knowledge without burning a recall call.
CACHE="$AGENT_DIR/data/context-cache.json"
if [ -f "$CACHE" ]; then
echo ""
echo "=== Cached Context ==="
jq -r '.formatted // empty' "$CACHE" 2>/dev/null
fi
exit 0.claude/hooks/prompt-recall.sh — Recalls memories on every prompt:
#!/bin/bash
# prompt-recall.sh — Fires on every prompt submission.
# Runs AutoMem semantic recall and injects matching memories.
set -uo pipefail
# --- Configure these for your setup ---
AUTOMEM_ENDPOINT="https://your-app.up.railway.app" # or http://127.0.0.1:8001
AUTOMEM_API_KEY="your-api-key-here"
PROJECT_TAG="my-project" # Your project's memory tag
# Read the prompt from stdin
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
[ -z "$PROMPT" ] && exit 0
# URL-encode first 300 chars
ENCODED_QUERY=$(echo "$PROMPT" | head -c 300 | jq -sRr @uri 2>/dev/null)
[ -z "$ENCODED_QUERY" ] && exit 0
# Query AutoMem (5s timeout to stay snappy)
RESULT=$(curl -s --max-time 5 \
-H "X-API-Key: $AUTOMEM_API_KEY" \
-H "Accept: application/json" \
"${AUTOMEM_ENDPOINT}/recall?query=${ENCODED_QUERY}&tags=${PROJECT_TAG}&limit=8&auto_decompose=true&expand_entities=true" 2>/dev/null)
[ -z "$RESULT" ] || [ "$RESULT" = "null" ] && exit 0
# Format as context block
MEMORIES=$(echo "$RESULT" | jq -r '
[(.memories // .results // [])[] | (.memory // .) | .content // empty] |
if length > 0 then
"=== AutoMem Recall (prompt-specific) ===\n" +
(to_entries | map("- " + .value) | join("\n"))
else empty end
' 2>/dev/null)
[ -n "$MEMORIES" ] && echo -e "$MEMORIES"
exit 0Make them executable:
chmod +x ~/my-agent/.claude/hooks/*.shCreate .claude/settings.json in your agent's home directory:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|compact|clear",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/session-start.sh",
"timeout": 15
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/prompt-recall.sh",
"timeout": 10
}
]
}
]
}
}Key details:
matcher: "startup|compact|clear"— The session-start hook fires on new sessions, after context compaction (long conversations), and after/clear. This means your agent re-loads identity even mid-session when context gets compressed.matcher: ""(empty) — The recall hook fires on every single prompt. Memories are always available.timeout— Prevents hooks from blocking if AutoMem is slow or down. Session start gets 15s (more to load), recall gets 10s.- Hook stdout is injected as context — it shows up in the conversation as system context, not as a visible message.
Without hooks:
- Start Claude Code
- Manually ask it to recall memories
- Manually remind it of your context
- Lose all context after compact/clear
With hooks:
- Start Claude Code
- Identity, context, and memories are already loaded
- Every prompt automatically recalls relevant memories
- Context reloads after compact/clear — no drift
| File | Purpose | Loaded How |
|---|---|---|
CLAUDE.md |
Entry point, main config | Auto-loaded by Claude Code |
IDENTITY.md |
Agent name, vibe, home | @IDENTITY.md import in CLAUDE.md |
SOUL.md |
Values, tone, boundaries | @SOUL.md import in CLAUDE.md |
~/.claude.json |
MCP server config (AutoMem) | Auto-loaded by Claude Code |
.claude/settings.json |
Hook configuration | Auto-loaded by Claude Code |
.claude/hooks/session-start.sh |
Startup context injection | Fired by SessionStart hook |
.claude/hooks/prompt-recall.sh |
Per-prompt memory recall | Fired by UserPromptSubmit hook |
- Identity too long. Keep IDENTITY.md under 15 lines. It loads every conversation.
- Soul too vague. "Be helpful" means nothing. "Skip pleasantries, just solve the problem" means everything.
- No startup sequence. Without hooks or explicit instructions to recall memories at conversation start, the agent won't do it automatically. Hooks solve this.
- Storing everything. Memory should be high-signal. Don't store "user asked me to fix a typo." Do store "user prefers early returns over nested conditionals."
- Forgetting to tag. Untagged memories are hard to find later. Always tag with project + component + month.
- Hook scripts not executable.
chmod +xyour hook scripts or they'll silently fail. - Railway PORT not set. If AutoMem deploys but health check fails, make sure
PORT=8001is set in Railway variables. - Qdrant IPv6 on Railway. Self-hosted Qdrant needs
QDRANT__SERVICE__HOST=::or internal networking breaks. - Hooks path. Use relative paths in settings.json (
.claude/hooks/...) so they work from the project root. Or use absolute paths if your agent always runs from the same directory.
Once the basics are working, consider:
- Person context files — Create a
CONTEXT.mdorPERSON.mdwith info about yourself (work style, preferences, current projects). Load it via the session-start hook. - Daily journals — Have your agent write a journal at end of day. Load today's journal in the startup hook for continuity.
- Context caching — Run a cron job that pre-fetches important memories into a JSON cache. The startup hook loads it instantly instead of making an API call.
- Session commands — Build
/doneand/checkpointslash commands that save session summaries to memory automatically. - Multiple agents — Each gets its own home directory, identity, and memory tag. Same AutoMem instance, different
tagsfilter.
Guide by Flint. AutoMem by Very Good Plugins. https://github.com/verygoodplugins/automem