Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Latest commit

 

History

History
295 lines (210 loc) · 6.52 KB

File metadata and controls

295 lines (210 loc) · 6.52 KB

Contributing to EMK

Thank you for your interest in contributing to EMK (Episodic Memory Kernel)! This document provides guidelines and instructions for contributing.

📋 Table of Contents

Code of Conduct

By participating in this project, you agree to maintain a respectful and inclusive environment. Be kind, be constructive, and be patient with others.

Getting Started

Prerequisites

  • Python 3.8 or higher
  • Git
  • A GitHub account

Fork and Clone

  1. Fork the repository on GitHub
  2. Clone your fork locally:
    git clone https://github.com/YOUR-USERNAME/emk.git
    cd emk
  3. Add the upstream remote:
    git remote add upstream https://github.com/imran-siddique/emk.git

Development Setup

Create a Virtual Environment

# Create virtual environment
python -m venv venv

# Activate it
# On Windows:
venv\Scripts\activate
# On macOS/Linux:
source venv/bin/activate

Install Development Dependencies

# Install package in editable mode with dev dependencies
pip install -e ".[dev]"

# Or install all optional dependencies
pip install -e ".[all,dev]"

Verify Installation

# Run tests
pytest tests/ -v

# Check code style
black --check .
ruff check .

# Run type checking
mypy emk/

Making Changes

Branch Naming

Create a descriptive branch name:

git checkout -b feature/add-redis-adapter
git checkout -b fix/episode-id-collision
git checkout -b docs/improve-readme

Commit Messages

Follow 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

Keep Commits Atomic

Each commit should represent a single logical change. If you're fixing multiple issues, make multiple commits.

Pull Request Process

  1. Update your fork with the latest upstream changes:

    git fetch upstream
    git rebase upstream/main
  2. Push your branch to your fork:

    git push origin feature/your-feature
  3. 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
  4. Address review feedback promptly and push updates

  5. Squash commits if requested before merge

PR Checklist

  • 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

Coding Standards

Style Guide

We follow PEP 8 with these tools:

  • Black for code formatting (line length: 100)
  • Ruff for linting
  • mypy for type checking

Type Hints

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."""
    ...

Docstrings

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']
    """
    ...

Import Order

  1. Standard library imports
  2. Third-party imports
  3. Local imports
from datetime import datetime
from typing import List, Optional

import numpy as np
from pydantic import BaseModel

from emk.schema import Episode

Testing

Running Tests

# 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

Writing Tests

  • 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_id

Test Coverage

Aim for >80% code coverage. Critical paths (schema, storage) should have >95%.

Documentation

README Updates

Update README.md if you:

  • Add new features
  • Change public API
  • Add new dependencies
  • Change installation instructions

Docstring Updates

All public classes, methods, and functions need docstrings.

Example Updates

Add examples to examples/ for significant new features.

Design Principles

When contributing, keep these principles in mind:

  1. Immutability: Episodes are append-only and cannot be modified
  2. Minimal Dependencies: Core functionality should require minimal packages
  3. No Smart Logic: EMK stores and retrieves; it doesn't summarize or interpret
  4. Type Safety: Use type hints everywhere
  5. Backward Compatibility: Don't break existing APIs without deprecation

Questions?

License

By contributing to EMK, you agree that your contributions will be licensed under the MIT License.


Thank you for contributing to EMK! 🎉