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.
When to Use thymian report convert
Section titled “When to Use thymian report convert”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
Prerequisites
Section titled “Prerequisites”- 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
Supported Input Format
Section titled “Supported Input Format”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.
Step by Step Instructions
Section titled “Step by Step Instructions”Step 1: Produce a Spectral JSON report
Section titled “Step 1: Produce a Spectral JSON report”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:
npx @stoplight/spectral-cli lint -f json -o report.json api.yamlThis 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.
Step 2: Convert it into a Thymian report
Section titled “Step 2: Convert it into a Thymian report”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:
npx thymian report convert --report spectral:./report.json --spec openapi:./api.yamlThe --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.
Step 3: Read the result
Section titled “Step 3: Read the result”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:
@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).
Step 4: Gate CI on the exit code
Section titled “Step 4: Gate CI on the exit code”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 clean2— usage or tool error: the report file is missing or malformed, or a--reporttype 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.
What to Expect from the Mapping
Section titled “What to Expect from the Mapping”- Every Spectral finding becomes a lint finding — the converted report is a lint report.
- Messages, severities, rule codes, and source locations survive the conversion;
documentationUrlbecomes the rule’s help link. - Endpoint mapping via
--specis best-effort: findings positioned at or after an endpoint’s location in the same source file attach to that endpoint; findings with asourcethat cannot be mapped fall back to afile:line:columnlocation; findings without asourcefall back to their JSON path (for examplepaths./users.get). - Unknown severity numbers convert conservatively as
error(with a warning) — findings are never dropped.