Contributing
Getting started
Section titled “Getting started”Prerequisites
Section titled “Prerequisites”- Python 3.10+
- Git
- A local LLM provider for testing (LM Studio or Ollama recommended)
Development setup
Section titled “Development setup”git clone https://github.com/kevinjobin1/model-lens.gitcd model-lenspip install -r requirements.txtpip install ".[dev]"pre-commit installDev dependencies
Section titled “Dev dependencies”The [dev] extra in pyproject.toml installs:
ruff— linting and formattingmypy— type checkingpytestandpytest-cov— testingpre-commit— git hook management
Pre-commit hooks
Section titled “Pre-commit hooks”On every commit, the following checks run automatically:
| Hook | What it checks |
|---|---|
trailing-whitespace | No trailing whitespace |
end-of-file-fixer | Files end with a newline |
check-yaml / check-json / check-toml | Valid config files |
check-added-large-files | No files > 500KB |
ruff check --fix | Linting with auto-fixes |
ruff format | Consistent code formatting |
mypy | Type checking (MYPYPATH=packages) |
To run manually:
pre-commit run --all-filesCode quality standards
Section titled “Code quality standards”These are enforced on every push via CI (.github/workflows/ci.yml):
# Lintruff check packages/ apps/cli/ tests/
# Formatruff format --check --diff packages/ apps/cli/ tests/
# Type checkMYPYPATH=packages mypy packages/ apps/cli/
# Testpytest tests/ -vThe CI is strict — any failure blocks the build. No || echo fallbacks.
Project conventions
Section titled “Project conventions”Architecture invariants
Section titled “Architecture invariants”- Events package is self-contained — never import from core, providers, or benchmarks into
packages/events/ - Providers never import core — each client depends only on
base.py - Core never imports benchmarks — imports flow the other direction
- Dual-authority benchmarks —
benchmark.pyandbench_apple_silicon_v2.pyare intentionally separate; do not merge them
URL handling
Section titled “URL handling”Use urllib.parse.urljoin() and helpers from packages/providers/base.py:
from providers.base import normalize_base_url, get_root_url, url_joinBanned patterns: .rstrip("/"), .removesuffix("/v1"), f"{base}/{path}" string concatenation.
Logging
Section titled “Logging”from packages.logging import get_loggerlogger = get_logger(__name__)logger.info("message", key="value")No print() for observability data — only for CLI user-facing output.
Exception handling
Section titled “Exception handling”Never use bare except: or except Exception:. Catch specific types:
try: ...except (requests.ConnectionError, requests.Timeout): ...Event emission
Section titled “Event emission”Providers emit TokenGeneratedEvent per streaming token and CompletionEvent after response. Benchmarks emit RunLifecycleEvent (started/completed/failed) and MetricEvent per result. Always use the thread-safe EventBus.
Running tests
Section titled “Running tests”# Full suitepytest tests/ -v
# Specific test filespytest tests/test_provider_clients.py -v
# With coveragepytest tests/ -v --cov=packages --cov-report=termSubmitting a PR
Section titled “Submitting a PR”- Fork the repository
- Create a feature branch
- Make your changes
- Run pre-commit checks:
pre-commit run --all-files - Run tests:
pytest tests/ -v - Submit a PR with a clear description
Documentation
Section titled “Documentation”The docs site lives at apps/docs/ (Starlight). To preview:
cd apps/docsbun installbun run dev # → http://localhost:4321