Contributing to Structum

Thank you for considering contributing to Structum! 🎉

We want to make contributing as easy and transparent as possible. This document outlines the process and guidelines.


🎯 Code of Conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.


🚀 Getting Started

Prerequisites

  • Python 3.11+

  • Git

  • uv (recommended) or pip

Development Setup

# 1. Clone repository
git clone https://github.com/PythonWoods/structum.git
cd structum

# 2. Install all packages + dev dependencies with uv (recommended)
uv sync --extra dev

# 3. Setup pre-commit hooks
pre-commit install

Note: uv sync --extra dev installs all workspace packages (packages/*) in editable mode plus development tools (mypy, ruff, black, pytest, etc.).

Alternative: Manual pip install

# If not using uv, you can install packages individually
pip install -e "packages/core[dev]"
pip install -e "packages/dynaconf"
pip install -e "packages/bootstrap"
# ... other packages as needed

🏷️ SPDX Headers & License Policy

Standard Header for New Files

All source files (.py, .toml, .yaml) MUST include SPDX headers:

# SPDX-FileCopyrightText: 2026 Your Name <your.email@example.com>
# SPDX-License-Identifier: Apache-2.0

Recommended: Use --auto to automatically detect your git config:

# Auto-detect from git config (user.name and user.email)
structum license add-header --auto path/to/newfile.py

# Automatically generates:
# SPDX-FileCopyrightText: 2026 Your Name <your@email.com>
# SPDX-License-Identifier: Apache-2.0

Alternative: Manual specification:

# Specify author explicitly
structum license add-header path/to/newfile.py \
  --author "Your Name" --email "your@email.com"

Default (core team only):

# Uses PythonWoods Team as copyright holder
structum license add-header path/to/newfile.py

Modifying Existing Files

When editing files created by others:

  • Small changes (< 10 lines): Keep existing headers unchanged

  • Substantial contributions (refactors, new features): Add your copyright line

# SPDX-FileCopyrightText: 2026 PythonWoods Team
# SPDX-FileCopyrightText: 2026 Your Name <your.email@example.com>
# SPDX-License-Identifier: Apache-2.0

Verify Compliance

Before submitting a PR:

# Check all files have proper SPDX headers
structum license check

# Expected: ✅ All files are properly licensed!

See: License Management Guide for complete policy.


📋 How to Contribute

Reporting Bugs

Use the Bug Report template:

  1. Search existing issues first

  2. Use the bug report template

  3. Include minimal reproduction

  4. Specify environment details

Suggesting Features

Use the Feature Request template:

  1. Check the Roadmap first

  2. Describe the problem clearly

  3. Propose your solution

  4. Consider alternatives

Proposing Plugins

Use the Plugin Proposal template:

  1. Review existing plugins

  2. Check ROADMAP for planned plugins

  3. Describe plugin purpose and interface

  4. Provide implementation outline


🔧 Development Workflow

1. Branch Strategy

# Create feature branch
git checkout -b feat/plugin-name

# Create fix branch
git checkout -b fix/issue-description

2. Code Standards

Type Hints: 100% coverage, mypy strict mode

mypy packages/*/src/ --strict

Formatting: Black with default settings

black packages/*/src/

Linting: Ruff with project config

ruff check packages/*/src/

Tests: >90% coverage required

pytest tests/ -v --cov --cov-report=term-missing

3. Plugin Development

Follow the AI Development Guide in docs/ai/:

  1. Read ROADMAP for plugin spec

  2. Create Protocol in packages/core/src/structum/[name]/

  3. Implement in packages/[name]/src/structum/plugins/[name]/

  4. Add tests with >90% coverage

  5. Update documentation

  6. Add usage example in demo/

Mandatory Checklist:

  • ✅ Protocol interface in core

  • ✅ Configuration-driven (no hardcoded values)

  • ✅ Metrics emission via get_metrics()

  • ✅ Structured logging via get_logger()

  • ✅ Health checks implemented

  • ✅ Graceful shutdown handling

  • ✅ Complete documentation

  • ✅ Tests >90% coverage

4. Commit Messages

We follow Conventional Commits:

<type>(<scope>): <description>

[optional body]

[optional footer]

Types:

  • feat: New feature

  • fix: Bug fix

  • docs: Documentation changes

  • refactor: Code refactoring

  • test: Test changes

  • chore: Maintenance tasks

  • ci: CI/CD changes

Examples:

feat(database): add SQLAlchemy provider
fix(auth): handle expired JWT tokens
docs(roadmap): update plugin priorities
refactor(cache): extract Redis client
test(messaging): add pub/sub integration tests
chore(deps): update dependencies
ci(workflow): add coverage reporting

5. Pull Request Process

  1. Update Documentation: README, docs/, CHANGELOG

  2. Run Quality Gates:

    # All must pass
    mypy packages/*/src/ --strict
    black --check packages/*/src/
    ruff check packages/*/src/
    pytest --cov
    
  3. Update CHANGELOG.md: Add entry under “Unreleased”

  4. Create PR: Use the PR template

  5. Request Review: Assign reviewers

  6. Address Feedback: Respond to all comments

  7. Squash Commits: Before merge (if requested)


📚 Documentation Guidelines

Code Documentation

Docstrings: Google style

def get_connection(self, timeout: int = 30) -> Connection:
    """Get database connection with timeout.
    
    Args:
        timeout: Connection timeout in seconds
    
    Returns:
        Active database connection
    
    Raises:
        ConnectionError: If connection fails
    
    Example:
        >>> db = get_database()
        >>> conn = db.get_connection(timeout=10)
    """

Markdown Documentation

  • Use headers properly (H1 = title, H2 = sections)

  • Include code examples

  • Add links to related docs

  • Keep it concise but complete


🧪 Testing Guidelines

Test Structure

# tests/test_plugin_name.py
import pytest
from structum.plugin import PluginInterface

def test_basic_functionality():
    """Test core functionality."""
    plugin = ConcretePlugin()
    result = plugin.operation()
    assert result is not None

def test_health_check():
    """Test health check implementation."""
    plugin = ConcretePlugin()
    health = plugin.health_check()
    assert health["status"] == "healthy"

def test_graceful_shutdown():
    """Test shutdown doesn't raise."""
    plugin = ConcretePlugin()
    plugin.shutdown()  # Should not raise

@pytest.fixture
def plugin_instance():
    """Fixture for plugin instance."""
    return ConcretePlugin()

Coverage Requirements

  • Overall: >90%

  • New code: 100%

  • Core modules: 95%+


🏗️ Architecture Principles

Core Principles:

  1. Protocol-First: Core has ONLY interfaces

  2. Configuration-Driven: No hardcoded values

  3. Observable: Metrics + logging everywhere

  4. Testable: Easy to mock and test

  5. Documented: Self-explanatory code + docs

Anti-Patterns to Avoid:

  • ❌ Core depending on plugins

  • ❌ Hardcoded configuration

  • ❌ Missing type hints

  • ❌ No metrics/logging

  • ❌ Untested code


📦 Release Process

For Maintainers:

  1. Update CHANGELOG.md

  2. Bump version (setuptools-scm handles this via tags)

  3. Create release PR

  4. Merge to main

  5. Create GitHub release with tag vX.Y.Z

  6. CI automatically publishes to PyPI


💬 Communication

  • GitHub Issues: Bug reports, feature requests

  • Pull Requests: Code contributions

  • Discussions: General questions, ideas

  • Discord (if available): Real-time chat


📄 License

By contributing, you agree that your contributions will be licensed under the Apache License 2.0.


🎓 Resources for Contributors


Questions? Open an issue or start a discussion!

Thank you for contributing to Structum! 🚀✨