Thank you for your interest in contributing to EMK (Episodic Memory Kernel)! This document provides guidelines and instructions for contributing.
- Code of Conduct
- Getting Started
- Development Setup
- Making Changes
- Pull Request Process
- Coding Standards
- Testing
- Documentation
By participating in this project, you agree to maintain a respectful and inclusive environment. Be kind, be constructive, and be patient with others.
- Python 3.8 or higher
- Git
- A GitHub account
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR-USERNAME/emk.git cd emk - Add the upstream remote:
git remote add upstream https://github.com/imran-siddique/emk.git
# Create virtual environment
python -m venv venv
# Activate it
# On Windows:
venv\Scripts\activate
# On macOS/Linux:
source venv/bin/activate# Install package in editable mode with dev dependencies
pip install -e ".[dev]"
# Or install all optional dependencies
pip install -e ".[all,dev]"# Run tests
pytest tests/ -v
# Check code style
black --check .
ruff check .
# Run type checking
mypy emk/Create a descriptive branch name:
git checkout -b feature/add-redis-adapter
git checkout -b fix/episode-id-collision
git checkout -b docs/improve-readmeFollow the Conventional Commits specification:
feat: add Redis storage adapter
fix: resolve episode ID collision on rapid creation
docs: add ChromaDB usage examples
test: add integration tests for FileAdapter
refactor: simplify Indexer tag extraction
chore: update dependencies
Each commit should represent a single logical change. If you're fixing multiple issues, make multiple commits.
-
Update your fork with the latest upstream changes:
git fetch upstream git rebase upstream/main
-
Push your branch to your fork:
git push origin feature/your-feature
-
Open a Pull Request on GitHub with:
- Clear title describing the change
- Description of what and why
- Reference to any related issues
- Screenshots/examples if applicable
-
Address review feedback promptly and push updates
-
Squash commits if requested before merge
- Tests pass locally (
pytest tests/ -v) - Code is formatted (
black .) - Linting passes (
ruff check .) - Type hints added for new code
- Docstrings added/updated
- Documentation updated if needed
- CHANGELOG updated for significant changes
We follow PEP 8 with these tools:
- Black for code formatting (line length: 100)
- Ruff for linting
- mypy for type checking
All public functions must have type hints:
from typing import List, Optional, Dict, Any
def store(self, episode: Episode, embedding: Optional[np.ndarray] = None) -> str:
"""Store an episode and return its ID."""
...Use Google-style docstrings:
def generate_episode_tags(episode: Episode) -> List[str]:
"""
Generate searchable tags from an episode.
Args:
episode: The episode to generate tags from.
Returns:
List of tags for indexing.
Raises:
ValueError: If episode content is empty.
Example:
>>> episode = Episode(goal="Test", action="Run", result="Pass", reflection="Good")
>>> tags = generate_episode_tags(episode)
>>> print(tags)
['test', 'run', 'pass', 'good']
"""
...- Standard library imports
- Third-party imports
- Local imports
from datetime import datetime
from typing import List, Optional
import numpy as np
from pydantic import BaseModel
from emk.schema import Episode# Run all tests
pytest tests/ -v
# Run with coverage
pytest tests/ -v --cov=emk --cov-report=html
# Run specific test file
pytest tests/test_schema.py -v
# Run specific test
pytest tests/test_schema.py::test_episode_immutability -v- Place tests in the
tests/directory - Name test files
test_*.py - Name test functions
test_* - Use descriptive test names that explain what's being tested
def test_episode_id_is_deterministic_for_same_content():
"""Episodes with identical content should have identical IDs."""
episode1 = Episode(
goal="Test",
action="Run",
result="Pass",
reflection="Good",
timestamp=datetime(2026, 1, 1, tzinfo=timezone.utc)
)
episode2 = Episode(
goal="Test",
action="Run",
result="Pass",
reflection="Good",
timestamp=datetime(2026, 1, 1, tzinfo=timezone.utc)
)
assert episode1.episode_id == episode2.episode_idAim for >80% code coverage. Critical paths (schema, storage) should have >95%.
Update README.md if you:
- Add new features
- Change public API
- Add new dependencies
- Change installation instructions
All public classes, methods, and functions need docstrings.
Add examples to examples/ for significant new features.
When contributing, keep these principles in mind:
- Immutability: Episodes are append-only and cannot be modified
- Minimal Dependencies: Core functionality should require minimal packages
- No Smart Logic: EMK stores and retrieves; it doesn't summarize or interpret
- Type Safety: Use type hints everywhere
- Backward Compatibility: Don't break existing APIs without deprecation
- Open a GitHub Issue for bugs or feature requests
- Start a Discussion for questions
By contributing to EMK, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to EMK! 🎉