Thanks for your interest in contributing! This guide covers everything you need to get started.
- Python 3.11 or newer
- Ollama (for running local models)
- Docker (optional, for full-stack testing)
- Git
git clone https://github.com/mara-werils/llmstack.git
cd llmstack
# Create a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
# Install in editable mode with dev dependencies
pip install -e ".[dev]"llmstack --version
llmstack doctor# Run the full test suite
pytest
# Run with verbose output
pytest -v
# Run a specific test file
pytest tests/unit/test_schema.py
# Run only fast tests (skip slow/integration)
pytest -m "not slow"
# Check code style
ruff check .
# Auto-format code
ruff format .- Place unit tests in
tests/unit/and integration tests intests/integration/. - Use
pytest-asynciofor async tests (the project usesasyncio_mode = "auto"). - Name test files
test_<module>.pyand test functionstest_<behaviour>. - Use
fakeredisinstead of a real Redis server in unit tests.
src/llmstack/
├── cli/ # Typer CLI commands
│ ├── app.py # Main Typer app and command registration
│ └── commands/ # One file per CLI command
├── config/ # Pydantic config schema + presets + loader
├── core/ # Stack orchestrator, hardware detection, resolver
├── gateway/ # FastAPI gateway (OpenAI-compatible proxy)
│ ├── main.py # App factory
│ ├── routes/ # One router per API group
│ └── middleware/ # Auth, logging, rate limiting, correlation ID
├── docker/ # Docker SDK wrapper
├── finetune/ # Fine-tuning pipeline (LoRA / QLoRA)
├── observe/ # Observability: traces, scoring, alerts
├── agent/ # Tool-using AI agent
├── mcp/ # MCP server for AI client integration
├── sdk/ # Python SDK (Client / AsyncClient)
└── plugins/ # Plugin interface + loader
- Python 3.11+ -- use modern syntax (
X | Yunions, etc.). - Ruff for linting and formatting. Config is in
pyproject.toml. - Type hints on all function signatures.
- Docstrings for every public function, class, and module (Google style).
- Line length 100 characters (
tool.ruff.line-length). - Prefer
from __future__ import annotationsat the top of every module. - Use
Field(default_factory=...)for mutable Pydantic defaults.
- Create
src/llmstack/cli/commands/<name>.pywith a top-level function. - Register it in
src/llmstack/cli/app.pyas a@app.command(). - Add tests in
tests/unit/test_<name>.py.
- Create a class extending
ServiceBaseinsrc/llmstack/services/. - Implement
container_spec(),health_url(). - Optionally implement
post_start(),openai_base_url(). - Register in
services/registry.pyor as a plugin viaentry_points. - Add tests in
tests/unit/.
See plugins/spec.py for the plugin interface.
# In your plugin's pyproject.toml:
[project.entry-points."llmstack.services"]
my_service = "my_package:MyServiceClass"- Branch -- create a feature branch from
main(e.g.feat/my-feature). - Commits -- use Conventional Commits
(
feat:,fix:,docs:,refactor:,test:,build:,ci:). - Tests -- add or update tests. All CI checks must pass.
- Lint -- run
ruff check . && ruff format --check .before pushing. - PR description -- explain what and why. Reference any related issues.
- Review -- a maintainer will review and may request changes.
- Keep PRs focused on a single concern.
- Aim for < 400 lines changed per PR.
- If a change is large, break it into a stack of smaller PRs.
Open an issue with:
- LLMStack version (
llmstack --version) - OS and Python version
- Steps to reproduce
- Expected vs actual behaviour
- Output of
llmstack doctor