Contributing guide
Thank you for helping. This guide covers how to set up, what we check, and the few architectural rules that reviews enforce strictly.
Generated from CONTRIBUTING.md in the Sarvex repository — edit the source there, not this page.
Thank you for helping. This guide covers how to set up, what we check, and the few architectural rules that reviews enforce strictly.
By participating you agree to the Code of Conduct. Report security problems privately — see SECURITY.md.
Ways to contribute
- Bugs: open an issue with steps to reproduce, expected and actual behaviour, and versions. A failing test is the best bug report.
- Features: open an issue first for anything beyond a small change, so we can agree on shape before you invest time. Read the “Scope” notes in
sarvex-v1-architecture.md. - New spec versions, commerce platforms, agent surfaces: these are designed to be added, not edited into. Follow
docs/HOWTO-add-spec-version.md,docs/HOWTO-add-platform.mdanddocs/HOWTO-add-surface.md. - Docs, tests, examples: always welcome. The docs site lives in
web/docs(make docsto preview); the API reference is generated from the contract files, and developer/contributor pages are synced from the Markdown underdocs/— edit the source file.
Development setup
You need Go 1.26+, Node.js (current LTS), and Docker for the local stack.
git clone https://github.com/sarvexlabs/sarvex.cp && cd sarvex.cp
go build ./...
make test-unit # no external services
make dev-up # full local stack (Mongo, Redis, NATS, Vault, planes)
make console # console in mock mode on :5173
cd web/console && npm ci && npm run test:run && npm run typecheck
PHP plugins: plugin/woocommerce runs with PHPUnit 9 (composer require --dev phpunit/phpunit:^9.5 && vendor/bin/phpunit); the Magento module’s pairing tests need a Magento install.
The rules reviews enforce
These come from the architecture (CLAUDE.md §2 has the full list). Breaking one blocks a merge.
- Three isolated planes.
internal/planes/{serving,sync,control}never import one another. They communicate over the event bus or by read-only access to a collection the other plane owns.internal/archtestand.golangci.ymlenforce this. - One writer per collection. Every collection has exactly one writing component. Others read.
- Tenant isolation is query-level. Every data-layer query filters by
merchant_id(account data) orstore_id(catalog/serving data), resolved server-side from the verified token or connector HMAC — never from a URL or query parameter. Readdocs/TENANCY-PATTERNS.mdbefore touching the data layer. - The serving read path uses only the cache. Checkout is the one exception, and only through the sync-plane connector.
- No credentials in checkout. Payment data is an opaque reference plus a handler id. Never add a credential-bearing field.
- Authentication is external. Services verify tokens; they never mint them or store passwords.
- Idempotency at every external edge. Retries are the normal case.
- Every change works on every supported spec generation and backend platform. A connector change is made to both
internal/platform/woocommerceandinternal/platform/magento;TestCapabilityMatrixmust cover new capabilities. - Contracts are authoritative. The control-plane HTTP API is exactly
sarvex-v1-control-plane.yaml; sync-plane events are exactlysarvex-v1-syncing-plane-async.yaml. Change the contract and the code together, and regenerate the console types (cd web/console && npm run gen:api). - Bugs you find get fixed with a regression test, in the same change.
Before you open a pull request
gofmt -l . | grep -v node_modules # must print nothing
go vet ./...
make test-unit
python3 scripts/license-headers.py --check
python3 scripts/check-licenses.py # when you touched dependencies
cd web/console && npm run typecheck && npm run test:run # when you touched the console
Golden files under **/testdata/golden freeze existing (platform, spec-version) output. Regenerate with UPDATE_GOLDENS=1 go test ./... only when the change is intended, and label the PR spec-change/<version> or platform-change/<platform> (see .github/workflows/golden-guard.yml).
Style
- Follow the surrounding code’s idioms, naming and comment density. Go is formatted with
gofmt; linting isgolangci-lint(.golangci.yml). - New Go, TypeScript, Vue and PHP source files start with the SPDX header;
python3 scripts/license-headers.pyadds it. - Keep PHP plugins thin: no scoring, mapping or protocol interpretation in PHP.
- Commit messages: a short imperative subject, then why the change is needed.
Licensing of contributions
Sarvex is licensed under the Apache License 2.0. Unless you state otherwise, contributions you submit are licensed under the same terms (Apache-2.0 §5). Do not copy code from sources whose licence is incompatible, and do not add dependencies under GPL/AGPL/SSPL/BUSL; scripts/check-licenses.py will fail on them.
Review and merge
Maintainers (see MAINTAINERS.md) review pull requests; CI must be green. Small, focused changes merge faster than large ones. See GOVERNANCE.md for how decisions are made.