Thanks for your interest in contributing — Statewave is built in the open and external contributions are very welcome.
This document covers the contribution process and the licensing implications of contributing to an Apache-2.0-licensed project.
- Bug reports — open a GitHub issue with reproduction steps, expected vs. actual behavior, and version info.
- Feature requests — open an issue describing the use case and the problem you are trying to solve. Concrete use cases beat abstract feature ideas.
- Pull requests — see "Pull request process" below.
- Documentation — improvements to the statewave-docs repo are equally valuable.
See the Quickstart section in the README for the canonical setup. In short:
docker compose up db -d
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,llm]"
alembic upgrade head
pytest tests/ -vPlease run ruff and the test suite locally before opening a PR.
To validate the full fresh-user path (wipe volumes → compose up → readiness → smoke checks), use the root Makefile target:
cp .env.example .env # if you have not already
pip install -e ".[dev]"
make test-coldmake test-cold will:
docker compose down -v(wipe persisted state)docker compose up -d- Poll
GET /readyzuntilstatusisready(60s timeout by default) - Run the smoke suite:
pytest tests/smoke/ -m smoke - Print time-to-first-ready in seconds
Override defaults if needed:
API_URL=http://127.0.0.1:8100 READYZ_TIMEOUT=90 make test-coldRequires Docker, curl, and Python dev dependencies (httpx, pytest).
Use the lightest-weight venue that fits the change:
- Small, obvious fixes — typos, doc tweaks, isolated bug fixes — go straight to a PR. No discussion needed.
- Larger features, behavior changes, new endpoints — start in GitHub Discussions under Ideas & Feature Requests with the use case and proposed shape, so we can align before you invest in code.
- Architecture changes, API shape changes, storage / security / integration designs — open an RFC in Discussions. The RFC template and process are documented in statewave-docs/community/discussions.md and discussion-templates.md.
- Confirmed bugs with clean reproduction — open an issue, not a discussion.
- Security concerns — never post publicly. Follow the coordinated disclosure process in SECURITY.md.
- Licensing questions — general questions ("how does Apache-2.0 apply to my use case?") are welcome publicly in Discussions. Enterprise support contracts (SLA, indemnity, procurement) go privately to licensing@statewave.ai — these are services agreements, not separate licenses. Apache-2.0 covers the code.
Rule of thumb: if you can describe a clean reproduction or a concrete change, open an Issue or PR. Otherwise, start in Discussions.
- Open an issue or discussion first for non-trivial changes so we can align on approach before you invest in code.
- Branch from
main, keep PRs focused, and prefer small commits with clear messages. - Add tests for new behavior. Statewave is infrastructure — coverage matters more than feature volume.
- Update docs if you change public API, configuration, or behavior.
- Pass CI — lint, type checks, and tests must be green.
- Describe the change in the PR body: motivation, approach, and any tradeoffs considered.
Statewave is licensed under the Apache License, Version 2.0. By contributing — opening a pull request, sending a patch, or otherwise submitting work — you agree that your contribution is licensed under Apache-2.0 along with the rest of the project. You retain copyright in your work.
We use the Developer Certificate of Origin (DCO)
for contributions. Sign your commits with git commit -s (or --signoff)
to add a Signed-off-by: trailer asserting that you have the right to
contribute the work under the project's license.
If your employer has rights to your work, please make sure they have authorized the contribution before submitting.
- Python 3.11+, formatted with
ruff(settings inpyproject.toml). - Type hints on public APIs.
- Match the surrounding code's conventions; prefer small, composable functions; prefer clear names over comments.
A few cross-cutting rules are checked automatically so a single change can't silently reintroduce a whole class of bug. If your PR trips one of these, the fix is to satisfy the rule (not to weaken the test):
- Tenant scoping — every repository query that takes a
subject_idmust also take atenant_idand apply_tenant_filter, so it can't read across tenants. (tests/test_tenant_scoping_invariant.py) - Bounded pagination — every
limitquery parameter needsgeandle, and everyoffsetneedsge. (tests/test_route_limits_invariant.py) - One tokenizer — lexical word comparison goes through
server.services.tokenization.tokenize; raw.lower().split()elsewhere is rejected, because punctuation welded onto tokens silently zeros overlap. (tests/test_no_raw_tokenization.py,tests/test_tokenization.py)
Each rule exists because a real bug shipped without it; the test is the cheapest place to catch the next one.
Please do not open a public issue for security vulnerabilities. See SECURITY.md for the coordinated disclosure process.
- General questions: GitHub Discussions
- Licensing questions: licensing@statewave.ai
- Security: security@statewave.ai