Skip to content

Importing Spectral results

If your team already lints OpenAPI documents with Spectral, thymian report convert imports those results into Thymian reporting: Spectral findings become first-class Thymian findings that render, format, and gate CI exactly like native lint results.

Use it when you have existing Spectral output and want it in the Thymian pipeline:

  • you are migrating from Spectral and want both result sets in one report format
  • your CI already runs Spectral and you want Thymian’s formatters (markdown, CSV, JSON) and exit-code gating on those results
  • you want Spectral findings mapped onto the endpoints of your API description
  • The Spectral CLI and a Spectral ruleset (.spectral.yaml) — or an already-generated Spectral JSON report
  • Optionally, the OpenAPI description Spectral linted, for endpoint mapping

The converter accepts exactly one format: the JSON array produced by Spectral’s json formatter (spectral lint -f json). Each result carries code, message, severity (0–3), path, and range, plus source and documentationUrl when Spectral knows them.

Spectral’s other output formats — stylish, text, JUnit, SARIF, and friends — are not supported. Re-run Spectral with -f json if you have something else.

Run Spectral as usual, choosing the JSON formatter and writing to a file. Spectral needs a ruleset (.spectral.yaml, e.g. extends: ["spectral:oas"]) next to your project:

Terminal window
npx @stoplight/spectral-cli lint -f json -o report.json api.yaml

This happens entirely outside Thymian — in CI, keep your existing Spectral step and just persist the JSON output. Note that spectral lint itself exits non-zero when it finds error-severity problems: let that step continue (for example with continue-on-error or || true) so the Thymian conversion in the next step performs the gating.

Pass the report as a typed input. The <type>:<location> syntax splits on the first colon, so locations may themselves contain colons (URLs, Windows paths); bare paths without a type are rejected:

Terminal window
npx thymian report convert --report spectral:./report.json --spec openapi:./api.yaml

The --spec input is optional. When you provide it, Thymian loads the API description and maps findings onto its endpoints where possible; findings it cannot map keep their file locations from the Spectral report.

The converted report renders like any other Thymian report. Rule ids are namespaced spectral/<code> so they never collide with Thymian rules, and each finding keeps its Spectral message, severity, and source location:

Terminal window
@thymian/plugin-spectral · lint · ──────────────────────────────────────────────
api.yaml:2:6
⚠ warn: Info object must have "contact" object.
› spectral/info-contact
⚠ warn: Info "description" must be present and non-empty string.
› spectral/info-description
Summary: 0 errors, 2 warnings, 0 hints, 0 infos.

Severities map one-to-one: Spectral 0/1/2/3 become error/warn/info/hint. Group headings show the finding’s source exactly as Spectral emitted it — typically an absolute path (shortened to api.yaml above for readability).

Exit codes follow the same policy as every Thymian workflow, applied to the converted findings:

  • 1 — the converted report contains failed findings (even though the conversion itself succeeded)
  • 0 — the converted report is clean
  • 2 — usage or tool error: the report file is missing or malformed, or a --report type no installed plugin claims

Severity never affects the exit code: a converted report containing only warnings or hints still exits 1, because every Spectral finding is a failed execution.

An unclaimed type fails fast before anything renders, naming the input — and, when other inputs in the same run were claimed, listing the supported report types.

Step 5: Save the inputs in your configuration file

Section titled “Step 5: Save the inputs in your configuration file”

Both inputs can live in thymian.config.yaml instead of flags, mirroring how specifications works:

reports:
- type: spectral
location: ./report.json
specifications:
- type: openapi
location: ./api.yaml
plugins:
'@thymian/plugin-openapi': {}
'@thymian/plugin-spectral': {}
'@thymian/plugin-reporter':
options:
formatters:
markdown: {}

With that in place, a bare npx thymian report convert does the same conversion. When starting a config from scratch, thymian generate config --for-spec openapi:./api.yaml --for-report spectral:./report.json generates one that already includes the entries.

Flags take precedence: --report replaces the config file’s reports entirely, exactly like --spec replaces specifications. See the Configuration File reference for the full precedence rules.

Step 6: Add file formatters if you want artifacts

Section titled “Step 6: Add file formatters if you want artifacts”

The standard report formatters apply unchanged — configure @thymian/plugin-reporter (or pass --option overrides) and the converted report is written as markdown, CSV, or JSON like any other run.

  • Every Spectral finding becomes a lint finding — the converted report is a lint report.
  • Messages, severities, rule codes, and source locations survive the conversion; documentationUrl becomes the rule’s help link.
  • Endpoint mapping via --spec is best-effort: findings positioned at or after an endpoint’s location in the same source file attach to that endpoint; findings with a source that cannot be mapped fall back to a file:line:column location; findings without a source fall back to their JSON path (for example paths./users.get).
  • Unknown severity numbers convert conservatively as error (with a warning) — findings are never dropped.