Thank you for your interest in contributing to Papr Memory! This guide will help you get started with contributing to our intelligent memory management system.
- Code of Conduct
- Getting Started
- Development Setup
- Code Style Guidelines
- Pull Request Process
- Testing
- Adding New Features
- Documentation
- Community
By participating in this project, you agree to abide by our Code of Conduct:
- Be respectful: Treat everyone with respect and kindness
- Be inclusive: Welcome contributors of all backgrounds and experience levels
- Be collaborative: Work together towards common goals
- Be constructive: Provide helpful feedback and suggestions
- Be patient: Remember that everyone is learning and growing
Before contributing, ensure you have:
- Python 3.8+ installed
- Docker & Docker Compose (recommended for development)
- Git for version control
- OpenAI API Key for core functionality testing
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/memory.git cd memory - Set up the development environment:
cp .env.example .env # Edit .env with your configuration docker compose up -d - Create a feature branch:
git checkout -b feature/your-feature-name
# Start all services
docker compose up -d
# View logs
docker compose logs -f web
# Run tests inside container
docker compose exec web pytest
# Access shell
docker compose exec web bash# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Start services (MongoDB, Neo4j, Redis, Qdrant, Parse Server)
docker compose up -d mongodb neo4j redis qdrant parse-server
# Run the application
python main.pyFor a broader, forward-looking view of what we are building across applications, SDKs, intelligence layer, memory tiers, and storage backends, see the Vision Architecture diagram in README.md.
graph TB
subgraph Vision
I1[Memory Cortex]
I2[Durable Execution]
T0[Tier-0: Working]
T1[Tier-1: Episodic]
T2[Tier-2: Vector]
T3[Tier-3: Graph]
B1[MongoDB]
B2[Qdrant]
B3[Neo4j]
end
I1 --> I2
I1 --> T0 --> B1
I1 --> T1 --> B1
I1 --> T2 --> B2
I1 --> T3 --> B3
- Copy environment file:
cp .env.example .env - Required variables for development:
OPENAI_API_KEY=your-openai-api-key PARSE_SERVER_APPLICATION_ID=papr-app-id PARSE_SERVER_MASTER_KEY=papr-master-key
- Database URLs (when using Docker):
MONGODB_URL=mongodb://admin:password@localhost:27017/papr_memory?authSource=admin NEO4J_URL=bolt://localhost:7687 REDIS_URL=redis://:password@localhost:6379/0 QDRANT_URL=http://localhost:6333
We follow PEP 8 with some modifications:
# Use Black formatting
black .
# Line length: 88 characters (Black default)
# Use type hints for function parameters and return values
def process_memory(content: str, user_id: str) -> Dict[str, Any]:
"""Process a memory item and return metadata."""
pass
# Use descriptive variable names
memory_content = "Important meeting notes"
user_session_token = "abc123"
# Use docstrings for functions and classes
class MemoryManager:
"""Manages memory storage and retrieval operations."""
def add_memory(self, content: str) -> str:
"""Add a new memory and return its ID.
Args:
content: The memory content to store
Returns:
The unique memory ID
"""
pass├── main.py # FastAPI application entry point
├── app_factory.py # Application factory and configuration
├── routes/ # API route definitions
│ ├── memory_routes.py # Memory-related endpoints
│ └── user_routes.py # User management endpoints
├── models/ # Pydantic models and data structures
├── services/ # Business logic and external integrations
├── datastore/ # Database connection and utilities
├── utils/ # Utility functions and helpers
└── tests/ # Test files
# Standard library imports
import asyncio
import logging
from datetime import datetime
from typing import Dict, List, Optional
# Third-party imports
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
# Local imports
from models.memory_models import MemoryRequest
from services.memory_service import MemoryService# Use specific exception types
try:
result = await memory_service.process_memory(content)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except MemoryNotFoundError as e:
raise HTTPException(status_code=404, detail="Memory not found")
except Exception as e:
logger.error(f"Unexpected error: {e}")
raise HTTPException(status_code=500, detail="Internal server error")-
Test your changes:
# Run all tests pytest # Run specific test categories pytest tests/unit/ pytest tests/integration/ # Check code coverage pytest --cov=./ --cov-report=html
-
Format your code:
# Format with Black black . # Sort imports isort . # Run linting flake8 .
-
Update documentation if needed
- Branch naming: Use descriptive names like
feature/add-vector-searchorfix/memory-deletion-bug - Commit messages: Write clear, descriptive commit messages
- Tests: Add tests for new functionality
- Documentation: Update documentation for new features
- Breaking changes: Note any breaking changes in the PR description
- Environment variables: Update
.env.exampleif new variables are added
type(scope): short description
Longer description if needed
Fixes #123
Types: feat, fix, docs, style, refactor, test, chore
Examples:
feat(memory): add vector similarity search
fix(auth): resolve session token validation issue
docs(api): update endpoint documentation
test(memory): add unit tests for memory creation
## Description
Brief description of changes made.
## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests added/updatedtests/
├── unit/ # Unit tests for individual functions
│ ├── test_memory_service.py
│ └── test_auth_utils.py
├── integration/ # Integration tests for API endpoints
│ ├── test_memory_api.py
│ └── test_user_api.py
├── fixtures/ # Test data and fixtures
└── conftest.py # Pytest configuration
# Unit test example
import pytest
from services.memory_service import MemoryService
@pytest.fixture
def memory_service():
return MemoryService()
def test_process_memory_valid_input(memory_service):
"""Test memory processing with valid input."""
content = "Test memory content"
result = memory_service.process_memory(content)
assert result is not None
assert "memory_id" in result
assert result["content"] == content
def test_process_memory_empty_content(memory_service):
"""Test memory processing with empty content."""
with pytest.raises(ValueError, match="Content cannot be empty"):
memory_service.process_memory("")# Integration test example
import pytest
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_create_memory_endpoint():
"""Test memory creation via API."""
response = client.post(
"/v1/memories",
json={"content": "Test memory", "type": "text"},
headers={"X-API-Key": "test-key"}
)
assert response.status_code == 200
data = response.json()
assert "memory_id" in data# Run all tests
pytest
# Run with verbose output
pytest -v
# Run specific test file
pytest tests/unit/test_memory_service.py
# Run tests with coverage
pytest --cov=./ --cov-report=html
# Run only fast tests (exclude integration)
pytest -m "not integration"- Create an issue describing the feature
- Discuss the approach with maintainers
- Create a feature branch:
git checkout -b feature/feature-name - Implement the feature:
- Add models (if needed)
- Implement business logic
- Add API endpoints
- Write tests
- Update documentation
- Test thoroughly
- Submit a pull request
- Keep features focused: One feature per PR
- Maintain backward compatibility when possible
- Add comprehensive tests
- Update documentation
- Consider performance implications
- Follow existing patterns
# RESTful endpoint design
@app.post("/v1/memories") # Create memory
@app.get("/v1/memories/{id}") # Get specific memory
@app.put("/v1/memories/{id}") # Update memory
@app.delete("/v1/memories/{id}") # Delete memory
@app.get("/v1/memories/search") # Search memories
# Use Pydantic models for request/response
class MemoryRequest(BaseModel):
content: str
type: MemoryType = MemoryType.TEXT
metadata: Optional[MemoryMetadata] = None
class MemoryResponse(BaseModel):
memory_id: str
content: str
created_at: datetime
updated_at: Optional[datetime] = None- Code comments: Explain complex logic
- Docstrings: Document functions and classes
- README updates: Keep setup instructions current
- API documentation: Auto-generated from Pydantic models
- Architecture docs: High-level system design
def search_memories(
query: str,
user_id: str,
limit: int = 10,
offset: int = 0
) -> List[MemorySearchResult]:
"""Search memories using semantic similarity.
Performs vector similarity search across user's memories
and returns ranked results based on semantic relevance.
Args:
query: Search query string
user_id: ID of the user performing the search
limit: Maximum number of results to return (default: 10)
offset: Number of results to skip for pagination (default: 0)
Returns:
List of MemorySearchResult objects ordered by relevance
Raises:
ValueError: If query is empty or user_id is invalid
MemoryServiceError: If search operation fails
Example:
>>> results = search_memories("meeting notes", "user123", limit=5)
>>> print(f"Found {len(results)} memories")
"""
pass- Database changes: Consider migration scripts
- API versioning: Use
/v1/,/v2/for breaking changes - Configuration: Add new environment variables to
.env.example - Dependencies: Update
requirements.txtand Docker files - Monitoring: Add logging and health checks
- Security: Review authentication and authorization needs
- Database queries: Use pagination and indexing
- Memory usage: Be mindful of large data processing
- Async operations: Use async/await for I/O operations
- Caching: Leverage Redis for frequently accessed data
- Vector operations: Optimize embedding and search operations
- Search existing issues to avoid duplicates
- Try to reproduce the issue consistently
- Check the latest version to see if it's already fixed
## Bug Description
Clear description of what the bug is.
## Steps to Reproduce
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected Behavior
What you expected to happen.
## Actual Behavior
What actually happened.
## Environment
- OS: [e.g. Ubuntu 20.04]
- Python Version: [e.g. 3.9.7]
- Docker Version: [e.g. 20.10.8]
## Additional Context
Any other context about the problem.- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Questions and general discussion
- Discord: Real-time chat and community support (https://discord.gg/sWpR5a3H)
- Check the documentation first
- Search existing issues and discussions
- Ask in discussions for general questions
- Create an issue for bugs or feature requests
We appreciate all contributions! Contributors are recognized in:
- CONTRIBUTORS.md file
- Release notes for significant contributions
- GitHub contributor graphs
- Community highlights in our documentation
By contributing to Papr Memory, you agree that your contributions will be licensed under the GNU Affero General Public License v3.0.
Thank you for contributing to Papr Memory! 🚀
Your contributions help build a better memory management system for everyone. If you have any questions, don't hesitate to ask in our discussions or reach out to the maintainers.