How the @quantakrypto/* packages are versioned and how breaking changes are
introduced. This policy operationalises ADR-0002
(@quantakrypto/core is the shared contract) and ADR-0003
(independent publish from one monorepo).
All packages follow Semantic Versioning 2.0.0: MAJOR.MINOR.PATCH.
- MAJOR — a backward-incompatible change to a package's public surface.
- MINOR — backward-compatible new functionality.
- PATCH — backward-compatible bug fixes (including detection-accuracy fixes that do not change the data contract).
Under SemVer's 0.x rule, anything may change in a minor release and the public
API is explicitly pre-stable. We make no compatibility promises before 1.0
— pre-1.0 breaking cleanups land in a 0.x minor even though they would be breaking
post-1.0. (The two earlier honesty items — the baseline-fingerprint schism P1-1 and
the dead ScanOptions.include option P1-2 — have both since been fixed this way.)
Reaching 1.0.0 requires a documented, frozen
public API surface (the core contract),
a generated API reference, and a maintained CHANGELOG.
Status (2026-07-20): the generated API reference and the frozen surface are now
in place — docs/API.md (human) and docs/api-surface.json
(the machine-readable contract) are generated by npm run api:docs from each
package's public entry point, and npm run api:check (a CI gate in the lint job)
fails if a package's real exports drift from the snapshot. So adding or removing a
public symbol is now a deliberate, reviewed change to the checked-in surface, not an
accident — the remaining 1.0 work is to keep the CHANGELOG current (ongoing) and to
make a considered decision that the surface is stable enough to freeze under the
post-1.0 breaking-change rules.
Each package versions independently (it has its own package.json and publishes
on its own line). But because five tools consume @quantakrypto/core — qScan, MCP,
the Action, agent, and qProbe (ADR-0002;
Sieve is standalone and depends on no other package):
- A MAJOR bump of
@quantakrypto/corethat changes the contract forces, at minimum, a MINOR bump of every consumer that adopts the new core (a new compatible feature) or a MAJOR bump where the consumer's own surface changes as a result. - Consumers declare their
@quantakrypto/coredependency with a range that does not cross a core MAJOR (e.g.^1). Crossing a core MAJOR is itself a breaking change for the consumer.
Only the documented surface is covered by SemVer. Internal modules (anything not
re-exported from a package entry point, anything under a src/internal-style
path, dist layout) are not part of the contract and may change in a PATCH.
| Package | Public surface (SemVer-covered) |
|---|---|
@quantakrypto/core |
The exports of src/index.ts + the types in src/types.ts (see §3). |
@quantakrypto/qscan |
The qscan CLI (flags, exit codes, output-format shape) and the qremediate CLI (flags, --mode diff|apply|pr, exit codes 0/2) and the programmatic API: runQscan, EXIT, parseArgs, defaultOptions, REMEDIATE_EXIT, severity + baseline helpers. |
@quantakrypto/mcp |
The MCP tool contract: tool names, their inputSchema, and result shape; the supported JSON-RPC methods. The bin name quantakrypto-mcp. |
@quantakrypto/action |
The action interface: action.yml inputs, outputs, and documented exit behavior; the uses: ref. |
@quantakrypto/sieve |
The SUT protocol (PROTOCOL.md, PROTOCOL_VERSION), the CLI flags/exit codes, and runSieve/formatHuman. |
@quantakrypto/agent |
The exported BYOK client API: resolveClient, triageFindings, proposeFix, validateAgainstSchema, the LlmClient/LlmConfig/LlmRequest types, and the prompt-version constants (TRIAGE_PROMPT_VERSION, FIX_PROMPT_VERSION). The internal provider adapters (anthropicClient, openAiCompatibleClient) and the response-cache layout are not the contract. |
@quantakrypto/qprobe |
The qprobe CLI (flags — incl. the ownership attestation --i-own-this/--owned-hosts — exit codes, output-format shape) and the programmatic API: runProbe, parseTarget, authorizeTargets, the classify/report helpers, and their types. The internal wire parsers are not the contract. |
Non-API-but-still-contract surfaces — the qScan exit codes (0/1/2), the
SARIF 2.1.0 output schema, the Sieve wire protocol, the baseline file
format — are versioned too: changing them is breaking. The Sieve protocol
additionally carries its own PROTOCOL_VERSION integer that bumps on any breaking
wire change independently of the package version.
A change to @quantakrypto/core is MAJOR (breaking) if it alters the meaning or
shape that a consumer relies on. Concretely, breaking:
- Removing or renaming any
src/index.tsexport — e.g.scan,scanParallel,walkFiles,toSarif,toJson,toCbom,formatSummary,buildInventory,remediationFor,verifyFix,detectors,vulnerableDependencies, the shared baseline surface (fingerprintFinding,applyBaseline,loadBaseline,saveBaseline), the offline agent-plane primitives (buildContext,buildTriageRequest,buildRemediateRequest,checkPatchPolicy,withWorktree,codemodFor,remediateFindings),loadConfig, andVERSION. (The re-export surface has grown ~3× since 0.1.0;packages/core/src/index.tsis the full list.) - Narrowing an input or widening an output type incompatibly — e.g.
removing a
Findingfield, making an optional field required, or removing a member from theSeverity,AlgorithmFamily, orFindingCategorystring-literal unions. - Changing the shape of
ScanResult,CryptoInventory, or a reporter's output object in a way existing consumers cannot read. - Changing the semantics of a stable field — e.g. flipping the meaning of an
hndlflag, or changing thereadinessScoreformula (the score is a contract output; tweaks that move existing scores are breaking). - Changing SARIF output structure in a way a conformant consumer would reject.
Not breaking (MINOR or PATCH):
- Adding a new
src/index.tsexport, a new optionalFindingfield, or a new detector (MINOR — new findings may appear; see the note below). - Adding a new member to an output-only union that consumers switch on with a default branch — treated as MINOR, and called out in the CHANGELOG, because a consumer that exhaustively switches may need a new case.
- A detection accuracy fix (fixing a false positive/negative) that does not change any type — PATCH. Detection-result changes are expected within a major: new detectors and accuracy fixes mean the set of findings on a given codebase can change between MINORs/PATCHes by design. The data contract is stable; the set of findings is not promised stable, and baselines exist precisely to absorb that. This distinction is the contract.
We deprecate before we remove. The window scales with the change's blast radius.
- Mark — annotate the symbol/flag with
@deprecated(JSDoc) and/or a runtime warning (CLI/MCP), naming the replacement. Add a CHANGELOG entry. - Keep working — the deprecated surface keeps functioning for at least the window below.
- Remove — only in a subsequent MAJOR release, never in a MINOR/PATCH.
| Surface | Minimum deprecation window before removal |
|---|---|
@quantakrypto/core public export / type field |
one MAJOR cycle, ≥ 6 months, whichever is longer. |
| qScan / Sieve CLI flag | one MINOR with a deprecation warning, removed no earlier than the next MAJOR. |
| MCP tool or tool input field | one MINOR announcing it; removal in the next MAJOR. Hosted clients get the longer of one MAJOR or 6 months. |
| Action input/output | one MINOR with a warning in the job log; removal in the next MAJOR of the action. |
| Sieve wire protocol field | bump PROTOCOL_VERSION; keep the prior version accepted for one MAJOR where feasible (SUTs are external code). |
| File formats (baseline, SARIF additions) | additive only within a MAJOR; format removal/restructuring is MAJOR with a documented migration. |
Security fixes are exempt from deprecation windows where a window would prolong an exposure: a P0 security change may change behavior in a MINOR (e.g. hosting filesystem MCP tools OFF by default), documented clearly in the CHANGELOG as a security-driven break.
- Every release updates the CHANGELOG ("Keep a Changelog" style) with an explicit Breaking section when MAJOR.
- Breaking changes to
@quantakrypto/corereference (or add) an ADR when they reflect a decision, not just a fix. - Releases are cut through the gated release workflow with npm provenance (see SUPPLY-CHAIN.md).