a2a-memory
v0.8.1
Published
Persistent AI memory for Claude Code - Session extraction, local DB, and hook automation
Maintainers
Readme
@a2a/memory - Persistent AI Memory for Claude Code
v0.6.0 — Local-first memory system with server sync, team collaboration, and intelligent search
Persistent AI memory for Claude Code. Automatically captures, stores, and retrieves knowledge across coding sessions.
Features
Core Capabilities
- Session Extraction - Extract memories from Claude Code sessions (JSONL parsing)
- Local-First DB - SQLite with FTS5 full-text search + vector similarity
- Auto-Capture Hooks - Claude Code hooks for automatic memory capture
- Context Injection - Inject relevant memories at session start (hybrid search)
- Hybrid Search - FTS + Vector + Recency ranking (Reciprocal Rank Fusion)
- Lifecycle Management - Quality scoring, TTL-based cleanup, memory tiering (Hot/Warm/Cold)
AI & Embeddings
- LLM Integration - AI-powered extraction and classification (OpenAI, Anthropic)
- Embeddings - Local TF-IDF (64D) or OpenAI (1536D) embeddings
- Vector Quantization - Float32 and Int8 scalar quantization for compression
Team & Sync
- Server Sync - Synchronize with A2A server via REST API
- Team Collaboration - Share memories across team members (CRDT vector clocks)
- E2E Encryption - AES-256-GCM encryption for sensitive content
- Scheduled Sync - Automatic periodic sync with configurable interval
- OS Keychain - Secure API key storage (macOS/Linux/Windows)
Developer Experience
- CLAUDE.md Sync - Sync CLAUDE.md sections to memory DB
- CLI (16 commands) - Full command-line interface for all operations
- Logging - JSON Lines hook logs with rotation and level filtering
- i18n - Internationalization support (Korean, English)
- Sensitive Info Filter - Auto-redaction of API keys, passwords, tokens (21 patterns)
Quick Start
# Install globally
npm install -g a2a-memory
# Initialize (creates DB + registers Claude Code hooks)
a2a-memory setup
# Extract memories from existing sessions
a2a-memory extract --limit 20
# Check status
a2a-memory status
# Search memories
a2a-memory search "authentication error"
# Health check
a2a-memory healthCLI Commands
| Command | Description | Options |
|---------|-------------|---------|
| a2a-memory setup | Initialize plugin, create DB, register hooks | - |
| a2a-memory status | Show memory count, DB size, category breakdown | - |
| a2a-memory extract | Extract memories from session files | --limit <n>, --project <path> |
| a2a-memory search <query> | Hybrid search across all memories | --limit <n>, --category <cat> |
| a2a-memory list | List memories with category/tier filters | --category, --tier, --limit |
| a2a-memory add | Manually add a memory (interactive) | - |
| a2a-memory edit <id> | Edit an existing memory (interactive) | - |
| a2a-memory rm <id> | Delete a memory | - |
| a2a-memory config | View and modify configuration | get <key>, set <key> <value> |
| a2a-memory sync | Synchronize with A2A server | --push, --pull, --watch, --interval <ms> |
| a2a-memory team | Team memory management | join <teamId>, sync, members |
| a2a-memory embed | Manage embeddings | generate, stats |
| a2a-memory cleanup | Remove low-quality/expired memories | --dry-run |
| a2a-memory health | System health check (DB, config, logs) | --verbose |
| a2a-memory claude-sync | Sync CLAUDE.md to memory DB | --dry-run, --force |
Architecture
1. Claude Code Hooks
After a2a-memory setup, three hooks are registered:
| Hook | Trigger | Action | Features | |------|---------|--------|----------| | SessionStart | Session begins | Injects relevant memories via hybrid search | Team memory pull, context injection | | PostToolUse | After Write/Edit/Bash | Auto-captures significant actions | Significance scoring, sensitive info filtering | | SessionEnd | Session ends | Extracts memories + optional team sync | Session summarization, team push, scheduled sync |
2. Memory Extraction
Parses ~/.claude/projects/<project>/<session>.jsonl files and extracts:
| Category | Examples |
|----------|---------|
| error_solution | Error + resolution pairs |
| code_pattern | Repeated tool usage patterns |
| decision | Architectural decisions with reasoning |
| project_knowledge | Project context and rules |
| convention | Development conventions and preferences |
3. Hybrid Search
Three-signal Reciprocal Rank Fusion (RRF):
Score = w1 * FTS_rank + w2 * Vector_similarity + w3 * Recency_score- FTS: SQLite FTS5 full-text search
- Vector: TF-IDF (local, 64D) or OpenAI (1536D) embeddings
- Recency: Time decay scoring
4. Storage & Indexing
- SQLite database at
~/.a2a/memory.db- FTS5 full-text search index
- Vector embeddings table (with quantization support)
- WAL mode for concurrent access
- Sync status tracking with CRDT vector clocks
- Memory Tiering: Hot (0-7 days), Warm (8-30 days), Cold (30+ days)
- Vector Quantization: Float32 (50% reduction), Int8 (75% reduction)
- E2E Encryption: AES-256-GCM with PBKDF2 key derivation
Configuration
Config file: ~/.a2a/config.json
{
"mode": "local",
"autoCapture": {
"enabled": false,
"triggers": ["Write", "Edit", "Bash"],
"significanceThreshold": 0.6
},
"autoInject": {
"enabled": true,
"maxMemories": 5,
"maxTokens": 2000
},
"autoSync": {
"enabled": false,
"pushOnSessionEnd": true,
"pullOnSessionStart": true,
"timeoutMs": 10000,
"intervalMs": 1800000
},
"db": {
"path": "~/.a2a/memory.db",
"maxSizeMB": 100
},
"embedding": {
"provider": "local",
"dimensions": 64
},
"lifecycle": {
"enabled": true,
"maxMemories": 10000,
"ttlDays": { "working": 7, "episodic": 90 },
"minQualityScore": 0.3
},
"logging": {
"enabled": false,
"level": "info",
"outputDir": "~/.a2a/logs",
"maxFileSizeMB": 10,
"maxFiles": 3
}
}Server Sync
# Configure server
a2a-memory config set server.url https://your-a2a-server.com
a2a-memory config set server.apiKey your-api-key
# One-time sync
a2a-memory sync --push # local -> remote
a2a-memory sync --pull # remote -> local
# Continuous sync (every 30 min)
a2a-memory sync --watch
a2a-memory sync --watch --interval 60000 # every 60sTeam Mode
# Join a team
a2a-memory team join my-team
# Sync team memories
a2a-memory team sync
# List team members
a2a-memory team membersCLAUDE.md Sync
# Sync CLAUDE.md sections to memory DB
a2a-memory claude-sync
# Preview without writing
a2a-memory claude-sync --dry-run
# Force re-sync
a2a-memory claude-sync --forceProgrammatic API
import {
// Core
MemoryDatabase,
ConfigManager,
extractMemories,
// Search
HybridRanker,
createEmbeddingProvider,
// Sync
A2AClient,
MemorySynchronizer,
TeamSynchronizer,
SyncScheduler,
// Lifecycle
cleanupMemories,
rebalanceTiers,
// Encryption
encryptContent,
decryptContent,
// Claude.md
syncClaudeMd,
} from 'a2a-memory';
// Database operations
const db = new MemoryDatabase('~/.a2a/memory.db');
db.initialize();
db.createMemory({
content: 'JWT tokens expire after 30 minutes',
category: 'convention',
tier: 'semantic',
tags: ['auth', 'jwt'],
});
// Hybrid search with embeddings
const provider = createEmbeddingProvider({ provider: 'local', dimensions: 64 });
const ranker = new HybridRanker(db, provider);
const ranked = await ranker.search('auth error', { limit: 5 });
// Server sync
const client = new A2AClient({
serverUrl: 'https://a2a-api-production-8d17.up.railway.app',
apiKey: 'your-api-key',
});
const sync = new MemorySynchronizer(db, client);
await sync.push();
await sync.pull();
// Scheduled sync
const scheduler = new SyncScheduler(sync, { intervalMs: 1800000 });
scheduler.start();
// Team collaboration
const teamSync = new TeamSynchronizer(db, client, 'team-id');
await teamSync.pushTeamMemories();
await teamSync.pullTeamMemories();
// Lifecycle management
await cleanupMemories(db, { ttlDays: 90, minQualityScore: 0.3 });
await rebalanceTiers(db);
// Anthropic Memory API adapter (for future integration)
import { toAnthropicFormat, fromAnthropicFormat } from 'a2a-memory';
const memory = db.getMemory('mem_123');
const anthropicFormat = toAnthropicFormat(memory);
// → { id, content, type: 'user_preference' | 'learned_info' | 'conversation_context', ... }
const anthropicMemory = { id: '...', content: '...', type: 'learned_info', ... };
const a2aInput = fromAnthropicFormat(anthropicMemory);
db.createMemory(a2aInput);Security
Sensitive Information Protection
Automatically filters 21 patterns including:
- Cloud provider keys (AWS, Google, Azure)
- API keys and secrets (OpenAI, Stripe, GitHub)
- Database connection strings
- Private keys and certificates (RSA, EC, DSA)
- JWT tokens and session cookies
- Personal identifiable information (Korean SSN, Business registration)
Encryption
E2E Encryption (opt-in via config):
a2a-memory config set autoSync.encryption.enabled true- Algorithm: AES-256-GCM
- Key derivation: PBKDF2-HMAC-SHA256 (600,000 iterations)
- Storage: OS keychain integration (macOS, Linux, Windows)
- Scope: Content + embeddings encrypted before transmission
API Key Storage
Uses OS-native secure storage:
- macOS: Keychain (
securitycommand) - Linux: Secret Service API (
secret-tool) - Windows: Credential Manager (via
node-keytar)
Fallback: Encrypted file storage at ~/.a2a/credentials.enc
Requirements
- Node.js >= 18.0.0
- Claude Code (for hooks integration)
License
MIT
