Safe Memory: Privacy & Compliance (Python)
Build AI agents that respect user privacy and meet GDPR requirements. Learn secure memory patterns in Python.
Why Privacy Matters for AI Memory
AI agents with persistent memory are powerful—but with great power comes great responsibility. When your agent remembers user preferences, decisions, and context, you're handling personal data that falls under privacy regulations like GDPR, CCPA, and others.
Building privacy into your memory architecture isn't just about compliance—it's about building trust. Users who know their data is handled responsibly are more likely to share the context that makes your agent truly useful.
The Privacy Principles for AI Memory
Before diving into code, let's establish the core principles that should guide your memory implementation:
- Data Minimization: Only store what you actually need
- Purpose Limitation: Use memories only for their intended purpose
- Storage Limitation: Delete data when it's no longer needed
- Transparency: Users should know what's stored about them
- User Control: Enable access, correction, and deletion rights
Memory Classification by Sensitivity
Not all memories carry the same privacy risk. Classifying data by sensitivity helps you apply appropriate protections.
from enum import Enum
from pydantic import BaseModel, Field
from datetime import datetime, timedelta
class SensitivityLevel(str, Enum):
PUBLIC = "public" # Non-personal, shareable
INTERNAL = "internal" # User-specific but not sensitive
CONFIDENTIAL = "confidential" # Personal preferences, decisions
RESTRICTED = "restricted" # PII, credentials, health data
class SecureMemory(BaseModel):
id: str
content: str
sensitivity: SensitivityLevel
user_id: str
purpose: str # Why this memory exists
legal_basis: str # GDPR: consent, legitimate_interest, etc.
retention_days: int # Auto-delete after this period
created_at: datetime = Field(default_factory=datetime.utcnow)
@property
def expires_at(self) -> datetime:
return self.created_at + timedelta(days=self.retention_days) Implementing GDPR Rights in Python
GDPR grants users specific rights over their data. Here's how to implement the key ones in your memory system.
Right to Access (Article 15)
Users can request all data you have about them. Implement a comprehensive export function.
async def export_user_data(user_id: str) -> dict:
"""Export all memories for a user in a portable format."""
memories = await memory_store.find_by_user(user_id)
return {
"export_date": datetime.utcnow().isoformat(),
"user_id": user_id,
"memory_count": len(memories),
"memories": [
{
"id": m.id,
"content": m.content,
"type": m.sensitivity,
"purpose": m.purpose,
"created": m.created_at.isoformat(),
"expires": m.expires_at.isoformat()
}
for m in memories
]
} Right to Erasure (Article 17)
The "right to be forgotten" requires complete deletion of user data when requested.
async def delete_user_data(user_id: str, reason: str) -> dict:
"""Permanently delete all memories for a user."""
memories = await memory_store.find_by_user(user_id)
count = len(memories)
# Delete from primary store
await memory_store.delete_many(user_id)
# Delete from vector embeddings
await vector_store.delete_by_user(user_id)
# Log deletion for audit (without PII)
await audit_log.record({
"action": "user_data_deletion",
"user_id_hash": hash_user_id(user_id),
"memory_count": count,
"reason": reason,
"timestamp": datetime.utcnow()
})
return {"deleted": count, "status": "complete"} Right to Rectification (Article 16)
Users can correct inaccurate data. Track corrections for transparency.
async def correct_memory(
memory_id: str,
user_id: str,
new_content: str,
correction_reason: str
) -> SecureMemory:
"""Update a memory with correction tracking."""
memory = await memory_store.get(memory_id)
if memory.user_id != user_id:
raise PermissionError("Cannot modify another user's memory")
# Store correction history
memory.metadata["corrections"] = memory.metadata.get("corrections", [])
memory.metadata["corrections"].append({
"previous": memory.content,
"corrected_at": datetime.utcnow().isoformat(),
"reason": correction_reason
})
memory.content = new_content
memory.updated_at = datetime.utcnow()
return await memory_store.save(memory) Automatic Data Retention
Implement automated cleanup to enforce retention policies. This prevents data hoarding and reduces compliance risk.
async def cleanup_expired_memories() -> int:
"""Run periodically to enforce retention policies."""
expired = await memory_store.find_expired(before=datetime.utcnow())
for memory in expired:
await memory_store.delete(memory.id)
await vector_store.delete(memory.id)
return len(expired)
# Schedule with APScheduler or similar
# scheduler.add_job(cleanup_expired_memories, 'cron', hour=3) Encryption at Rest
Sensitive memories should be encrypted before storage. Here's a pattern using Fernet symmetric encryption.
from cryptography.fernet import Fernet
class EncryptedMemoryStore:
def __init__(self, key: bytes):
self.cipher = Fernet(key)
def encrypt_content(self, content: str) -> str:
return self.cipher.encrypt(content.encode()).decode()
def decrypt_content(self, encrypted: str) -> str:
return self.cipher.decrypt(encrypted.encode()).decode()
async def save(self, memory: SecureMemory) -> SecureMemory:
if memory.sensitivity in [SensitivityLevel.CONFIDENTIAL,
SensitivityLevel.RESTRICTED]:
memory.content = self.encrypt_content(memory.content)
memory.metadata["encrypted"] = True
return await self.store.save(memory) Consent Management
Track user consent for different types of memory storage. Never store memories without proper legal basis.
class ConsentManager:
async def can_store_memory(
self,
user_id: str,
memory_type: str,
sensitivity: SensitivityLevel
) -> bool:
consent = await self.get_user_consent(user_id)
# Check if user has consented to this type of storage
if sensitivity == SensitivityLevel.RESTRICTED:
return consent.get("explicit_sensitive", False)
return consent.get("memory_storage", False)
async def record_consent(
self,
user_id: str,
consent_type: str,
granted: bool
) -> None:
await self.consent_store.save({
"user_id": user_id,
"type": consent_type,
"granted": granted,
"timestamp": datetime.utcnow(),
"ip_hash": get_anonymized_ip()
}) Audit Logging
Maintain audit trails for compliance verification without storing additional PII.
async def log_memory_access(
user_id: str,
memory_id: str,
action: str,
context: str
) -> None:
"""Log access without storing identifiable data."""
await audit_store.save({
"user_hash": hashlib.sha256(user_id.encode()).hexdigest()[:16],
"memory_hash": hashlib.sha256(memory_id.encode()).hexdigest()[:16],
"action": action,
"context_category": context, # e.g., "code_review", not actual content
"timestamp": datetime.utcnow()
}) Build Trustworthy AI Agents
Privacy-respecting AI memory isn't just about avoiding fines—it's about building the kind of agent that users feel comfortable sharing context with. When users trust that their data is handled responsibly, they provide richer information, leading to better agent performance.
CodeMem handles these compliance patterns out of the box: encryption at rest, automatic retention enforcement, GDPR rights endpoints, and audit logging. You focus on your agent's capabilities while we handle the security infrastructure.