Development Setup
OpenTremor is split into several independently packaged modules that all live in one
repository, each as a top-level directory with its own pyproject.toml/package.json,
tests and LICENSE. This page covers developing against OpenTremor-core (the
server). For a full local stack (core + an analyzer + dashboard + MongoDB) in one
command, see the docker-compose.yaml at the repository root.
Prerequisites
Section titled “Prerequisites”| Tool | Version | Purpose |
|---|---|---|
| Python | 3.14.x | Runtime |
| Poetry | 1.8+ | Dependency management |
| Docker | any | MongoDB for integration tests |
Install
Section titled “Install”git clone <opentremor-repo-url> opentremorcd opentremor/OpenTremor-corepoetry installThis installs runtime and dev dependencies (pytest, black, isort, …) but no
analyzer — GET /analyzers returns an empty list until you install one. To run the
full test suite (including the tests that exercise a real analyzer end-to-end), pull in
the analyzers as well. They are already sibling directories in the clone
(OpenTremor-analyzer-terraform-plan, OpenTremor-analyzer-terraform-code-change,
OpenTremor-analyzer-blackhole — each is independent of the others), so the path
dependencies resolve with no extra setup:
poetry install --with internalStart services
Section titled “Start services”docker compose up mongodb -dpoetry run python src/tools/init_mongo.pyA default superadmin account is available out of the box via auth.default_admin_email/default_admin_password — in configs/opentremor-core-local.yaml when running the server directly, or in the workspace root’s shared configs/opentremor-local.yaml when running either docker stack. See Configuration Reference — auth.
Run the server (dev mode)
Section titled “Run the server (dev mode)”poetry run uvicorn opentremor_core.controllers.app:app \ --reload \ --host 0.0.0.0 \ --port 8000Or with the bundled server entrypoint (reads HOST, PORT, CONFIG_FILE env vars):
CONFIG_FILE=configs/opentremor-core-local.yaml poetry run python src/server.pyProject layout
Section titled “Project layout”opentremor-core/├── configs/│ ├── opentremor-core.yaml This repo's own standalone docker stack (MongoDB)│ ├── opentremor-core-local.yaml Local dev (in-memory, default)│ ├── opentremor-core-prod.yaml Operator's cloud SaaS deployment│ └── opentremor-core-tests.yaml Test suite config├── src/│ ├── opentremor_core/ Python package — server framework, no analyzers│ ├── tests/ Test suite│ ├── tools/ CLI utilities│ └── server.py Uvicorn entrypoint├── pyproject.toml├── Dockerfile└── docker-compose.yaml This repo alone (app + MongoDB, no analyzer/dashboard)Code style
Section titled “Code style”# Formatpoetry run black src/
# Sort importspoetry run isort src/
# Both (typical pre-commit)poetry run black src/ && poetry run isort src/Continuous integration
Section titled “Continuous integration”.github/workflows/ci.yml at the repository root runs on every push and pull request.
Every job targets runs-on: self-hosted, so the workflow needs a registered self-hosted
runner on the repository; without one the jobs queue instead of failing. The runner has to
provide Docker (the compose config job shells out to docker compose) and enough disk for
the Python, Node and Go toolchains the setup-* actions install into its tool cache.
One job per module, all in parallel:
| Job | Runs |
|---|---|
python · <module> | poetry install + pytest for OpenTremor-platform, OpenTremor-core, the three analyzers, and OpenTremor-task-scheduler. Core installs --with internal so the analyzer-dependent tests run instead of skipping. |
platform independence | Asserts opentremor_core is not importable from the platform venv — platform must stay runnable without the product mounted on it. |
dashboard | npm ci, npm run lint, npx tsc --noEmit, npm run build. |
docs | npm ci + npm run build, which runs the module-docs composition step first. |
terraform-provider | go build, go vet, go test. |
helm chart | helm lint, then helm template against each values profile. |
compose config | docker compose config over all three compose files. |
There is no path filtering — every job runs on every push, because the dependency edges
between modules (a platform change must still run core’s suite; an analyzer change must
still run core with --with internal) don’t match the directories that changed.
Dependency updates
Section titled “Dependency updates”Renovate opens update pull requests every Monday morning
(UTC), configured in .github/renovate.json5. It finds every manifest on its own — the seven
pyproject.toml/poetry.lock pairs, the dashboard and docs package.json files, the provider’s
go.mod (indirect requirements included), every Dockerfile and *.Dockerfile, the
docker-compose files, the chart’s values.yaml, core’s mise.toml and the workflow actions.
| Update | Pull request | Merged by |
|---|---|---|
| Python, npm, Go — minor and patch | one per ecosystem | Renovate, once every check is green and the version is 3 days old |
| Container images — minor and patch | one for all images | a person — CI builds no image |
Dev tools in mise.toml — minor and patch | one | a person |
| Security fix (OSV advisory) | one per advisory, any day of the week | as its ecosystem’s group |
| GitHub Actions — any | one for all actions, ci(deps) | a person |
| Any major | none, until ticked on the Dependency Dashboard issue | a person |
| Lockfile refresh (transitive dependencies) | one, weekly | a person |
Majors wait on the Dependency Dashboard. Renovate keeps one issue listing every pending
major; ticking its checkbox opens the pull request. A major that can’t pass yet — eslint 10
before eslint-plugin-react supports it — stays listed there instead of being re-opened every
week.
Lockfiles are written with CI’s toolchain — node 24, npm 11.19.0, Poetry 2.4.1, under
constraints in the config. Bump them there when NODE_VERSION or POETRY_VERSION changes
in .github/workflows/ci.yml; nothing checks that the two agree.
Pinned in the config rather than proposed:
mongostays below 8 — every 8.x refuses to start on Linux 6.19+ (MongoDB SERVER-121912).- The
pythonbase image’s minor and major wait for approval — it moves withpython = ">=3.14,<3.15"in everypyproject.tomland CI’sPYTHON_VERSION, never alone. - Go’s
godirective waits for approval — it is the language version, and CI’s setup-go reads it fromgo.mod. - Our own images and workspace packages are ignored —
ghcr.io/tguisep/opentremor-*, the localopentremor-*compose images and@opentremor/*. release-please stamps them.
Commits use chore(deps) and ci(deps). chore is a hidden section in release-please’s
changelog, so a package bump ships in the next release without a changelog line.
Documentation
Section titled “Documentation”Docs live in the sibling OpenTremor-docs directory:
cd ../OpenTremor-docsnpm installnpm run dev # live-reload dev server at http://localhost:4321npm run build # static site → dist/Reaching the dev server on a hostname other than localhost
Section titled “Reaching the dev server on a hostname other than localhost”Astro’s dev server is Vite, and Vite refuses requests whose Host header it doesn’t
recognise — a DNS-rebinding protection. Reached through a proxy or on a real domain it
answers Blocked request. This host ("…") is not allowed. instead of the site. List the
extra hostnames in DOCS_ALLOWED_HOSTS (comma-separated; * disables the check
entirely):
DOCS_ALLOWED_HOSTS=docs.example.com npm run dev -- --hostThis affects npm run dev only. npm run build output is static files with no dev
server involved, so a production deployment never needs the variable — the workspace’s
docker-compose.dev.yaml sets it for its docs service, docker-compose.prod.yaml
does not.