Best Practices
Learn best practices for using the Memory Scope API in production. These guidelines will help you build secure, performant, and maintainable applications.
API Key Management
- Never commit API keys to version control
- Use environment variables for API keys
- Rotate API keys regularly
- Use different keys for different environments
- Monitor API key usage for suspicious activity
User ID Consistency
- Use consistent user_id format across all operations
- Don't use personally identifiable information (PII) in user_id
- Use a stable identifier that doesn't change
Revocation Token Security
- Store revocation tokens securely
- Associate tokens with user sessions
- Never expose tokens in URLs or logs
- Provide users with UI to revoke access
Choose the Right Scope
Select the scope that best fits your use case. This affects policy enforcement and merging behavior.
# Good: Using appropriate scope
client.create_memory(
user_id="user123",
scope="preferences", # Correct scope for user likes/dislikes
domain="food",
value_json={"likes": ["pizza"]}
)
# Bad: Using wrong scope
client.create_memory(
user_id="user123",
scope="constraints", # Wrong scope - constraints are for rules, not preferences
domain="food",
value_json={"likes": ["pizza"]}
)Use Domains for Organization
Domains help organize memories within a scope. Use them consistently.
# Good: Using domains consistently
client.create_memory(
user_id="user123",
scope="preferences",
domain="food", # Consistent domain for food preferences
value_json={"likes": ["pizza"]}
)
client.create_memory(
user_id="user123",
scope="preferences",
domain="music", # Different domain for music preferences
value_json={"likes": ["jazz"]}
)Use Descriptive Purposes
Write clear, descriptive purpose strings that accurately explain why you're accessing the memory.
# Good: Clear, descriptive purpose
result = client.read_memory(
user_id="user123",
scope="preferences",
domain="food",
purpose="generate personalized food recommendations for user dashboard"
)
# Bad: Vague purpose
result = client.read_memory(
user_id="user123",
scope="preferences",
domain="food",
purpose="read data" # Too vague
)Handle Policy Denials Gracefully
Policy denials are expected in some cases. Always handle them gracefully.
from memory_scope.exceptions import PolicyDeniedError
try:
result = client.read_memory(
user_id="user123",
scope="preferences",
domain="food",
purpose="execute task to auto-order lunch"
)
except PolicyDeniedError:
# Handle gracefully - this is expected behavior
# Use default values or ask user for permission
result = {"likes": [], "dislikes": []} # FallbackUse max_age_days Appropriately
Filter out stale memories to improve performance and relevance.
# Good: Filtering stale data
result = client.read_memory(
user_id="user123",
scope="preferences",
domain="food",
purpose="generate food recommendations",
max_age_days=30 # Only get recent preferences
)Cache Responses When Appropriate
Cache API responses to reduce the number of requests, but respect revocation tokens.
# Cache responses with appropriate TTL
cache_key = f"memory:{user_id}:{scope}:{domain}"
cached_result = cache.get(cache_key)
if cached_result is None:
result = client.read_memory(...)
# Cache for 5 minutes
cache.set(cache_key, result, ttl=300)
else:
result = cached_resultAlways Handle Errors
Implement comprehensive error handling for all API operations.
from memory_scope.exceptions import (
PolicyDeniedError,
InvalidRequestError,
AuthenticationError,
RateLimitError
)
try:
result = client.read_memory(...)
except PolicyDeniedError as e:
# Handle policy denial
logger.info(f"Policy denied: {e.message}")
result = get_default_preferences()
except RateLimitError as e:
# Handle rate limit with retry
logger.warning(f"Rate limit: {e.message}")
time.sleep(60)
result = client.read_memory(...) # Retry
except AuthenticationError as e:
# Handle auth error
logger.error(f"Auth error: {e.message}")
raise
except Exception as e:
# Handle unexpected errors
logger.error(f"Unexpected error: {e}")
raiseProvide User Control
- Always provide users with a way to revoke access
- Show clear messages when data is unavailable
- Handle empty results gracefully
- Respect user privacy choices
Use Confidence Scores
Consider confidence scores when making decisions based on merged results. Low confidence may indicate incomplete data.
result = client.read_memory(...)
if result.confidence < 0.5:
# Low confidence - data may be incomplete
# Ask user to provide more information
show_preference_form()
else:
# High confidence - use the data
use_preferences(result.summary_struct)- API keys stored in environment variables
- Error handling implemented for all operations
- Rate limit handling with exponential backoff
- User revocation UI implemented
- Audit logs reviewed regularly
- Monitoring and alerting set up
- Test coverage for critical paths