prerelease Prerelease stable Latest
Kumoss
prerelease Prerelease stable Latest

Development

Contribute to Kumoss: prerequisites, running the stack for development, core and frontend tests, type checking, linting, and regenerating sidecar clients.

This guide covers contributing to Kumoss itself — running the repository’s own test suites, checks, and tooling. It does not cover deploying or operating Kumoss; for that, see Quickstart and Deploy to production.

Prerequisites

Before contributing, read Contributing for the Contributor License Agreement, the code of conduct, and the process for proposing a change.

Repository layout

The repository is a monorepo: the FastAPI core in core/, the IaC and notifications sidecar services in services/, the React web application in client/web/, and the sidecar OpenAPI contracts in contracts/. See Architecture for how they fit together.

Running the stack for development

Copy each env.sample to a .env next to it (core/.env is required), set the two model strings in config.yaml, and run docker compose up --build. Quickstart is the step-by-step guide. --build matters: without it, Compose runs the published release images (ghcr.io/inditextech/kumoss-*) instead of your checkout. A docker compose pull later replaces locally built images with the published ones again.

After a code change, rebuild and recreate the affected service, for example docker compose up -d --build core. An edit to config.yaml needs only docker compose restart core, because Compose bind-mounts that file.

Local Compose overrides

Settings that belong to your machine rather than to the project go in docker-compose.override.yml, which Compose loads automatically and git ignores. docker-compose.override.example.yml is the tracked template — copy it rather than editing it in place:

cp docker-compose.override.example.yml docker-compose.override.yml

Behind a TLS-inspecting proxy

On a corporate network that inspects HTTPS, most outbound container requests fail while a few domains keep working: web_search returns engine snippets instead of page content, and docker compose logs core shows the reads failing before any HTTP request is sent.

Page read for '<url>' failed, falling back to the engine snippet:
PageReadError("could not render '<url>'")
(RuntimeError('[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify
failed: self-signed certificate in certificate chain'))

The proxy terminates TLS and re-signs it with its own root, which the containers do not trust; the domains that still work are the ones the proxy passes through untouched. Confirm it by looking at who signed what you received:

docker compose exec core sh -c \
  'echo | openssl s_client -connect example.com:443 \
   -servername example.com 2>/dev/null | openssl x509 -noout -issuer'

An issuer naming your company rather than a public CA confirms the interception. The fix is two-part, both wired in the override template above, and keeps the certificates on your machine:

  • Build — the core downloads Chromium, so the roots are needed at build time too. The override points the host-certs build context at the host directory holding them.

  • Runtime — the override mounts that directory at KUMOSS_CA_DIR, and each entrypoint merges its certificates into a bundle and points the HTTP clients at it before starting the server.

A hostname mismatch is not a trust problem: the proxy is sinkholing that domain under its filtering policy, and the certificate honestly belongs to the sinkhole. No configuration fixes that one.

Core tests

Python 3.14, uv. pytest and pytest-cov are part of the tooling dependency group, so sync the project first:

cd core
uv sync --frozen --group tooling
uv run --no-sync pytest tests/

Async tests use unittest.IsolatedAsyncioTestCase (no pytest-asyncio plugin, no --asyncio-mode flag). core/tests/conftest.py supplies placeholder values for the LLM credential, the database URL and the mandatory KUMOSS_IAC_TOKEN that the configuration module validates at import; suites that talk to PostgreSQL or Redis need the compose stack (or point KUMOSS_SQL_DATABASE_URL and KUMOSS_REDIS_URL at your own instances).

Type checking

basedpyright lives in the tooling dependency group, which the project install above does not include; install the group first:

cd core
uv pip install --system --group tooling -r pyproject.toml
basedpyright

pyrightconfig.json only includes src/ — tests are not type-checked.

Frontend checks

Node 24:

cd client/web
npm ci
npm run lint
npm run test:ci
npm run build

Sidecar tests

Each sidecar service has its own tooling dependency group with pytest and its test helpers (the exact set differs per service):

cd services/<name>
uv sync --group tooling
uv run pytest

Linting and formatting

pre-commit run --all-files runs Ruff (ruff check and ruff format), the REUSE check, and gitleaks secret scanning. Install the hooks once with pre-commit install.

Continuous integration

Pull requests run Repolinter, the REUSE compliance check, the Conventional Commits check, and an offline Markdown link and anchor check, plus a Verify workflow: frontend type check, tests, and production build, and the pytest suite of each sidecar service. The core suite is not run in CI, so run it locally against the compose stack before opening a pull request.

Regenerating sidecar clients

Changing a sidecar’s behavior means updating its spec in contracts/openapi/, its conformance suite in contracts/conformance/, and regenerating the core’s client for that service. From core/, once per service:

uv run --group tooling openapi-python-client generate \
  --path ../contracts/openapi/<service>.v1.yaml \
  --config ../contracts/openapi-python-client.yaml \
  --meta none \
  --output-path src/clients/<service> \
  --overwrite

Regeneration drops the SPDX headers from the generated files; re-add them afterwards. Do not hand-edit anything under core/src/clients/{authz,iac,mapping,notifications}/.

Pull requests

Once your change is ready, Contributing covers the pull-request process and the checks it must pass.