@yuesu4/specdrift-codex-b
v0.1.0
Published
Diff OpenAPI 3.x specifications and identify breaking API changes
Maintainers
Readme
specdrift
specdrift compares two OpenAPI 3.x documents and reports contract drift. It reads JSON or YAML from local paths and HTTPS URLs, resolves local $ref pointers while comparing schemas, emits human or stable machine-readable output, and exits non-zero when the configured severity threshold is reached.
Install
npm install --global @yuesu4/specdrift-codex-bNode.js 20 or newer is required.
CLI
specdrift <old-spec> <new-spec> [options]
Options:
--format <text|json> Output format (default: text)
--fail-on <breaking|additive|informational>
Lowest severity that exits 1 (default: breaking)
--no-cache Bypass the on-disk HTTPS cache
-h, --help Show help
-v, --version Show versionBoth inputs may independently be a local JSON/YAML file or an https:// URL. HTTP is deliberately rejected so remote API contracts are not downloaded in clear text.
# Human-readable diff; fail only for breaking changes
specdrift openapi-v1.yaml openapi-v2.yaml
# Stable JSON; fail for additive or breaking changes
specdrift https://example.com/v1.json ./v2.yaml --format json --fail-on additive
# Always re-download remote inputs
specdrift OLD_URL NEW_URL --no-cacheText is coloured only when stdout is a TTY; set NO_COLOR=1 to disable colour explicitly. Exit code 0 means the threshold was not met, 1 means it was, and 2 means the inputs or command line were invalid. The default --fail-on breaking makes the command directly useful as a CI gate.
Severity thresholds are inclusive:
| --fail-on | Exits 1 for |
| --- | --- |
| breaking | breaking |
| additive | additive, breaking |
| informational | informational, additive, breaking |
What is detected
- Paths and HTTP methods added or removed
- Parameters added or removed, retyped, or changed between optional and required
- Request bodies added, removed, or changed between optional and required
- Request and response properties added, removed, retyped, or changed between optional and required
- Response status codes added or removed
- Effective operation security requirements changed, including inherited root requirements
Nested object and array properties are reported with paths such as owner.login and items[].id. Local OpenAPI component references are followed with cycle protection. External $ref documents are not downloaded; bundle them first when their schemas need to be compared. For each content map, application/json is preferred and otherwise the lexically first media type is compared.
Severity taxonomy
Every change includes a severity and a short reason. The taxonomy is intentionally consumer-oriented: if a previously valid request may be rejected, or a previously documented response can no longer be safely consumed, the change is breaking.
| Change | Severity | Reasoning | | --- | --- | --- | | Remove path or method | breaking | Existing calls lose their target. | | Add path or method | additive | Existing operations are unchanged. | | Add required request parameter/body/property | breaking | Existing clients do not send it. | | Add optional request parameter/body/property | additive | Existing requests remain valid. | | Remove request parameter/body/property | breaking | Existing clients may still send it. | | Make request input required | breaking | Existing clients may omit it. | | Make request input optional | additive | The accepted request set expands. | | Add response property or status | additive | A response capability is added without removing an existing one. | | Remove response property or status | breaking | Clients may depend on the documented result. | | Make response property optional | breaking | Clients can no longer assume it is present. | | Make response property required | breaking | Strict validators observe a stronger contract constraint. | | Retype parameter or schema property | breaking | Existing encoded values or decoders may be incompatible. | | Change effective security requirements | breaking | Authentication/authorization assumptions may no longer hold. |
informational is reserved in result schema 1.0 for future non-contract metadata detectors. It is accepted now as the lowest failure threshold so consumers do not need a CLI change when those detectors arrive.
JSON output
--format json emits a deterministic object. schemaVersion versions this public contract; new fields may be added compatibly, while a breaking shape change will increment it.
{
"schemaVersion": "1.0",
"changes": [
{
"category": "parameter.required",
"severity": "breaking",
"location": {
"path": "/pets",
"method": "GET",
"parameter": "query:limit"
},
"message": "parameter query:limit became required",
"reason": "Existing requests may omit the parameter."
}
],
"summary": {
"total": 1,
"breaking": 1,
"additive": 0,
"informational": 0
},
"hasBreakingChanges": true
}Changes are ordered by path, method, and comparison category traversal so the same documents produce stable output.
URL cache
Successful HTTPS responses are cached by a SHA-256 digest of their URL. The default directory is $XDG_CACHE_HOME/specdrift, or ~/.cache/specdrift when XDG_CACHE_HOME is unset. A repeat run parses the cached bytes without another request. --no-cache bypasses both cache reads and writes. The library API also accepts cacheDir for isolated CI caches.
Real-world verification
The release was verified on 2026-08-25 against two dated, publicly available versions of GitHub's REST API OpenAPI description: 2022-11-28 and 2026-03-10. Both URLs returned HTTP 200. The actual report contained 1,378 changes, so this worked example shows its first findings and complete summary:
specdrift \
https://raw.githubusercontent.com/github/rest-api-description/8114b0d0e23240dfe45374e2daf01651a4729210/descriptions/api.github.com/api.github.com.2022-11-28.yaml \
https://raw.githubusercontent.com/github/rest-api-description/8114b0d0e23240dfe45374e2daf01651a4729210/descriptions/api.github.com/api.github.com.2026-03-10.yamlBREAKING (1371)
[!] GET / · response 200 · authorizations_url — response property authorizations_url was removed
Existing clients may depend on this response property.
[!] GET / · response 200 · hub_url — response property hub_url was removed
Existing clients may depend on this response property.
[!] DELETE /app/installations/{installation_id} · response 204 — response status 204 was removed
Clients may rely on handling this documented response.
… 1368 more breaking changes
ADDITIVE (7)
[+] DELETE /app/installations/{installation_id} · response 202 — response status 202 was added
The operation documents an additional outcome without removing an existing one.
… 6 more additive changes
Summary: 1371 breaking, 7 additive, 0 informational.The opt-in npm run test:live test also fetches GitHub's current public document through the same loader. Ordinary npm test uses deterministic fixtures and a controlled Fetch response, so CI is not coupled to an external service.
Library API
The package ships ESM JavaScript and TypeScript declarations.
import { diffSources, diffSpecs, formatText, loadSpec } from '@yuesu4/specdrift-codex-b';
const oldDocument = await loadSpec('./old.yaml');
const newDocument = await loadSpec('https://example.com/new.yaml');
const pureResult = diffSpecs(oldDocument, newDocument); // synchronous, no I/O
const loadedResult = await diffSources('./old.yaml', './new.yaml', {
cache: true,
cacheDir: '/tmp/specdrift-cache',
});
console.log(formatText(loadedResult));Public values:
loadSpec(source, options?)loads and validates one OpenAPI 3.x document.diffSpecs(oldDocument, newDocument)performs a deterministic in-memory comparison.diffSources(oldSource, newSource, options?)loads both inputs concurrently and compares them.formatText(result, colour?)renders the human-readable form.- Types include
Change,ChangeCategory,ChangeLocation,ChangeSummary,DiffResult,LoadOptions,OpenApiDocument, andSeverity.
Development
npm ci
npm run lint
npm run typecheck
npm test
npm run build
npm run docsCI runs lint, type checking, and tests on Node.js 20 and 22. Releases publish the scoped package with npm provenance, and the documentation site is rebuilt from this README.
License
MIT
