MCAL: Memory-Context Alignment Layer
Intent-Preserving Memory for Goal-Coherent AI Agents
Why MCAL?
Current AI memory systems store facts but lose meaning:
| What's Stored | What's Lost |
|---|---|
| "User chose PostgreSQL" | WHY they chose it over MongoDB |
| "User wants to visit Japan" | HOW this fits their overall travel goals |
MCAL preserves the reasoning behind decisions, not just the conclusions.
Installation
pip install mcal-ai
Framework integrations:
pip install mcal-ai-langgraph # LangGraph integration
pip install mcal-ai-crewai # CrewAI integration
pip install mcal-ai-autogen # AutoGen integration
Quick Start
import asyncio
from mcal import MCAL
async def main():
mcal = MCAL(llm_provider="anthropic") # or "openai", "bedrock"
messages = [
{"role": "user", "content": "I'm building a fraud detection pipeline"},
{"role": "assistant", "content": "Let's start with data ingestion..."},
{"role": "user", "content": "I chose PostgreSQL over MongoDB for storage"},
]
# Extract goals, decisions, and reasoning
result = await mcal.add(messages, user_id="user_123")
print(f"Extracted {result.unified_graph.node_count} nodes")
# Search with goal-aware retrieval
results = await mcal.search("What database?", user_id="user_123")
# Get context for LLM prompts
context = await mcal.get_context("What's next?", user_id="user_123")
asyncio.run(main())
Key Features
- Intent Graph — Hierarchical goal structures (Mission → Goal → Task)
- Reasoning Chains — Store WHY decisions were made, not just conclusions
- Goal-Aware Retrieval — Retrieve based on objective alignment, not just similarity
- Extraction Profiles —
decision(rationale/alternatives/trade-offs),conversational(preferences/relationships),comprehensive(both) - Hybrid Retrieval — Graph traversal + ChunkStore embedding search for maximum recall
- Multi-Provider — Works with Anthropic, OpenAI, and AWS Bedrock
- Standalone Storage — Built-in JSON and SQLite persistence, no external services needed
- Thread-Safe — Safe for concurrent multi-user access
- Tiered Models — Fast/smart model routing for cost-efficient extraction
- Extraction Cache — Skip redundant LLM calls with per-turn cache hits
- Graph Compaction — Automatic deduplication with FACT/PERSON node protection
- GDPR-Ready — Full user data erasure with
clear_user_data()
Configuration
mcal = MCAL(
llm_provider="bedrock", # "openai", "anthropic", or "bedrock"
anthropic_api_key="sk-ant-...", # Or set ANTHROPIC_API_KEY env var
openai_api_key="sk-...", # Or set OPENAI_API_KEY env var
storage_path="~/.mcal", # Persistent storage location
enable_persistence=True, # Cross-session persistence (default)
max_graph_nodes=500, # Max nodes per user graph
# Extraction profiles — choose the right depth for your domain
extraction_profile="decision", # "decision", "conversational", "comprehensive"
# Hybrid retrieval — embedding search over raw text chunks
enable_chunk_store=True, # Combine graph + chunk retrieval
chunk_size=512, # Tokens per chunk
chunk_overlap=64, # Overlap between chunks
max_chunks_per_user=1000, # Max chunks stored per user
# Bedrock options
bedrock_model="llama-3.3-70b", # Default extraction model
bedrock_region="us-east-1", # AWS region
# Tiered model routing (fast for simple, smart for complex)
enable_tiered_extraction=True,
bedrock_fast_model="llama-3.1-8b",
bedrock_smart_model="llama-3.3-70b",
# Extraction cache
enable_extraction_cache=True, # Skip repeated LLM calls (default)
cache_ttl_seconds=86400, # Cache lifetime (default: 24h)
# Graph compaction
compaction_policy="moderate", # "none", "moderate", or "aggressive"
compaction_interval=10, # Compact every N turns
)
LangGraph Integration
from mcal import MCAL
from mcal_langgraph import MCALMemory, MCALMemoryConfig, MCALStore
# Declarative config — all Bedrock/tiered params supported
config = MCALMemoryConfig(
llm_provider="bedrock",
bedrock_model="llama-3.3-70b",
bedrock_region="us-east-1",
enable_tiered_extraction=True,
enable_persistence=True,
)
# Or create directly
mcal = MCAL(llm_provider="bedrock")
memory = MCALMemory(mcal=mcal, user_id="user_123")
# Use as LangGraph BaseStore
store = MCALStore(mcal)
# Memory accepts both LangChain Message objects and plain dicts
await memory.add([
{"role": "user", "content": "We chose Kafka for event streaming"},
{"role": "assistant", "content": "Good choice for high throughput."},
])
# Search returns goal-aware results
results = await memory.search("streaming architecture")
User Data Management
# Full user data erasure (GDPR Article 17 compliant)
await mcal.clear_user_data("user_123")
# Removes all files, graphs, caches, and in-memory state for the user
# In-memory-only mode — zero disk writes
mcal = MCAL(
llm_provider="openai",
storage_path="/tmp/session",
enable_persistence=False, # No files written to disk
)
Environment Variables
# Choose your LLM provider
ANTHROPIC_API_KEY=sk-ant-... # For Claude
OPENAI_API_KEY=sk-... # For GPT-4 / embeddings
# Optional: AWS Bedrock
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_DEFAULT_REGION=us-east-1
MCAL auto-detects API keys from environment variables when not passed explicitly.
Benchmark Results
MCAL has been evaluated on two benchmarks spanning 150 to 1020+ conversation turns:
| Metric | CTO-150 | CTO-300 | CTO-1020 | LoCoMo-10 (1,540 QA) |
|---|---|---|---|---|
| Decision Retention (DRR) | 93.3% | 94.4% | 89.9% | — |
| Cross-Era Recall | — | — | 84.4% | — |
| Token Reduction | 66% | 79% | 91% | 84% |
| Cost Savings | — | 85% | 95% | — |
| LoCoMo-10 Accuracy | — | — | — | 46.1% |
| LLM-Judged Quality (J-Score) | — | — | — | 80% of full-context |
- DRR = keyword-matched probe scoring across all decisions in the conversation
- Cross-era recall = early-session decisions still retrievable after 34 sessions (1020 turns)
- Query-aware subgraph retrieval improved DRR by 4.5pp at 1020 turns while reducing context tokens by 53%
- CTO-300 multi-run: 88.8% ± 2.4% across 3 temperatures × 3 repetitions (9 runs)
- LoCoMo-10: 46.1% overall (single-hop 63.5%, temporal 25.5%, multi-hop 31.2%, open-domain 49.8%)
What's New in 0.5.0
- Query-Aware Subgraph Retrieval — New seed-and-expand pipeline replaces 6 query-blind retrieval paths with a single query-aware pass. Semantic FAISS search finds seed nodes, then 1-hop BFS expansion pulls in connected decisions, goals, and facts. Reduces context tokens by 53% at 1020 turns while improving DRR by 4.5pp.
QuerySubgraphdataclass — New public API for structured subgraph results, partitioned by node type (goals, decisions, facts, entities, actions) with structural edge resolution.- Adjacency index — Lazy-built bidirectional adjacency index on
UnifiedGraphenables O(1) neighbor lookups for graph traversal. Automatically invalidated on edge mutations. get_neighbors()method — BFS traversal returning neighbor IDs and connecting edges within configurable hop distance, with optional edge-type filtering.- Improved DRR at scale — CTO-1020 DRR improved from 85.3% to 89.9% (+4.6pp); CTO-300 improved from 92.2% to 94.4% (+2.2pp). Cross-era recall: 84.4% of decisions from 300+ turns earlier remain accessible.
- LoCoMo-10 Evaluation — Full 10-conversation, 1,540 QA binary evaluation: 46.1% overall accuracy (single-hop 63.5%, temporal 25.5%, multi-hop 31.2%, open-domain 49.8%).
What's New in 0.4.1
- First-Class FACT Nodes (#143) — 3 new typed edges (
measures,evidence_for,quantifies) replace genericrelatesedges on FACT nodes, improving edge degree from 1 to 2-4 edges per fact - Importance Scoring Boost — FACT nodes with concrete numeric values get a +2.0 scoring bonus, making quantitative facts more retrievable
- Query-Aware Fact Retrieval — Quantitative queries ("how much", "what cost", "what percentage") automatically double the fact retrieval budget
search_facts()API — New method onUnifiedGraphfor filtering facts by category and value range- Richer FACT Formatting — Context assembly now includes value/unit annotations on fact entries
- Version Metadata Fix — Integration packages now report correct
__version__(was stuck at 0.2.9)
What's New in 0.4.0
- Graph Compaction Fixes (#141, #142) — Improved retrieval quality with facts-in-context, expanded edge types, and chunk boost scoring
- CTO-1020 Benchmark — First 1000+ turn evaluation: 85.3% DRR, 95.6% cross-era recall, 88% token reduction
- Statistical Rigor — Multi-run validation with Fisher's exact test (p < 0.05), Wilson score confidence intervals
- LLM-Judged Probes — J-Score evaluation (1-5 scale) complements keyword DRR for nuanced quality measurement
Older releases
What's New in 0.3.0
- Expanded Relationship Edge Types — 10 new edge types (
family,friend,colleague,knows,likes,dislikes,prefers,lives_in,works_at,scheduled) for richer social and personal relationship graphs - Key Facts & Entities in Search Context —
search()now surfaces extracted facts and background entities directly inresult.context, improving answer quality for factual queries - Improved Chunk Retrieval — ChunkStore search returns more results (k=10) with equal weighting to graph results, and conversation excerpts are prioritized in context assembly
- Higher Extraction Fidelity — Increased message processing window preserves more content per extraction batch, reducing information loss during ingestion
What's New in 0.2.9
- Configurable Extraction Profiles (#139) — Choose
decision,conversational, orcomprehensiveprofiles to optimize extraction for your domain - Hybrid Retrieval with ChunkStore (#138) — Optional
enable_chunk_store=Trueadds embedding-based retrieval over raw text chunks alongside graph search - FACT/PERSON Node Protection (#140) — Graph compaction now preserves FACT and PERSON nodes that anchor information (numeric values, names, roles)
What's New in 0.2.7
- GDPR-compliant data erasure —
clear_user_data()now removes the entire user directory from disk - Dict-format message support —
MCALMemoryaccepts plain dicts alongside LangChain Message objects - In-memory-only mode —
enable_persistence=Falseguarantees zero disk writes - Full
MCALMemoryConfig— Declarative config now supports all Bedrock, tiered model, persistence, and cache parameters - Tiered routing accuracy — Complexity classifier routes on raw user messages for reliable fast/smart splits
- Extraction cache per-turn support — Cache hits work with agents that pass one turn at a time
Documentation
License
MIT License — see LICENSE for details.
Author
Created by Shiva Koreddi
Release files for mcal-ai 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcal_ai-0.5.0.tar.gz | 116.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcal_ai-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 237.4 kB
Release files / mcal_ai-0.5.0.tar.gz
| Download URL | mcal_ai-0.5.0.tar.gz |
|---|---|
| Size | 116.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
091cd851e78b5792ef5fdabab21897814cbe4415687b8fd6d8aa2a65a315f817
|
|
BLAKE2b-256 checksum How to use checksums |
a6c81c641dd58c4bd3b45277f34207dce0aaa10aaf4de023efb0ce8e1e84360a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.11
|
Release files / mcal_ai-0.5.0-py3-none-any.whl
| Download URL | mcal_ai-0.5.0-py3-none-any.whl |
|---|---|
| Size | 120.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c47316f1dbca52f8b85e1c5ad107ee0a811340d820a799ab83d4a0e1606f43ef
|
|
BLAKE2b-256 checksum How to use checksums |
150440bc00851646a75f51f8be710ae92f4bfa163d0880bed1b4e7fd97f04732
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.11
|