Contributing
Contributions to Orchestrix are welcome. Here is how to get involved.
Setup Development Environment
1. Clone the repository
2. Install dependencies
With just (recommended):
Or manually with uv:
3. Verify installation
Development Workflow
Available Commands
# Setup
just setup # Initial setup (uv sync)
just install PKG # Install a package
# Code quality
just fix # Auto-format and auto-fix code
just qa # Run all quality checks (lint + format + type + test)
just check # Quick check (lint + typecheck only)
# Testing
just test # Run tests
just test-cov # Run tests with coverage
just test-watch # Watch mode — re-run on file change
# Build
just build # Build package
just clean # Clean build artifacts
# Documentation
just docs # Serve documentation locally
just docs-build # Build documentation
just docs-deploy # Deploy to GitHub Pages
# CI/CD
just ci # Full CI pipeline
Before Committing
# 1. Auto-format code
just fix
# 2. Run all quality checks
just qa
# 3. Verify tests pass with coverage
just test-cov
All checks must pass.
Coding Guidelines
Messages
# Commands: imperative (intent)
@dataclass(frozen=True, kw_only=True)
class CreateOrder(Command):
order_id: str
customer_id: str
# Events: past tense (fact)
@dataclass(frozen=True, kw_only=True)
class OrderCreated(Event):
order_id: str
customer_id: str
Type Annotations
Always use complete type hints:
# Correct
def handle(self, command: CreateOrder) -> None:
events: list[Event] = []
order: Order = Order.create(command.order_id)
# Avoid
def handle(self, command):
events = []
Docstrings
Google-style docstrings for public APIs:
def subscribe(self, message_type: type[Message], handler: Callable) -> None:
"""Subscribe a handler to a message type.
Args:
message_type: The message class to handle.
handler: Callable or handler instance with handle() method.
Example:
>>> bus.subscribe(CreateOrder, create_order_handler)
"""
Tests
Every new feature needs tests:
def test_message_bus_subscription():
"""Test that handlers are called when message is published."""
# Arrange
bus = InMemoryMessageBus()
events_received = []
bus.subscribe(OrderCreated, lambda e: events_received.append(e))
# Act
event = OrderCreated(order_id="ORD-001")
bus.publish(event)
# Assert
assert len(events_received) == 1
assert events_received[0].order_id == "ORD-001"
Commit Conventions
Use Conventional Commits:
| Type | Purpose |
|---|---|
feat: |
New features |
fix: |
Bug fixes |
docs: |
Documentation |
test: |
Tests |
refactor: |
Code refactoring |
perf: |
Performance improvements |
ci: |
CI/CD changes |
Pull Request Process
1. Create feature branch
2. Make changes and run quality checks
3. Push and create PR
Include in your PR description:
- What changed and why
- Tests added
- Breaking changes (if any)
Integration Tests with Testcontainers
Integration tests for PostgreSQL and EventSourcingDB use testcontainers-python for isolated, reproducible container-based testing.
Container Version Management
Container image versions are defined centrally in .container-versions.json:
Test fixtures read this file to determine which image version to use. Dependabot monitors this file for updates.
Updating container versions
- Edit
.container-versions.jsonwith the desired image tag - Run tests locally to verify compatibility
- Commit and push
CI/CD Pipeline
GitHub Actions runs on every push:
- Tests on Python 3.12 and 3.13
- Tests on Linux, macOS, Windows
- Ruff linting and formatting
- Type checking with
ty - CodeQL security analysis
Release Process
- Update
CHANGELOG.md - Tag version:
git tag v0.2.0 - Push tags:
git push --tags - GitHub Actions publishes to PyPI
Questions?
Open a GitHub Issue or Discussion.