Continuum is intended to be sold, so every dependency has to permit distribution in closed-source commercial software. Nothing recorded that before: our own crates and npm packages carried no licence field at all, which made `cargo deny` report them as `unlicensed` errors and left the actual policy nowhere. docs/LICENSES.md is the policy and lives here because it is the repo both other tiers already depend on. It covers the allow/deny list, the 2026-09-17 audit of all six repos (no copyleft reaches any binary), and the three categories `cargo deny` structurally cannot see: external binaries we spawn or ship, ML model weights, and self-hosted server software whose licence is not its client library's. Two findings in there are worth more than the tooling: Redis 7.4+ is RSALv2/SSPL and 8.0+ adds AGPLv3, and Ultralytics YOLO and Obico's print-failure model are both AGPL-3.0 - the obvious choice in each case is the one we cannot ship. Crates declare `LicenseRef-Proprietary` with `publish = false`; that string is deliberately not valid SPDX so it must never enter an allow list. npm packages use `"license": "UNLICENSED"`.
7.2 KiB
Licence policy
Continuum is a closed-source commercial product. We intend to sell it, so
every dependency must permit distribution in proprietary software without
publishing our own source. This document is the policy; deny.toml in each
repo is the machine-enforced half of it.
The rule
Permissive only. A dependency is allowed if it is one of:
| Licence | Notes |
|---|---|
| MIT, ISC, 0BSD, BSD-2-Clause, BSD-3-Clause | The common case |
Apache-2.0 (incl. WITH LLVM-exception) |
Carries a patent grant, which is a plus |
| Unlicense, CC0-1.0 | Public-domain dedications |
| Zlib, BlueOak-1.0.0 | Permissive, OSI/Blue Oak approved |
| Unicode-3.0 | Unicode data tables |
| MPL-2.0 | File-level copyleft only; fine as long as we do not edit the dependency's own files |
Forbidden, no exceptions: GPL, LGPL (when statically linked), AGPL, SSPL, RSAL, Commons Clause, "source available", CC-BY-NC, and any licence with a field-of-use or non-commercial restriction.
Two rules that are easy to get wrong:
- Dual-licensed dependencies are fine - we elect the permissive option.
Record the election here so it is not re-litigated (see
node-forgebelow). - LGPL is conditionally fine but only via dynamic linking with the library replaceable by the user. Rust static linking does not qualify. Assume LGPL is forbidden unless someone writes down why a specific case is not.
How it is enforced
Rust, per repo:
cargo deny check licenses # proxy, ai-worker
cargo deny --manifest-path packages/rust-core/Cargo.toml check licenses # common, schemas
cargo deny --manifest-path apps/desktop/src-tauri/Cargo.toml check licenses # app
Our own crates declare license = "LicenseRef-Proprietary" with
publish = false. LicenseRef-Proprietary is deliberately not a real SPDX
identifier and must never be added to a deny.toml allow list - a
third-party crate claiming it would be a genuine finding, and publish = false is what marks ours as first-party. Our npm packages use
"license": "UNLICENSED" with "private": true, which is npm's equivalent
convention.
JavaScript has no cargo deny equivalent wired up yet; the audit below was
done by walking installed node_modules manifests.
What the tooling cannot see
cargo deny only reads the cargo graph. Three categories sit outside it and
have to be checked by hand:
- External binaries we spawn or ship. Invoking a GPL program as a separate process is not itself a derivative work, but shipping it in our installer means distributing it under its own terms.
- ML model weights. A model's licence is independent of the runtime that
loads it. This is the single biggest trap in this project (see
continuum-ai-workerbelow). - Managed/self-hosted services. The client library's licence is not the
server's licence.
ioredisbeing MIT says nothing about Redis.
Audit, 2026-09-17 (Redis resolved 2026-10-03)
All six repos audited. No copyleft code is currently compiled into any
Continuum binary. Every Rust crate across continuum-proxy,
continuum-ai-worker, continuum-app/apps/desktop, continuum-common and
continuum-schemas passes the policy above. The JS graphs are MIT/Apache/ISC/
BSD/BlueOak throughout.
Fixed in this pass: all six of our own crates and all nine of our npm
packages were missing a licence field (cargo deny reported them as
unlicensed errors), and no repo had a deny.toml.
Findings carried forward
Redis - RESOLVED 2026-10-03, we use Valkey. Redis 7.4+ is RSALv2/SSPLv1
and Redis 8.0+ added AGPLv3 as a third option. All three are non-permissive,
and SSPL §13 specifically targets offering the software's functionality as a
service - which is what a cloud control plane does. The clients were never
the problem (ioredis and the redis crate are both MIT); the server we
deploy was.
We now deploy Valkey (BSD-3-Clause, Linux Foundation, forked from Redis
7.2.4). What changed: REDIS_URL -> VALKEY_URL and
CONTINUUM_REDIS_URL -> CONTINUUM_VALKEY_URL, the exported redis client
in continuum-backend/src/queue/ renamed to valkey, Config.redis_url ->
Config.valkey_url in continuum-ai-worker, /health now reports a
valkey field, and continuum-backend/docker-compose.yml pins
valkey/valkey:8-alpine. Both tiers still typecheck/compile unchanged
otherwise, because Valkey speaks the same protocol.
Two things deliberately did not change, so nobody "fixes" them later:
the redis:// URL scheme (it names the RESP wire protocol, and no client
library understands a valkey:// scheme), and the client libraries
themselves (ioredis, the redis crate) - they are RESP clients, and their
names refer to the protocol's origin, not to the server we run.
AI model weights - blocks PLAN.md step 4. src/inference/mod.rs
currently stubs a "spaghetti" detection. The two obvious off-the-shelf
sources are both AGPL-3.0: Ultralytics YOLO (v5/v8/v11) and Obico / The
Spaghetti Detective's print-failure model. Neither can ship in a commercial
product without a paid enterprise licence. The ort crate itself is MIT and
fine. Permissive alternatives to evaluate when step 4 comes up: YOLOX
(Apache-2.0), RT-DETR (Apache-2.0), RF-DETR (Apache-2.0), or training our own
weights on a permissively-licensed architecture. Decide the architecture
before collecting training data - retraining because of a licence is the
expensive version of this mistake.
go2rtc and ffmpeg - currently fine, keep it that way.
continuum-proxy/src/go2rtc.rs spawns go2rtc (MIT) from PATH and expects
the operator to have installed it, so we distribute nothing. If that ever
changes: go2rtc shells out to ffmpeg, and ffmpeg is LGPL-2.1+ only when
built without --enable-gpl. Most distro and prebuilt ffmpeg binaries are
GPL builds (they bundle x264). Shipping one would be a GPL distribution.
node-forge - dual-licensed, we elect BSD-3-Clause. It appears in
continuum-app as (BSD-3-Clause OR GPL-2.0). The election is ours to make
and is recorded here so the GPL half does not trigger a false alarm later.
caniuse-lite - CC-BY-4.0, attribution required if redistributed. A
build-time browserslist dependency in continuum-app; its data is not
bundled into the Nuxt output, so no attribution obligation today. It would
acquire one if anything started shipping the dataset itself.
Infrastructure already clear. PostgreSQL and pgvector (PostgreSQL licence), PgBouncer (ISC), pgCat (MIT), Supabase (Apache-2.0), ONNX Runtime (MIT), Cloudflare R2 (a service, governed by contract not licence) all permit commercial use.
Not findings
A node_modules walk turns up packages named baz, browser_field,
invalid_main, false_main and nw-pre-gyp-module-test with no licence
field. These are test fixtures inside other packages, not dependencies.
Ignore them.
When adding a dependency
- Check the licence against the table above before writing code against it. Replacing a library after it is load-bearing is the costly path.
- Run the repo's
cargo deny check licenses. - If it is an external binary, a model, or a service, none of the tooling will catch it - add it to the audit section above by hand.