-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
This guide walks you through setting up Agent Memory, integrating it with Claude Code, and using it to recall past conversations.
AI coding agents like Claude Code have a context window - they can only remember the current conversation. When you ask "what did we discuss about authentication last week?", the agent has no way to answer without scanning through potentially thousands of past conversation logs.
Current approaches are broken:
- Brute-force scanning - Loading entire conversation histories consumes tokens and is slow
- Vector search alone - Returns fragments without context or verification
- Manual search - Users have to dig through logs themselves
Agent Memory provides agentic search through progressive disclosure. Instead of loading everything, the agent navigates a time-based hierarchy:
Year (2026: "focus on authentication")
-> Month (January: "JWT implementation")
-> Week (Week 3: "token refresh logic")
-> Day (Thursday: "fixed expiration bug")
-> Segment (actual conversation excerpt)
At each level, the agent reads a summary and decides whether to drill down. This mirrors how humans search email - you filter by date, scan subjects, then open the relevant thread.
| Benefit | Description |
|---|---|
| Low token overhead | Navigate with ~500 tokens vs. 50,000+ for full scan |
| Verifiable answers | Every summary links to source conversations via "grips" |
| Automatic capture | Hooks record conversations passively - zero manual effort |
| Fast queries | RocksDB provides millisecond lookups |
| Private and local | All data stays on your machine |
- "What authentication approach did we decide on last week?"
- "Show me our discussion about database migration"
- "What was the solution to that JWT bug?"
- "Summarize what we worked on yesterday"
- "Find the conversation where we discussed Rust error handling"
Get up and running in 5 minutes.
- Rust 1.82+ with Cargo
- Claude Code (or another compatible AI coding agent)
- protoc (Protocol Buffers compiler)
# Check Rust version
rustc --version # Should be 1.82 or higher
# Check protoc
protoc --version# Clone the repository
git clone https://github.com/SpillwaveSolutions/agent-memory.git
cd agent-memory
# Build release binaries
cargo build --release
# Install to local bin directory
mkdir -p ~/.local/bin
cp target/release/memory-daemon ~/.local/bin/
cp target/release/memory-ingest ~/.local/bin/
# Add to PATH (add to your shell profile for persistence)
export PATH="$HOME/.local/bin:$PATH"
# Verify installation
memory-daemon --version# Start the memory daemon
memory-daemon start
# Verify it's running
memory-daemon statusYou should see:
Memory daemon is running (PID: 12345)
Copy the hooks configuration to capture conversations automatically:
# Create Claude Code hooks directory if it doesn't exist
mkdir -p ~/.claude
# Copy the example hooks configuration
cp examples/hooks.yaml ~/.claude/hooks.yamlThe hooks.yaml captures these events:
-
SessionStart/SessionEnd- Conversation lifecycle -
UserPromptSubmit- Your messages to Claude -
PostToolUse- Tool executions (file edits, commands) -
SubagentStart/SubagentStop- Multi-agent workflows
Test that events are being captured:
# Send a test event
echo '{"hook_event_name":"UserPromptSubmit","session_id":"test-123","message":"Hello world"}' | memory-ingest
# Expected output:
# {"continue":true}
# Check that the daemon received it
memory-daemon query --endpoint http://[::1]:50051 rootAfter some conversations have been captured:
# Get TOC root (year-level summaries)
memory-daemon query --endpoint http://[::1]:50051 root
# Navigate to a specific node
memory-daemon query --endpoint http://[::1]:50051 node --node-id "toc:year:2026"
# Browse children of a node
memory-daemon query --endpoint http://[::1]:50051 browse --parent-id "toc:month:2026-01" --limit 10Agent Memory uses a layered architecture optimized for agentic navigation.
+-------------------------------------------------------+
| AI Agent (Claude Code) |
+-------------------------------------------------------+
|
| gRPC (port 50051)
v
+-------------------------------------------------------+
| Memory Daemon |
| +-------------+ +-------------+ +---------------+ |
| | Ingestion | | Query | | TOC Builder | |
| | Service | | Service | | (Background) | |
| +-------------+ +-------------+ +---------------+ |
| | |
| +---------------------------------------------------+|
| | Storage Layer (RocksDB) ||
| | Events | TOC Nodes | Grips | Outbox | Checkpts ||
| +---------------------------------------------------+|
+-------------------------------------------------------+
^
| JSON events
+-------------------------------------------------------+
| memory-ingest |
| (CCH hook handler - reads from stdin) |
+-------------------------------------------------------+
^
| Hook events
+-------------------------------------------------------+
| Claude Code / AI Agent |
+-------------------------------------------------------+
-
Ingestion: Claude Code triggers hooks ->
memory-ingestreads event -> sends to daemon via gRPC -> stored in RocksDB -
TOC Building: Background job reads new events -> creates/updates time-based segments -> generates summaries with LLM -> stores TOC nodes and grips
-
Query: Agent requests TOC navigation -> daemon returns summaries and grips -> agent drills down to find answers
| Concept | Description |
|---|---|
| TOC (Table of Contents) | Time-based hierarchy: Year -> Month -> Week -> Day -> Segment |
| Node | A TOC entry with title, summary bullets, keywords, and child links |
| Grip | Links a summary bullet to the source conversation events |
| Event | An immutable record of a conversation turn |
| Segment | A chunk of related events within a time window |
The memory-ingest binary is a Claude Code Hooks (CCH) handler that:
- Receives JSON events from Claude Code via stdin
- Converts them to memory events
- Sends them to the daemon via gRPC
- Returns
{"continue":true}to allow Claude to proceed
Fail-open behavior: If the daemon is down, memory-ingest still returns success. Conversations continue uninterrupted - you just won't capture those events.
The example hooks.yaml (copy to ~/.claude/hooks.yaml):
version: "1.0"
settings:
# Always allow Claude to continue, even if memory system fails
fail_open: true
# Timeout for hook script (seconds)
script_timeout: 5
rules:
# Capture conversation events to agent-memory
- name: capture-to-memory
description: Send conversation events to agent-memory daemon for TOC-based recall
matchers:
operations:
# Session lifecycle
- SessionStart
- SessionEnd
# User interactions
- UserPromptSubmit
# Tool activity
- PostToolUse
# Subagent spawning
- SubagentStart
- SubagentStop
actions:
run: "~/.local/bin/memory-ingest"To also capture assistant responses (more verbose but complete):
rules:
- name: capture-to-memory
matchers:
operations:
- SessionStart
- SessionEnd
- UserPromptSubmit
- AssistantResponse # Add this for full responses
- PostToolUse
- SubagentStart
- SubagentStop
actions:
run: "~/.local/bin/memory-ingest"# 1. Ensure daemon is running
memory-daemon status
# 2. Start a Claude Code session
# (have a conversation)
# 3. Check for captured events
memory-daemon query --endpoint http://[::1]:50051 root
# 4. If no events, check manually
echo '{"hook_event_name":"SessionStart","session_id":"test"}' | memory-ingestWhen the memory-query plugin is installed, you can use these slash commands in Claude Code.
Search past conversations for a specific topic:
/memory-search authentication
/memory-search "JWT tokens" --period "last week"
/memory-search database --period january
What it does:
- Checks daemon status
- Gets TOC root to find available periods
- Navigates to relevant time period
- Searches node summaries for matching keywords
- Presents results with grip IDs for drill-down
Output format:
## Memory Search: authentication
### Week of January 20-26, 2026
**Summary:** JWT token implementation, OAuth2 provider integration
**Excerpts:**
- "Implemented JWT token refresh logic" `grip:1706540400000:01HN4QXKN6`
- "Fixed OAuth2 callback URL handling" `grip:1706540500000:01HN4QXYZ`
---
Expand any excerpt: /memory-context grip:IDShow recent conversation summaries:
/memory-recent
/memory-recent --days 3
/memory-recent --days 14 --limit 20
What it does:
- Gets TOC root to find current year
- Navigates to current period (month, week)
- Collects day nodes within the specified range
- Presents summaries with timestamps
Output format:
## Recent Conversations (Last 7 Days)
### January 30, 2026
**Topics:** rust, grpc, rocksdb
**Segments:**
1. **10:00** - Memory daemon implementation
- Implemented gRPC service `grip:...`
- Added RocksDB storage layer `grip:...`
---
Total: 8 segments across 5 daysGet full conversation context around a specific excerpt:
/memory-context grip:1706540400000:01HN4QXKN6YWXVKZ3JMHP4BCDE
/memory-context grip:... --before 5 --after 5
What it does:
- Validates grip ID format
- Expands the grip to retrieve surrounding events
- Presents the conversation thread
Output format:
## Conversation Context
**Grip:** `grip:1706540400000:01HN4QXKN6YWXVKZ3JMHP4BCDE`
**Timestamp:** January 29, 2026 10:00:00
### Before (3 events)
| Role | Message |
|------|---------|
| user | How do we handle authentication? |
| assistant | We have several options... |
| user | Let's go with JWT |
### Excerpt (Referenced)
> Implemented JWT token refresh logic
### After (3 events)
| Role | Message |
|------|---------|
| assistant | I've added the refresh endpoint... |
| user | What about the race condition? |
| assistant | Good catch, we need a mutex... || Command | Description |
|---|---|
memory-daemon start |
Start the daemon |
memory-daemon stop |
Stop the daemon |
memory-daemon status |
Check if daemon is running |
memory-daemon query root |
Get year-level TOC nodes |
memory-daemon query node --node-id ID |
Get specific TOC node |
memory-daemon query browse --parent-id ID |
Browse children |
memory-daemon query expand --grip-id ID |
Expand a grip |
memory-daemon admin stats |
Show storage statistics |
memory-daemon admin compact |
Compact the database |
Check what's in memory:
memory-daemon query --endpoint http://[::1]:50051 rootNavigate the TOC:
# Start at year
memory-daemon query --endpoint http://[::1]:50051 node --node-id "toc:year:2026"
# Drill to month
memory-daemon query --endpoint http://[::1]:50051 node --node-id "toc:month:2026-01"
# Browse weeks in that month
memory-daemon query --endpoint http://[::1]:50051 browse --parent-id "toc:month:2026-01" --limit 10Get raw events from a time range:
# Last hour
NOW=$(date +%s)000
HOUR_AGO=$(( $(date +%s) - 3600 ))000
memory-daemon query --endpoint http://[::1]:50051 events --from $HOUR_AGO --to $NOW --limit 50Check storage health:
memory-daemon admin --db-path ~/.memory-store statsSettings are loaded with this precedence (highest to lowest):
-
CLI flags -
memory-daemon start --port 50052 -
Environment variables -
MEMORY_PORT=50052 -
Config file -
~/.config/agent-memory/config.toml - Built-in defaults
| Variable | Description | Default |
|---|---|---|
MEMORY_PORT |
gRPC server port | 50051 |
MEMORY_DB_PATH |
RocksDB directory | ~/.memory-store |
MEMORY_LOG_LEVEL |
Log level (trace, debug, info, warn, error) | info |
MEMORY_GRPC_HOST |
gRPC host binding | 0.0.0.0 |
MEMORY_ENDPOINT |
Endpoint for memory-ingest | http://[::1]:50051 |
Create ~/.config/agent-memory/config.toml:
# Storage location
db_path = "~/.memory-store"
# gRPC server settings
grpc_port = 50051
grpc_host = "0.0.0.0"
# Log level
log_level = "info"
# Multi-agent mode: "separate" (per-project) or "unified" (shared with tags)
multi_agent_mode = "separate"
# Summarizer configuration
[summarizer]
provider = "openai" # "openai", "anthropic", or "local"
model = "gpt-4o-mini" # Model name
# api_key loaded from OPENAI_API_KEY or ANTHROPIC_API_KEY env var
# api_base_url = "https://custom-endpoint.com/v1" # Optional custom endpointThe summarizer generates TOC node summaries from raw events.
OpenAI (recommended for cost/speed):
export OPENAI_API_KEY="sk-..."Config:
[summarizer]
provider = "openai"
model = "gpt-4o-mini"Anthropic:
export ANTHROPIC_API_KEY="sk-ant-..."Config:
[summarizer]
provider = "anthropic"
model = "claude-3-haiku-20240307"Local (Ollama):
[summarizer]
provider = "local"
model = "llama3.2"
api_base_url = "http://localhost:11434/v1"Cause: Binary not in PATH
Fix:
# Add to PATH
export PATH="$HOME/.local/bin:$PATH"
# Or use full path
~/.local/bin/memory-daemon statusCause: Daemon not running
Fix:
# Check status
memory-daemon status
# Start if needed
memory-daemon start
# If status shows running but connection fails, check port
lsof -i :50051Cause: Port 50051 is taken
Fix:
# Find what's using the port
lsof -i :50051
# Kill it or use different port
memory-daemon start --port 50052
# Update memory-ingest endpoint
export MEMORY_ENDPOINT="http://[::1]:50052"Cause: CCH hooks not configured or daemon not running during conversation
Fix:
# Check hooks file exists
cat ~/.claude/hooks.yaml
# Verify memory-ingest is findable
which memory-ingest
# Test manually
echo '{"hook_event_name":"SessionStart","session_id":"test"}' | memory-ingest
# Check daemon
memory-daemon statusCause: Missing or invalid API key
Fix:
# Check if key is set
echo ${OPENAI_API_KEY:+set}
echo ${ANTHROPIC_API_KEY:+set}
# Set the key
export OPENAI_API_KEY="sk-..."
# Restart daemon to pick up new key
memory-daemon stop && memory-daemon startQuick diagnostic:
# All-in-one health check
echo "=== Status ===" && memory-daemon status && \
echo "=== Port ===" && lsof -i :50051 && \
echo "=== Query ===" && memory-daemon query --endpoint http://[::1]:50051 root && \
echo "=== Hooks ===" && grep memory-ingest ~/.claude/hooks.yaml 2>/dev/null || echo "No hook"Storage health:
memory-daemon admin --db-path ~/.memory-store stats| Platform | Log Path |
|---|---|
| macOS | ~/Library/Logs/memory-daemon/daemon.log |
| Linux | ~/.local/state/memory-daemon/daemon.log |
Enable debug logging:
MEMORY_LOG_LEVEL=debug memory-daemon startRestart daemon:
memory-daemon stop && sleep 2 && memory-daemon startClear stale PID:
# macOS
rm -f ~/Library/Application\ Support/memory-daemon/daemon.pid
# Linux
rm -f ~/.local/state/memory-daemon/daemon.pid
memory-daemon startRun compaction (if slow or large):
memory-daemon admin --db-path ~/.memory-store compactFix permissions:
chmod 700 ~/.memory-store ~/.config/agent-memoryNow that Agent Memory is running:
-
Have some conversations - Start using Claude Code normally. Events will be captured automatically.
-
Wait for TOC building - The daemon builds TOC nodes in the background. After a few minutes, you should see summaries.
-
Try a query - Ask Claude "what did we discuss recently?" or use
/memory-search. -
Install the plugin - For the best experience, install the memory-query plugin from the Claude Code marketplace.
-
Explore the CLI - Use
memory-daemon querycommands to understand the data structure.
For more details, see:
- API Reference - gRPC service definitions
- Architecture - Deep dive into internals
- Usage Guide - Advanced CLI usage